LDMX Software
dqm::PhotoNuclearDQM Class Reference

Public Member Functions

 PhotoNuclearDQM (const std::string &name, framework::Process &process)
 
void configure (framework::config::Parameters &parameters) override
 Read common configuration parameters: sim_particles_coll_name, sim_particles_passname, count_light_ions.
 
void analyze (const framework::Event &event) override
 Process the event and make histograms or summaries.
 
- Public Member Functions inherited from dqm::NuclearDQM
 NuclearDQM (const std::string &name, framework::Process &process)
 
- Public Member Functions inherited from framework::Analyzer
 Analyzer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for an Analyzer is calling analyze.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header) final
 Don't allow Analyzers to add parameters to the run header.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Member Functions

void findRecoilProperties (const ldmx::SimParticle *recoil)
 Fill recoil-electron vertex histograms.
 
void analyzeInteractionDetails (const framework::Event &event)
 Analyze the PhotonuclearInteraction collection when present.
 

Private Attributes

std::string pn_collection_name_
 
std::string pn_pass_name_
 

Additional Inherited Members

- Public Types inherited from dqm::NuclearDQM
enum class  EventType {
  nothing_hard = 0 , single_neutron = 1 , two_neutrons = 2 , three_or_more_neutrons = 3 ,
  single_charged_pion = 4 , two_charged_pions = 5 , single_neutral_pion = 6 , single_charged_pion_and_nucleon = 7 ,
  single_charged_pion_and_two_nucleons = 8 , two_charged_pions_and_nucleon = 9 , single_neutral_pion_and_nucleon = 10 , single_neutral_pion_and_two_nucleons = 11 ,
  single_neutral_pion_charged_pion_and_nucleon = 12 , single_proton = 13 , two_protons = 14 , proton_neutron = 15 ,
  klong = 16 , charged_kaon = 17 , kshort = 18 , exotics = 19 ,
  multibody = 20
}
 Classification of PN/EN events by the hard particles produced above a kinetic-energy threshold. More...
 
enum class  CompactEventType {
  single_neutron = 0 , single_charged_kaon = 1 , single_neutral_kaon = 2 , two_neutrons = 3 ,
  soft = 4 , other = 5
}
 Compact classification focusing on very-high-energy single particles. More...
 
- Protected Member Functions inherited from dqm::NuclearDQM
std::vector< const ldmx::SimParticle * > findDaughters (const std::map< int, ldmx::SimParticle > &particleMap, const ldmx::SimParticle *parent, int require_process_type=-1) const
 Return daughters of parent that pass PDG-based filtering:
 
void findParticleKinematics (const std::vector< const ldmx::SimParticle * > &daughters, const std::string &prefix)
 Fill kinematic histograms for the nuclear interaction products.
 
void findExtendedKinematics (const std::vector< const ldmx::SimParticle * > &daughters, const std::string &prefix)
 Fill extended kinematic histograms for EN interactions: hardest_pi_ke/theta (π± only), hardest_pi0_ke/theta, {prefix}_proton_mult, {prefix}_charged_pion_mult, {prefix}_neutral_pion_mult, leading_particle_type.
 
void findSubleadingKinematics (const ldmx::SimParticle *initiator, const std::vector< const ldmx::SimParticle * > &daughters, EventType eventType)
 Fill subleading-kinematics histograms for 1n, 2n, charged-kaon and neutral-kaon event types.
 
EventType classifyEvent (const std::vector< const ldmx::SimParticle * > &daughters, double threshold)
 Classify the event by the number and type of hard daughters above threshold [MeV] of kinetic energy.
 
CompactEventType classifyCompactEvent (const ldmx::SimParticle *initiator, const std::vector< const ldmx::SimParticle * > &daughters, double threshold)
 Compact classification: looks for a single particle carrying >= 80% of the initiator energy, or two neutrons each above threshold [MeV].
 
constexpr bool isLightIon (int pdgCode) const
 Return true if pdgCode is a light ion (Z <= 4).
 
- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from dqm::NuclearDQM
std::string sim_particles_coll_name_
 
std::string sim_particles_passname_
 
bool count_light_ions_ {true}
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 9 of file PhotoNuclearDQM.h.

Constructor & Destructor Documentation

◆ PhotoNuclearDQM()

dqm::PhotoNuclearDQM::PhotoNuclearDQM ( const std::string & name,
framework::Process & process )

Definition at line 8 of file PhotoNuclearDQM.cxx.

10 : NuclearDQM(name, process) {}
virtual void process(Event &event) final
Processing an event for an Analyzer is calling analyze.

Member Function Documentation

◆ analyze()

void dqm::PhotoNuclearDQM::analyze ( const framework::Event & event)
overridevirtual

Process the event and make histograms or summaries.

Parameters
eventThe Event to analyze

Implements framework::Analyzer.

Definition at line 86 of file PhotoNuclearDQM.cxx.

86 {
87 // Get the particle map from the event. If the particle map is empty,
88 // don't process the event.
89 auto particle_map{event.getMap<int, ldmx::SimParticle>(
90 sim_particles_coll_name_, sim_particles_passname_)};
91 if (particle_map.empty()) return;
92
93 // Get the recoil electron
94 auto [trackID, recoil] = analysis::getRecoil(particle_map);
96
97 // Use the recoil electron to retrieve the gamma that underwent a
98 // photo-nuclear reaction.
99 auto pn_gamma{analysis::getPNGamma(particle_map, recoil, 2500.)};
100 if (pn_gamma == nullptr) {
101 ldmx_log(warn) << "PN Daughter is lost, skipping";
102 return;
103 }
104
105 const auto pn_daughters{findDaughters(particle_map, pn_gamma)};
106
107 if (!pn_daughters.empty()) {
108 auto pn_vertex_volume{pn_daughters[0]->getVertexVolume()};
109 auto pn_interaction_material{pn_daughters[0]->getInteractionMaterial()};
110
111 // Let's start with the PN vertex volume
112 if (pn_vertex_volume.find("W_cooling") != std::string::npos) {
113 // W_cooling_volume_X
114 histograms_.fill("pn_vertex_volume", 2);
115 } else if (pn_vertex_volume.find("C_volume") != std::string::npos) {
116 // C_volume_X
117 histograms_.fill("pn_vertex_volume", 3);
118 } else if (pn_vertex_volume.find("PCB_volume") != std::string::npos) {
119 histograms_.fill("pn_vertex_volume", 4);
120 } else if (pn_vertex_volume.find("CarbonBasePlate") != std::string::npos) {
121 // CarbonBasePlate_volume
122 histograms_.fill("pn_vertex_volume", 5);
123 } else if (pn_vertex_volume.find("W_front") != std::string::npos) {
124 // W_front_volume_X
125 histograms_.fill("pn_vertex_volume", 6);
126 } else if (pn_vertex_volume.find("Si_volume") != std::string::npos) {
127 histograms_.fill("pn_vertex_volume", 7);
128 } else if (pn_vertex_volume.find("Glue") != std::string::npos) {
129 histograms_.fill("pn_vertex_volume", 8);
130 } else if (pn_vertex_volume.find("motherboard") != std::string::npos) {
131 histograms_.fill("pn_vertex_volume", 9);
132 } else {
133 ldmx_log(debug) << " Else pn_vertex_volume = " << pn_vertex_volume
134 << " with pn_interaction_material = "
135 << pn_interaction_material;
136 histograms_.fill("pn_vertex_volume", 1);
137 }
138
139 // Now the interaction material
140 if (pn_interaction_material.find("Silicon") != std::string::npos ||
141 pn_interaction_material.find("G4_Si") != std::string::npos) {
142 histograms_.fill("pn_interaction_material", 2);
143 } else if (pn_interaction_material.find("Tungsten") != std::string::npos ||
144 pn_interaction_material.find("G4_W") != std::string::npos) {
145 histograms_.fill("pn_interaction_material", 3);
146 } else if (pn_interaction_material.find("FR4") != std::string::npos) {
147 // Glass epoxy
148 histograms_.fill("pn_interaction_material", 4);
149 } else if (pn_interaction_material.find("Steel") != std::string::npos) {
150 histograms_.fill("pn_interaction_material", 5);
151 } else if (pn_interaction_material.find("Epoxy") != std::string::npos) {
152 // CarbonEpoxyComposite
153 histograms_.fill("pn_interaction_material", 6);
154 } else if (pn_interaction_material.find("Scintillator") !=
155 std::string::npos) {
156 // This is the notion for PVT
157 histograms_.fill("pn_interaction_material", 7);
158 } else if (pn_interaction_material.find("Glue") != std::string::npos) {
159 // This is the notion for PVT
160 histograms_.fill("pn_interaction_material", 8);
161 } else if (pn_interaction_material.find("Air") != std::string::npos ||
162 pn_interaction_material.find("G4_AIR") != std::string::npos) {
163 // Air
164 histograms_.fill("pn_interaction_material", 9);
165 } else {
166 ldmx_log(debug) << " Else pn_interaction_material = "
167 << pn_interaction_material
168 << " with pn_vertex_volume = " << pn_vertex_volume;
169 histograms_.fill("pn_interaction_material", 1);
170 }
171 } else {
172 histograms_.fill("pn_vertex_volume", 0);
173 histograms_.fill("pn_interaction_material", 0);
174 }
175
176 findParticleKinematics(pn_daughters, "pn");
177
178 histograms_.fill("pn_particle_mult", pn_gamma->getDaughters().size());
179 histograms_.fill("pn_gamma_energy", pn_gamma->getEnergy());
180 histograms_.fill("pn_gamma_int_x", pn_gamma->getEndPoint()[0]);
181 histograms_.fill("pn_gamma_int_y", pn_gamma->getEndPoint()[1]);
182 histograms_.fill("pn_gamma_int_x:pn_gamma_int_y", pn_gamma->getEndPoint()[0],
183 pn_gamma->getEndPoint()[1]);
184 histograms_.fill("pn_gamma_int_z", pn_gamma->getEndPoint()[2]);
185 histograms_.fill("pn_gamma_vertex_x", pn_gamma->getVertex()[0]);
186 histograms_.fill("pn_gamma_vertex_y", pn_gamma->getVertex()[1]);
187 histograms_.fill("pn_gamma_vertex_z", pn_gamma->getVertex()[2]);
188
189 // Classify the event
190 auto event_type{classifyEvent(pn_daughters, 200)};
191 auto event_type500_mev{classifyEvent(pn_daughters, 500)};
192 auto event_type2000_mev{classifyEvent(pn_daughters, 2000)};
193
194 auto event_type_comp{classifyCompactEvent(pn_gamma, pn_daughters, 200)};
195 auto event_type_comp500_mev{
196 classifyCompactEvent(pn_gamma, pn_daughters, 500)};
197 auto event_type_comp2000_mev{
198 classifyCompactEvent(pn_gamma, pn_daughters, 2000)};
199
200 histograms_.fill("event_type", static_cast<int>(event_type));
201 histograms_.fill("event_type_500mev", static_cast<int>(event_type500_mev));
202 histograms_.fill("event_type_2000mev", static_cast<int>(event_type2000_mev));
203 histograms_.fill("event_type_compact", static_cast<int>(event_type_comp));
204 histograms_.fill("event_type_compact_500mev",
205 static_cast<int>(event_type_comp500_mev));
206 histograms_.fill("event_type_compact_2000mev",
207 static_cast<int>(event_type_comp2000_mev));
208
209 switch (event_type) {
210 case EventType::single_neutron:
211 if (pn_daughters.size() > 1) {
212 auto second_hardest_pdg{std::abs(pn_daughters[1]->getPdgID())};
213 int n_event_type{-10};
214 if (second_hardest_pdg == 2112)
215 n_event_type = 0;
216 else if (second_hardest_pdg == 2212)
217 n_event_type = 1;
218 else if (second_hardest_pdg == 211)
219 n_event_type = 2;
220 else if (second_hardest_pdg == 111)
221 n_event_type = 3;
222 else
223 n_event_type = 4;
224 histograms_.fill("1n_event_type", n_event_type);
225 }
226 [[fallthrough]]; // Remaining code is important for 1n as well
227 case EventType::two_neutrons:
228 case EventType::charged_kaon:
229 case EventType::klong:
230 case EventType::kshort:
231 findSubleadingKinematics(pn_gamma, pn_daughters, event_type);
232 break;
233 default: // Nothing to do
234 break;
235 }
236
237 // Analyze detailed photonuclear interaction tracking if available
239}
const ldmx::SimParticle * getPNGamma(const std::map< int, ldmx::SimParticle > &particleMap, const ldmx::SimParticle *recoil, const float &energyThreshold)
Get a pointer to the sim particle associated with the photon that underwent a photo-nuclear reaction.
std::tuple< int, const ldmx::SimParticle * > getRecoil(const std::map< int, ldmx::SimParticle > &particleMap)
Find and return the sim particle associated with the recoil electron.
std::vector< const ldmx::SimParticle * > findDaughters(const std::map< int, ldmx::SimParticle > &particleMap, const ldmx::SimParticle *parent, int require_process_type=-1) const
Return daughters of parent that pass PDG-based filtering:
EventType classifyEvent(const std::vector< const ldmx::SimParticle * > &daughters, double threshold)
Classify the event by the number and type of hard daughters above threshold [MeV] of kinetic energy.
CompactEventType classifyCompactEvent(const ldmx::SimParticle *initiator, const std::vector< const ldmx::SimParticle * > &daughters, double threshold)
Compact classification: looks for a single particle carrying >= 80% of the initiator energy,...
void findSubleadingKinematics(const ldmx::SimParticle *initiator, const std::vector< const ldmx::SimParticle * > &daughters, EventType eventType)
Fill subleading-kinematics histograms for 1n, 2n, charged-kaon and neutral-kaon event types.
void findParticleKinematics(const std::vector< const ldmx::SimParticle * > &daughters, const std::string &prefix)
Fill kinematic histograms for the nuclear interaction products.
void findRecoilProperties(const ldmx::SimParticle *recoil)
Fill recoil-electron vertex histograms.
void analyzeInteractionDetails(const framework::Event &event)
Analyze the PhotonuclearInteraction collection when present.
HistogramPool histograms_
helper object for making and filling histograms
void fill(const std::string &name, const T &val)
Fill a 1D histogram.
Class representing a simulated particle.
Definition SimParticle.h:25

