LDMX Software
TargetBremFilter.cxx
1/*~~~~~~~~~~~~~*/
2/* Biasing */
3/*~~~~~~~~~~~~~*/
4#include "Biasing/TargetBremFilter.h"
5
6/*~~~~~~~~~~~~*/
7/* Geant4 */
8/*~~~~~~~~~~~~*/
9#include "G4Electron.hh"
10#include "G4EventManager.hh"
11#include "G4RunManager.hh"
12
13/*~~~~~~~~~~~~~*/
14/* SimCore */
15/*~~~~~~~~~~~~~*/
16#include "SimCore/G4User/PtrRetrieval.h"
17#include "SimCore/G4User/UserEventInformation.h"
18#include "SimCore/G4User/UserTrackInformation.h"
19
20/*~~~~~~~~~~~~~*/
21/* C++ StdLib */
22/*~~~~~~~~~~~~~*/
23#include <cmath>
24
25namespace biasing {
26
27TargetBremFilter::TargetBremFilter(const std::string& name,
29 : simcore::UserAction(name, parameters) {
30 recoil_max_p_threshold_ = parameters.get<double>("recoil_max_p_threshold");
31 brem_energy_threshold_ = parameters.get<double>("brem_min_energy_threshold");
32 brem_theta_min_ = parameters.get<double>("brem_theta_min");
33 brem_theta_max_ = parameters.get<double>("brem_theta_max");
34 dral_min_ = parameters.get<double>("dral_min");
35 dral_max_ = parameters.get<double>("dral_max");
36 kill_recoil_ = parameters.get<bool>("kill_recoil_track");
37
38 ldmx_log(info) << "TargetBremFilter configured:"
39 << " recoil_max_p_threshold=" << recoil_max_p_threshold_
40 << " brem_min_energy_threshold=" << brem_energy_threshold_
41 << " brem_theta=[" << brem_theta_min_ << ", "
42 << brem_theta_max_ << "]"
43 << " dral=[" << dral_min_ << ", " << dral_max_ << "]";
44}
45
47
48G4ClassificationOfNewTrack TargetBremFilter::classifyNewTrack(
49 const G4Track* track, const G4ClassificationOfNewTrack& currentTrackClass) {
50 // get the PDGID of the track.
51 G4int pdg_id = track->GetParticleDefinition()->GetPDGEncoding();
52
53 // Get the particle type.
54 G4String particle_name = track->GetParticleDefinition()->GetParticleName();
55
56 // Use current classification by default so values from other plugins are not
57 // overridden.
58 G4ClassificationOfNewTrack classification = currentTrackClass;
59
60 if (track->GetTrackID() == 1 && pdg_id == 11) {
61 return fWaiting;
62 }
63
64 return classification;
65}
66
67void TargetBremFilter::stepping(const G4Step* step) {
68 double last_dral = -1;
69 double last_theta = -1;
70 // Get the track associated with this step.
71 auto track{step->GetTrack()};
72
73 // Only process the primary electron track
74 if (track->GetParentID() != 0) return;
75
76 // Get the PDG ID of the track and make sure it's an electron. If
77 // another particle type is found, thrown an exception.
78 if (auto pdg_id{track->GetParticleDefinition()->GetPDGEncoding()};
79 pdg_id != 11)
80 return;
81
82 // Get the region the particle is currently in. Continue processing
83 // the particle only if it's in the target region.
84 static auto target_region =
85 simcore::g4user::ptrretrieval::getRegion("target");
86 if (!target_region) {
87 ldmx_log(warn) << "Region 'target' not found in Geant4 region store";
88 }
89 auto phy_vol{track->GetVolume()};
90 auto log_vol{phy_vol ? phy_vol->GetLogicalVolume() : nullptr};
91 auto track_region{log_vol ? log_vol->GetRegion() : nullptr};
92 if (track_region != target_region) return;
93
94 /*
95 std::cout << "[TargetBremFilter] : Stepping primary electron in 'target'
96 region into "
97 << track->GetNextVolume()->GetName()
98 << std::endl;
99 */
100
113 auto recoil_physical_volume =
114 simcore::g4user::ptrretrieval::getPhysicalVolume("recoil_PV");
115 auto world_physical_volume =
116 simcore::g4user::ptrretrieval::getPhysicalVolume("World_PV");
117 if (!recoil_physical_volume) {
118 ldmx_log(warn) << "Volume 'recoil_PV' not found in Geant4 volume store";
119 }
120 if (!world_physical_volume) {
121 ldmx_log(warn) << "Volume 'World_PV' not found in Geant4 volume store";
122 }
123 auto track_volume = track->GetNextVolume();
124 if (track_volume == recoil_physical_volume or
125 track_volume == world_physical_volume) {
126 // If the recoil electron momentum is too high, abort
127 if (track->GetMomentum().mag() >= recoil_max_p_threshold_) {
128 ldmx_log(trace) << "Abort: recoil p=" << track->GetMomentum().mag()
129 << " MeV >= threshold=" << recoil_max_p_threshold_;
130 track->SetTrackStatus(fKillTrackAndSecondaries);
131 G4RunManager::GetRunManager()->AbortEvent();
132 return;
133 }
134
135 // Get the electron secondaries
136 bool has_brem_candidate = false;
137 if (auto secondaries = step->GetSecondary(); secondaries->size() == 0) {
138 ldmx_log(trace) << "Abort: no secondaries produced";
139 track->SetTrackStatus(fKillTrackAndSecondaries);
140 G4RunManager::GetRunManager()->AbortEvent();
141 return;
142 } else {
143 ldmx_log(trace) << "Exiting target: recoil p ="
144 << track->GetMomentum().mag() << " MeV, "
145 << secondaries->size() << " secondaries";
146
147 for (auto& secondary_track : *secondaries) {
148 auto electron = G4Electron::Definition();
149 auto ebrem_process =
150 simcore::g4user::ptrretrieval::getProcess(electron, "eBrem");
151 if (!ebrem_process) {
152 ldmx_log(warn) << "Process 'eBrem' not found in Geant4 process store";
153 }
154
155 if (ebrem_process &&
156 secondary_track->GetKineticEnergy() > brem_energy_threshold_) {
157 // Check if secondary is photon
158 auto secondary_pdg_id =
159 secondary_track->GetParticleDefinition()->GetPDGEncoding();
160 if (secondary_pdg_id != 22) continue;
161
162 // Brem angle
163 auto momentum = secondary_track->GetMomentum();
164 double theta = std::atan2(std::sqrt(momentum.x() * momentum.x() +
165 momentum.y() * momentum.y()),
166 momentum.z());
167 bool pass_brem_theta =
168 theta >= brem_theta_min_ && theta <= brem_theta_max_;
169
170 // Maximum and Minimum angle between outgoing Brem photons and
171 // electrons
172 auto gamma_mom = secondary_track->GetMomentum();
173 auto electron_mom = track->GetMomentum();
174 double gamma_eta = gamma_mom.eta();
175 double gamma_phi = gamma_mom.phi();
176 double electron_eta = electron_mom.eta();
177 double electron_phi = electron_mom.phi();
178
179 double dphi = std::atan2(std::sin(electron_phi - gamma_phi),
180 std::cos(electron_phi - gamma_phi));
181 double dral = std::sqrt((electron_eta - gamma_eta) *
182 (electron_eta - gamma_eta) +
183 dphi * dphi);
184 bool pass_dral = dral >= dral_min_ && dral <= dral_max_;
185
186 last_theta = theta;
187 last_dral = dral;
188
189 ldmx_log(trace) << " photon E="
190 << secondary_track->GetKineticEnergy()
191 << " MeV, theta=" << theta
192 << " (pass=" << pass_brem_theta << ")"
193 << ", dR=" << dral << " (pass=" << pass_dral << ")";
194
195 if (pass_brem_theta && pass_dral) {
196 auto track_info{
197 simcore::UserTrackInformation::get(secondary_track)};
198 track_info->tagBremCandidate();
199
201
202 has_brem_candidate = true;
203 }
204 }
205 }
206 }
207
208 if (!has_brem_candidate) {
209 ldmx_log(trace) << "Abort: no brem candidate passed cuts";
210 track->SetTrackStatus(fKillTrackAndSecondaries);
211 G4RunManager::GetRunManager()->AbortEvent();
212 return;
213 }
214
215 ldmx_log(info) << "ACCEPTED: brem candidate with theta=" << last_theta
216 << ", dR=" << last_dral;
217
218 // Check if the recoil electron should be killed. If not, postpone
219 // its processing until the brem gamma has been processed.
220 if (kill_recoil_)
221 track->SetTrackStatus(fStopAndKill);
222 else
223 track->SetTrackStatus(fSuspend);
224
225 } else if (step->GetPostStepPoint()->GetKineticEnergy() == 0) {
226 track->SetTrackStatus(fKillTrackAndSecondaries);
227 G4RunManager::GetRunManager()->AbortEvent();
228 return;
229 }
230}
231
233} // namespace biasing
234
#define DECLARE_ACTION(CLASS)
register a new UserAction with its factory
Definition UserAction.h:216
User action that allows a user to filter out events that don't result in a brem within the target.
double brem_theta_min_
Maximum and Minimum brem gamma angle relative to beam axis [rad].
TargetBremFilter(const std::string &name, framework::config::Parameters &parameters)
Constructor.
void stepping(const G4Step *step) override
Implement the stepping action which performs the target volume biasing.
bool kill_recoil_
Flag indicating if the recoil electron track should be killed.
double dral_min_
Maximum and Minimum electron-photon separation in eta-phi space.
double brem_energy_threshold_
Brem gamma energy treshold.
void endOfEventAction(const G4Event *) override
Method called at the end of every event.
double recoil_max_p_threshold_
Recoil electron threshold.
G4ClassificationOfNewTrack classifyNewTrack(const G4Track *aTrack, const G4ClassificationOfNewTrack &currentTrackClass) override
Classify a new track which postpones track processing.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
UserEventInformation * getEventInfo() const
Get a handle to the event information.
void incBremCandidateCount()
Increment the number of brem candidates in an event.
static UserTrackInformation * get(const G4Track *track)
get
Dynamically loadable photonuclear models either from SimCore or external libraries implementing this ...