-
Notifications
You must be signed in to change notification settings - Fork 37
/
GateLETActor.cpp
165 lines (145 loc) · 6.18 KB
/
GateLETActor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* --------------------------------------------------
Copyright (C): OpenGATE Collaboration
This software is distributed under the terms
of the GNU Lesser General Public Licence (LGPL)
See LICENSE.md for further details
------------------------------------ -------------- */
#include "GateLETActor.h"
#include "G4Navigator.hh"
#include "G4RandomTools.hh"
#include "G4RunManager.hh"
#include "GateHelpers.h"
#include "GateHelpersDict.h"
#include "GateHelpersImage.h"
#include "G4Deuteron.hh"
#include "G4Electron.hh"
#include "G4EmCalculator.hh"
#include "G4Gamma.hh"
#include "G4MaterialTable.hh"
#include "G4NistManager.hh"
#include "G4ParticleDefinition.hh"
#include "G4ParticleTable.hh"
#include "G4Positron.hh"
#include "G4Proton.hh"
// Mutex that will be used by thread to write in the edep/dose image
G4Mutex SetLETPixelMutex = G4MUTEX_INITIALIZER;
GateLETActor::GateLETActor(py::dict &user_info) : GateVActor(user_info, true) {
// Create the image pointer
// (the size and allocation will be performed on the py side)
cpp_numerator_image = ImageType::New();
cpp_denominator_image = ImageType::New();
// Action for this actor: during stepping
fActions.insert("SteppingAction");
fActions.insert("BeginOfRunAction");
fActions.insert("EndSimulationAction");
// Option: compute uncertainty
fdoseAverage = DictGetBool(user_info, "dose_average");
ftrackAverage = DictGetBool(user_info, "track_average");
fLETtoOtherMaterial = DictGetBool(user_info, "let_to_other_material");
fotherMaterial = DictGetStr(user_info, "other_material");
// fQAverage = DictGetBool(user_info, "qAverage");
fInitialTranslation = DictGetG4ThreeVector(user_info, "translation");
// Hit type (random, pre, post etc)
fHitType = DictGetStr(user_info, "hit_type");
}
void GateLETActor::ActorInitialize() {}
void GateLETActor::BeginOfRunAction(const G4Run *) {
// Important ! The volume may have moved, so we re-attach each run
AttachImageToVolume<ImageType>(cpp_numerator_image, fPhysicalVolumeName,
fInitialTranslation);
AttachImageToVolume<ImageType>(cpp_denominator_image, fPhysicalVolumeName,
fInitialTranslation);
// compute volume of a dose voxel
auto sp = cpp_numerator_image->GetSpacing();
fVoxelVolume = sp[0] * sp[1] * sp[2];
static G4Material *water =
G4NistManager::Instance()->FindOrBuildMaterial(fotherMaterial);
}
void GateLETActor::SteppingAction(G4Step *step) {
auto preGlobal = step->GetPreStepPoint()->GetPosition();
auto postGlobal = step->GetPostStepPoint()->GetPosition();
auto touchable = step->GetPreStepPoint()->GetTouchable();
// FIXME If the volume has multiple copy, touchable->GetCopyNumber(0) ?
// consider random position between pre and post
auto position = postGlobal;
if (fHitType == "pre") {
position = preGlobal;
}
if (fHitType == "random") {
auto x = G4UniformRand();
auto direction = postGlobal - preGlobal;
position = preGlobal + x * direction;
}
if (fHitType == "middle") {
auto direction = postGlobal - preGlobal;
position = preGlobal + 0.5 * direction;
}
auto localPosition =
touchable->GetHistory()->GetTransform(0).TransformPoint(position);
// convert G4ThreeVector to itk PointType
ImageType::PointType point;
point[0] = localPosition[0];
point[1] = localPosition[1];
point[2] = localPosition[2];
// get pixel index
ImageType::IndexType index;
bool isInside =
cpp_numerator_image->TransformPhysicalPointToIndex(point, index);
// set value
if (isInside) {
// With mutex (thread)
G4AutoLock mutex(&SetLETPixelMutex);
// get edep in MeV (take weight into account)
auto w = step->GetTrack()->GetWeight();
auto edep = step->GetTotalEnergyDeposit() / CLHEP::MeV * w;
double dedx_cut = DBL_MAX;
// dedx
auto *current_material = step->GetPreStepPoint()->GetMaterial();
auto density = current_material->GetDensity() / CLHEP::g * CLHEP::cm3;
// double dedx_currstep = 0., dedx_water = 0.;
// double density_water = 1.0;
// other material
const G4ParticleDefinition *p = step->GetTrack()->GetParticleDefinition();
auto energy1 = step->GetPreStepPoint()->GetKineticEnergy() / CLHEP::MeV;
auto energy2 = step->GetPostStepPoint()->GetKineticEnergy() / CLHEP::MeV;
auto energy = (energy1 + energy2) / 2;
// Accounting for particles with dedx=0; i.e. gamma and neutrons
// For gamma we consider the dedx of electrons instead - testing
// with 1.3 MeV photon beam or 150 MeV protons or 1500 MeV carbon ion
// beam showed that the error induced is 0 when comparing
// dose and dosetowater in the material G4_WATER For neutrons the dose
// is neglected - testing with 1.3 MeV photon beam or 150 MeV protons or
// 1500 MeV carbon ion beam showed that the error induced is < 0.01%
// when comparing dose and dosetowater in the material
// G4_WATER (we are systematically missing a little bit of dose of
// course with this solution)
if (p == G4Gamma::Gamma())
p = G4Electron::Electron();
auto &l = fThreadLocalData.Get().emcalc;
auto dedx_currstep =
l.ComputeElectronicDEDX(energy, p, current_material, dedx_cut) /
CLHEP::MeV * CLHEP::mm;
auto steplength = step->GetStepLength() / CLHEP::mm;
double scor_val_num = 0.;
double scor_val_den = 0.;
if (fLETtoOtherMaterial) {
auto density_water = water->GetDensity() / CLHEP::g * CLHEP::cm3;
auto dedx_water = l.ComputeElectronicDEDX(energy, p, water, dedx_cut) /
CLHEP::MeV * CLHEP::mm;
auto SPR_otherMaterial = dedx_water / dedx_currstep;
edep *= SPR_otherMaterial;
dedx_currstep *= SPR_otherMaterial;
}
if (fdoseAverage) {
scor_val_num = edep * dedx_currstep / CLHEP::MeV / CLHEP::MeV * CLHEP::mm;
scor_val_den = edep / CLHEP::MeV;
} else if (ftrackAverage) {
scor_val_num = steplength * dedx_currstep * w / CLHEP::MeV;
scor_val_den = steplength * w / CLHEP::mm;
}
ImageAddValue<ImageType>(cpp_numerator_image, index, scor_val_num);
ImageAddValue<ImageType>(cpp_denominator_image, index, scor_val_den);
//}
} // else : outside the image
}
void GateLETActor::EndSimulationAction() {}