Skip to content

Commit 5b18ecc

Browse files
authored
Merge pull request #726 from OpenGATE/spect_config2
Spect FreeFlight cont.
2 parents a03defc + f71b3c3 commit 5b18ecc

File tree

96 files changed

+2698
-508
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+2698
-508
lines changed

core/opengate_core/opengate_lib/GateAcceptanceAngleTesterManager.cpp renamed to core/opengate_core/opengate_lib/GateAcceptanceAngleManager.cpp

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,48 @@
55
See LICENSE.md for further details
66
-------------------------------------------------- */
77

8-
#include "GateAcceptanceAngleTesterManager.h"
8+
#include "GateAcceptanceAngleManager.h"
99
#include "G4RunManager.hh"
10-
#include "GateAcceptanceAngleTester.h"
10+
#include "GateAcceptanceAngleSingleVolume.h"
1111
#include "GateHelpersDict.h"
1212

13-
GateAcceptanceAngleTesterManager::GateAcceptanceAngleTesterManager() {
13+
GateAcceptanceAngleManager::GateAcceptanceAngleManager() {
1414
fEnabledFlag = false;
1515
fNotAcceptedEvents = 0;
1616
fAALastRunId = -1;
1717
fPolicy = AASkipEvent;
18-
fMaxNotAcceptedEvents = 100000;
18+
fMaxNotAcceptedEvents = 10000;
1919
}
2020

21-
void GateAcceptanceAngleTesterManager::Initialize(py::dict puser_info,
22-
bool is_valid_type) {
23-
fAcceptanceAngleVolumeNames = DictGetVecStr(puser_info, "volumes");
21+
GateAcceptanceAngleManager::~GateAcceptanceAngleManager() {}
22+
23+
void GateAcceptanceAngleManager::Initialize(py::dict user_info,
24+
bool is_valid_type) {
25+
// AA is enabled if volumes is not empty and one of the flags is True
26+
// intersection_flag or normal_flag
27+
fAcceptanceAngleVolumeNames = DictGetVecStr(user_info, "volumes");
2428
fEnabledFlag = !fAcceptanceAngleVolumeNames.empty();
29+
30+
bool b2 = DictGetBool(user_info, "intersection_flag");
31+
bool b3 = DictGetBool(user_info, "normal_flag");
32+
33+
fEnabledFlag = fEnabledFlag && (b2 || b3);
34+
2535
if (!fEnabledFlag)
2636
return;
2737
// (we cannot use py::dict here as it is lost at the end of the function)
28-
fAcceptanceAngleParam = DictToMap(puser_info);
29-
auto s = DictGetStr(puser_info, "skip_policy");
38+
fAcceptanceAngleParam = DictToMap(user_info);
39+
auto s = DictGetStr(user_info, "skip_policy");
40+
fMaxNotAcceptedEvents = DictGetInt(user_info, "max_rejection");
41+
3042
fPolicy = AAUndefined;
3143
if (s == "ZeroEnergy")
3244
fPolicy = AAZeroEnergy;
3345
if (s == "SkipEvents")
3446
fPolicy = AASkipEvent;
3547
if (fPolicy == AAUndefined) {
3648
std::ostringstream oss;
37-
oss << "Unknown '" << s << "' mode for GateAcceptanceAngleTesterManager. "
49+
oss << "Unknown '" << s << "' mode for GateAcceptanceAngleManager. "
3850
<< "Expected: ZeroEnergy or SkipEvents";
3951
Fatal(oss.str());
4052
}
@@ -48,13 +60,14 @@ void GateAcceptanceAngleTesterManager::Initialize(py::dict puser_info,
4860
}
4961
}
5062

51-
void GateAcceptanceAngleTesterManager::InitializeAcceptanceAngle() {
63+
void GateAcceptanceAngleManager::InitializeAcceptanceAngle() {
5264
if (!fEnabledFlag)
5365
return;
5466
// Create the testers (only the first time)
5567
if (fAATesters.empty()) {
5668
for (const auto &name : fAcceptanceAngleVolumeNames) {
57-
auto *t = new GateAcceptanceAngleTester(name, fAcceptanceAngleParam);
69+
auto *t =
70+
new GateAcceptanceAngleSingleVolume(name, fAcceptanceAngleParam);
5871
fAATesters.push_back(t);
5972
}
6073
}
@@ -68,34 +81,33 @@ void GateAcceptanceAngleTesterManager::InitializeAcceptanceAngle() {
6881
fEnabledFlag = !fAcceptanceAngleVolumeNames.empty();
6982
}
7083

71-
unsigned long
72-
GateAcceptanceAngleTesterManager::GetNumberOfNotAcceptedEvents() const {
84+
unsigned long GateAcceptanceAngleManager::GetNumberOfNotAcceptedEvents() const {
7385
return fNotAcceptedEvents;
7486
}
7587

76-
bool GateAcceptanceAngleTesterManager::TestIfAccept(
88+
bool GateAcceptanceAngleManager::TestIfAccept(
7789
const G4ThreeVector &position, const G4ThreeVector &momentum_direction) {
7890
if (!fEnabledFlag)
7991
return true;
8092

81-
// Loop on all volume to check if it at least one volume is accepted
82-
for (auto *tester : fAATesters) {
93+
// Loop on all the volumes to check if it at least one volume is accepted
94+
for (const auto *tester : fAATesters) {
8395
bool accept = tester->TestIfAccept(position, momentum_direction);
8496
if (accept)
8597
return true;
8698
}
87-
fNotAcceptedEvents++;
8899
if (fNotAcceptedEvents > fMaxNotAcceptedEvents) {
89100
std::ostringstream oss;
90101
oss << "Error, in AcceptanceAngleTest: " << fNotAcceptedEvents
91102
<< " trials has been tested without accepted angle ; probably no "
92103
"possible direction here. Abort. ";
93104
Fatal(oss.str());
94105
}
106+
fNotAcceptedEvents++;
95107
return false;
96108
}
97109

98-
void GateAcceptanceAngleTesterManager::StartAcceptLoop() {
110+
void GateAcceptanceAngleManager::StartAcceptLoop() {
99111
if (!fEnabledFlag)
100112
return;
101113
fNotAcceptedEvents = 0;

core/opengate_core/opengate_lib/GateAcceptanceAngleTesterManager.h renamed to core/opengate_core/opengate_lib/GateAcceptanceAngleManager.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,21 @@
55
See LICENSE.md for further details
66
-------------------------------------------------- */
77

8-
#ifndef GateAcceptanceAngleTesterManager_h
9-
#define GateAcceptanceAngleTesterManager_h
8+
#ifndef GateAcceptanceAngleManager_h
9+
#define GateAcceptanceAngleManager_h
1010

11-
#include "GateAcceptanceAngleTester.h"
11+
#include "GateAcceptanceAngleSingleVolume.h"
1212
#include "GateHelpers.h"
1313

14-
class GateAcceptanceAngleTesterManager {
14+
class GateAcceptanceAngleManager {
1515
public:
16-
GateAcceptanceAngleTesterManager();
16+
GateAcceptanceAngleManager();
17+
18+
~GateAcceptanceAngleManager();
1719

1820
enum AAPolicyType { AAZeroEnergy, AASkipEvent, AAUndefined };
1921

20-
void Initialize(py::dict puser_info, bool is_iso);
22+
void Initialize(py::dict user_info, bool is_valid_type);
2123

2224
void InitializeAcceptanceAngle();
2325

@@ -34,12 +36,12 @@ class GateAcceptanceAngleTesterManager {
3436

3537
AAPolicyType fPolicy;
3638
std::map<std::string, std::string> fAcceptanceAngleParam;
37-
std::vector<GateAcceptanceAngleTester *> fAATesters{};
39+
std::vector<GateAcceptanceAngleSingleVolume *> fAATesters{};
3840
std::vector<std::string> fAcceptanceAngleVolumeNames;
3941
bool fEnabledFlag;
4042
unsigned long fNotAcceptedEvents;
4143
unsigned long fMaxNotAcceptedEvents;
4244
int fAALastRunId;
4345
};
4446

45-
#endif // GateAcceptanceAngleTesterManager_h
47+
#endif // GateAcceptanceAngleManager_h
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/* --------------------------------------------------
2+
Copyright (C): OpenGATE Collaboration
3+
This software is distributed under the terms
4+
of the GNU Lesser General Public Licence (LGPL)
5+
See LICENSE.md for further details
6+
-------------------------------------------------- */
7+
8+
#include "GateAcceptanceAngleSingleVolume.h"
9+
#include "G4LogicalVolumeStore.hh"
10+
#include "G4Navigator.hh"
11+
#include "G4PhysicalVolumeStore.hh"
12+
#include "GateHelpersDict.h"
13+
#include "GateHelpersImage.h"
14+
15+
GateAcceptanceAngleSingleVolume::GateAcceptanceAngleSingleVolume(
16+
const std::string &volume,
17+
const std::map<std::string, std::string> &param) {
18+
fAcceptanceAngleVolumeName = volume;
19+
fAASolid = nullptr;
20+
fAANavigator = nullptr;
21+
fAARotation = nullptr;
22+
fIntersectionFlag = false;
23+
fNormalFlag = false;
24+
fNormalAngleTolerance = 0;
25+
fMinDistanceNormalAngleTolerance = 0;
26+
fDistanceDependentAngleToleranceFlag = false;
27+
fAngle1 = 0;
28+
fAngle2 = 0;
29+
fDistance1 = 0;
30+
fDistance2 = 0;
31+
32+
// Retrieve the solid
33+
const auto lvs = G4LogicalVolumeStore::GetInstance();
34+
const auto lv = lvs->GetVolume(fAcceptanceAngleVolumeName);
35+
fAASolid = lv->GetSolid();
36+
37+
// Init a navigator that will be used to find the transform
38+
const auto pvs = G4PhysicalVolumeStore::GetInstance();
39+
const auto world = pvs->GetVolume("world");
40+
fAANavigator = new G4Navigator();
41+
fAANavigator->SetWorldVolume(world);
42+
43+
// parameters
44+
fIntersectionFlag = StrToBool(param.at("intersection_flag"));
45+
fNormalFlag = StrToBool(param.at("normal_flag"));
46+
fNormalAngleTolerance = StrToDouble(param.at("normal_tolerance"));
47+
fMinDistanceNormalAngleTolerance =
48+
StrToDouble(param.at("normal_tolerance_min_distance"));
49+
fNormalVector = StrToG4ThreeVector(param.at("normal_vector"));
50+
51+
if (fNormalAngleTolerance <= 0) {
52+
Fatal("Normal angle tolerance must be strictly positive while it is " +
53+
std::to_string(fNormalAngleTolerance));
54+
}
55+
56+
// DD -> not recommended (too slow), prefer normal_tolerance_min_distance
57+
fDistanceDependentAngleToleranceFlag =
58+
StrToBool(param.at("distance_dependent_normal_tolerance"));
59+
fAngle1 = StrToDouble(param.at("angle1"));
60+
fAngle2 = StrToDouble(param.at("angle2"));
61+
fDistance1 = StrToDouble(param.at("distance1"));
62+
fDistance2 = StrToDouble(param.at("distance2"));
63+
if (fDistance1 >= fDistance2) {
64+
Fatal(
65+
"For 'distance_dependent_normal_tolerance', Distance1 must be strictly "
66+
"less than distance2 " +
67+
std::to_string(fDistance1) + " " + std::to_string(fDistance2));
68+
}
69+
a = (1.0 / tan(fAngle1) - 1.0 / tan(fAngle2)) / (fDistance1 - fDistance2);
70+
b = 1.0 / tan(fAngle2) - a * fDistance2;
71+
}
72+
73+
GateAcceptanceAngleSingleVolume::~GateAcceptanceAngleSingleVolume() {
74+
delete fAARotation;
75+
}
76+
77+
void GateAcceptanceAngleSingleVolume::UpdateTransform() {
78+
79+
if (fAARotation == nullptr)
80+
fAARotation = new G4RotationMatrix;
81+
82+
// Get the transformation
83+
G4ThreeVector tr;
84+
ComputeTransformationFromWorldToVolume(fAcceptanceAngleVolumeName, tr,
85+
*fAARotation, true);
86+
// It is not fully clear why the AffineTransform need the inverse
87+
fAATransform = G4AffineTransform(fAARotation->inverse(), tr);
88+
}
89+
90+
bool GateAcceptanceAngleSingleVolume::TestIfAccept(
91+
const G4ThreeVector &position,
92+
const G4ThreeVector &momentum_direction) const {
93+
const auto localDirection = (*fAARotation) * (momentum_direction);
94+
double dist = 0;
95+
if (fIntersectionFlag || fDistanceDependentAngleToleranceFlag) {
96+
const auto localPosition = fAATransform.TransformPoint(position);
97+
dist = fAASolid->DistanceToIn(localPosition, localDirection);
98+
}
99+
if (fIntersectionFlag) {
100+
if (dist == kInfinity)
101+
return false;
102+
}
103+
if (fNormalFlag || fDistanceDependentAngleToleranceFlag) {
104+
const auto angle = fNormalVector.angle(localDirection);
105+
if (dist < fMinDistanceNormalAngleTolerance)
106+
return true;
107+
if (fDistanceDependentAngleToleranceFlag)
108+
return DistanceDependentToleranceTest(angle, dist);
109+
return angle < fNormalAngleTolerance;
110+
}
111+
return true;
112+
}
113+
114+
bool GateAcceptanceAngleSingleVolume::DistanceDependentToleranceTest(
115+
// This is very slow, (3x than other methods
116+
// We recommend to not use this method
117+
const double angle, const double dist) const {
118+
const double tol = atan(1.0 / (a * dist + b));
119+
120+
if (tol < 0)
121+
return true;
122+
return angle < tol;
123+
}

core/opengate_core/opengate_lib/GateAcceptanceAngleTester.h renamed to core/opengate_core/opengate_lib/GateAcceptanceAngleSingleVolume.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,44 @@
55
See LICENSE.md for further details
66
-------------------------------------------------- */
77

8-
#ifndef GateAcceptanceAngleTester_h
9-
#define GateAcceptanceAngleTester_h
8+
#ifndef GateAcceptanceAngleSingleVolume_h
9+
#define GateAcceptanceAngleSingleVolume_h
1010

1111
#include "G4AffineTransform.hh"
1212
#include "GateHelpers.h"
1313

14-
class GateAcceptanceAngleTester {
14+
class GateAcceptanceAngleSingleVolume {
1515
public:
16-
GateAcceptanceAngleTester(const std::string &volume,
17-
std::map<std::string, std::string> &param);
16+
GateAcceptanceAngleSingleVolume(
17+
const std::string &volume,
18+
const std::map<std::string, std::string> &param);
1819

19-
~GateAcceptanceAngleTester();
20+
~GateAcceptanceAngleSingleVolume();
2021

2122
bool TestIfAccept(const G4ThreeVector &position,
2223
const G4ThreeVector &momentum_direction) const;
2324

2425
void UpdateTransform();
26+
bool DistanceDependentToleranceTest(double angle, double dist) const;
2527

2628
protected:
2729
std::string fAcceptanceAngleVolumeName;
2830
bool fIntersectionFlag;
2931
bool fNormalFlag;
3032
double fNormalAngleTolerance;
33+
bool fDistanceDependentAngleToleranceFlag;
34+
double fMinDistanceNormalAngleTolerance;
35+
double fAngle1;
36+
double fAngle2;
37+
double fDistance1;
38+
double fDistance2;
39+
double a;
40+
double b;
3141
G4ThreeVector fNormalVector;
3242
G4AffineTransform fAATransform;
3343
G4RotationMatrix *fAARotation;
3444
G4VSolid *fAASolid;
3545
G4Navigator *fAANavigator;
3646
};
3747

38-
#endif // GateAcceptanceAngleTester_h
48+
#endif // GateAcceptanceAngleSingleVolume_h

0 commit comments

Comments
 (0)