◆ analyzeInteractionDetails()

void dqm::PhotoNuclearDQM::analyzeInteractionDetails ( const framework::Event & event)
private

Analyze the PhotonuclearInteraction collection when present.

Fills target Z/A, cascade multiplicity, and descendant histograms.

Definition at line 27 of file PhotoNuclearDQM.cxx.

27 {
28 // Check if PhotonuclearInteraction collection exists
29 if (!event.exists(pn_collection_name_, pn_pass_name_)) {
30 // Collection not present - PN tracing was not enabled
31 return;
32 }
33
34 // Get the PhotonuclearInteraction collection
35 const auto& pn_interactions =
36 event.getCollection<ldmx::PhotonuclearInteraction>(pn_collection_name_,
37 pn_pass_name_);
38
39 // Analyze full cascade genealogy information not available from SimParticles:
40 // - Target nucleus Z/A
41 // - Immediate cascade multiplicity
42 // - Full descendant genealogy tree (ALL particles, not just final state)
43
44 int n_interactions = pn_interactions.size();
45 histograms_.fill("pn_interaction_count", n_interactions);
46
47 for (const auto& interaction : pn_interactions) {
48 // Target nucleus information - UNIQUE to PhotonuclearInteraction
49 histograms_.fill("pn_target_z", interaction.getTargetZ());
50 histograms_.fill("pn_target_a", interaction.getTargetA());
51 histograms_.fill("pn_target_z:target_a", interaction.getTargetZ(),
52 interaction.getTargetA());
53
54 // Cascade multiplicity: how many particles created in initial cascade
55 int n_cascade_secondaries = interaction.getNumImmediateSecondaries();
56 histograms_.fill("pn_cascade_multiplicity", n_cascade_secondaries);
57
58 // Full cascade genealogy tree - includes ALL descendants (intermediate +
59 // final) This shows the complete cascade evolution, not just final state
60 // particles
61 auto descendant_map = interaction.getDescendantMap();
62 int total_descendants = 0;
63 for (const auto& [secondary_id, descendants] : descendant_map) {
64 int n_desc = descendants.size();
65 total_descendants += n_desc;
66 // How many particles (intermediate + final) descended from each cascade
67 // particle
68 histograms_.fill("pn_descendants_per_cascade_particle", n_desc);
69 }
70 histograms_.fill("pn_total_final_state_descendants", total_descendants);
71
72 // Cascade compactness: ratio shows what fraction of tree are immediate
73 // secondaries ~1.0 → Compact cascade, few branches (most particles are
74 // immediate secondaries) ~0.5 → Moderate branching (half the particles are
75 // from further generations) ~0.1 → Highly branched cascade with extensive
76 // decay/rescatter chains ~0.0 → Extreme branching (the "tungsten bomb"
77 // scenarios)
78 if (total_descendants > 0) {
79 double compactness_ratio =
80 static_cast<double>(n_cascade_secondaries) / total_descendants;
81 histograms_.fill("pn_cascade_evolution_ratio", compactness_ratio);
82 }
83 }
84}
bool exists(const std::string &name, const std::string &passName, bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Definition Event.cxx:107
Stores detailed information about a photonuclear interaction.

References framework::Event::exists().

◆ configure()

void dqm::PhotoNuclearDQM::configure ( framework::config::Parameters & parameters)
overridevirtual

Read common configuration parameters: sim_particles_coll_name, sim_particles_passname, count_light_ions.

Reimplemented from dqm::NuclearDQM.

Definition at line 12 of file PhotoNuclearDQM.cxx.

12 {
13 NuclearDQM::configure(parameters);
14 pn_collection_name_ = parameters.get<std::string>("pn_collection_name",
15 "PhotonuclearInteractions");
16 pn_pass_name_ = parameters.get<std::string>("pn_pass_name", "");
17}
void configure(framework::config::Parameters &parameters) override
Read common configuration parameters: sim_particles_coll_name, sim_particles_passname,...
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75

References framework::config::Parameters::get().

◆ findRecoilProperties()

void dqm::PhotoNuclearDQM::findRecoilProperties ( const ldmx::SimParticle * recoil)
private

Fill recoil-electron vertex histograms.

Definition at line 19 of file PhotoNuclearDQM.cxx.

19 {
20 histograms_.fill("recoil_vertex_x", recoil->getVertex()[0]);
21 histograms_.fill("recoil_vertex_y", recoil->getVertex()[1]);
22 histograms_.fill("recoil_vertex_z", recoil->getVertex()[2]);
23 histograms_.fill("recoil_vertex_x:recoil_vertex_y", recoil->getVertex()[0],
24 recoil->getVertex()[1]);
25}
std::vector< double > getVertex() const
Get a vector containing the vertex of this particle in mm.

References ldmx::SimParticle::getVertex().

Member Data Documentation

◆ pn_collection_name_

std::string dqm::PhotoNuclearDQM::pn_collection_name_
private

Definition at line 27 of file PhotoNuclearDQM.h.

◆ pn_pass_name_

std::string dqm::PhotoNuclearDQM::pn_pass_name_
private

Definition at line 28 of file PhotoNuclearDQM.h.


The documentation for this class was generated from the following files: