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
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 10 of file PhotoNuclearDQM.h.

Constructor & Destructor Documentation

◆ PhotoNuclearDQM()

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

Definition at line 6 of file PhotoNuclearDQM.cxx.

8 : 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 84 of file PhotoNuclearDQM.cxx.

84 {
85 // Get the particle map from the event. If the particle map is empty,
86 // don't process the event.
87 auto particle_map{event.getMap<int, ldmx::SimParticle>(
88 sim_particles_coll_name_, sim_particles_passname_)};
89 if (particle_map.empty()) return;
90
91 // Get the recoil electron
92 auto [trackID, recoil] = analysis::getRecoil(particle_map);
94
95 // Use the recoil electron to retrieve the gamma that underwent a
96 // photo-nuclear reaction.
97 auto pn_gamma{analysis::getPNGamma(particle_map, recoil, 2500.)};
98 if (pn_gamma == nullptr) {
99 ldmx_log(warn) << "PN Daughter is lost, skipping";
100 return;
101 }
102
103 const auto pn_daughters{findDaughters(particle_map, pn_gamma)};
104
105 if (!pn_daughters.empty()) {
106 auto pn_vertex_volume{pn_daughters[0]->getVertexVolume()};
107 auto pn_interaction_material{pn_daughters[0]->getInteractionMaterial()};
108
109 // Let's start with the PN vertex volume
110 if (pn_vertex_volume.find("W_cooling") != std::string::npos) {
111 // W_cooling_volume_X
112 histograms_.fill("pn_vertex_volume", 2);
113 } else if (pn_vertex_volume.find("C_volume") != std::string::npos) {
114 // C_volume_X
115 histograms_.fill("pn_vertex_volume", 3);
116 } else if (pn_vertex_volume.find("PCB_volume") != std::string::npos) {
117 histograms_.fill("pn_vertex_volume", 4);
118 } else if (pn_vertex_volume.find("CarbonBasePlate") != std::string::npos) {
119 // CarbonBasePlate_volume
120 histograms_.fill("pn_vertex_volume", 5);
121 } else if (pn_vertex_volume.find("W_front") != std::string::npos) {
122 // W_front_volume_X
123 histograms_.fill("pn_vertex_volume", 6);
124 } else if (pn_vertex_volume.find("Si_volume") != std::string::npos) {
125 histograms_.fill("pn_vertex_volume", 7);
126 } else if (pn_vertex_volume.find("Glue") != std::string::npos) {
127 histograms_.fill("pn_vertex_volume", 8);
128 } else if (pn_vertex_volume.find("motherboard") != std::string::npos) {
129 histograms_.fill("pn_vertex_volume", 9);
130 } else {
131 ldmx_log(debug) << " Else pn_vertex_volume = " << pn_vertex_volume
132 << " with pn_interaction_material = "
133 << pn_interaction_material;
134 histograms_.fill("pn_vertex_volume", 1);
135 }
136
137 // Now the interaction material
138 if (pn_interaction_material.find("Silicon") != std::string::npos ||
139 pn_interaction_material.find("G4_Si") != std::string::npos) {
140 histograms_.fill("pn_interaction_material", 2);
141 } else if (pn_interaction_material.find("Tungsten") != std::string::npos ||
142 pn_interaction_material.find("G4_W") != std::string::npos) {
143 histograms_.fill("pn_interaction_material", 3);
144 } else if (pn_interaction_material.find("FR4") != std::string::npos) {
145 // Glass epoxy
146 histograms_.fill("pn_interaction_material", 4);
147 } else if (pn_interaction_material.find("Steel") != std::string::npos) {
148 histograms_.fill("pn_interaction_material", 5);
149 } else if (pn_interaction_material.find("Epoxy") != std::string::npos) {
150 // CarbonEpoxyComposite
151 histograms_.fill("pn_interaction_material", 6);
152 } else if (pn_interaction_material.find("Scintillator") !=
153 std::string::npos) {
154 // This is the notion for PVT
155 histograms_.fill("pn_interaction_material", 7);
156 } else if (pn_interaction_material.find("Glue") != std::string::npos) {
157 // This is the notion for PVT
158 histograms_.fill("pn_interaction_material", 8);
159 } else if (pn_interaction_material.find("Air") != std::string::npos ||
160 pn_interaction_material.find("G4_AIR") != std::string::npos) {
161 // Air
162 histograms_.fill("pn_interaction_material", 9);
163 } else {
164 ldmx_log(debug) << " Else pn_interaction_material = "
165 << pn_interaction_material
166 << " with pn_vertex_volume = " << pn_vertex_volume;
167 histograms_.fill("pn_interaction_material", 1);
168 }
169 } else {
170 histograms_.fill("pn_vertex_volume", 0);
171 histograms_.fill("pn_interaction_material", 0);
172 }
173
174 findParticleKinematics(pn_daughters, "pn");
175
176 histograms_.fill("pn_particle_mult", pn_gamma->getDaughters().size());
177 histograms_.fill("pn_gamma_energy", pn_gamma->getEnergy());
178 histograms_.fill("pn_gamma_int_x", pn_gamma->getEndPoint()[0]);
179 histograms_.fill("pn_gamma_int_y", pn_gamma->getEndPoint()[1]);
180 histograms_.fill("pn_gamma_int_x:pn_gamma_int_y", pn_gamma->getEndPoint()[0],
181 pn_gamma->getEndPoint()[1]);
182 histograms_.fill("pn_gamma_int_z", pn_gamma->getEndPoint()[2]);
183 histograms_.fill("pn_gamma_vertex_x", pn_gamma->getVertex()[0]);
184 histograms_.fill("pn_gamma_vertex_y", pn_gamma->getVertex()[1]);
185 histograms_.fill("pn_gamma_vertex_z", pn_gamma->getVertex()[2]);
186
187 // Classify the event
188 auto event_type{classifyEvent(pn_daughters, 200)};
189 auto event_type500_mev{classifyEvent(pn_daughters, 500)};
190 auto event_type2000_mev{classifyEvent(pn_daughters, 2000)};
191
192 auto event_type_comp{classifyCompactEvent(pn_gamma, pn_daughters, 200)};
193 auto event_type_comp500_mev{
194 classifyCompactEvent(pn_gamma, pn_daughters, 500)};
195 auto event_type_comp2000_mev{
196 classifyCompactEvent(pn_gamma, pn_daughters, 2000)};
197
198 histograms_.fill("event_type", static_cast<int>(event_type));
199 histograms_.fill("event_type_500mev", static_cast<int>(event_type500_mev));
200 histograms_.fill("event_type_2000mev", static_cast<int>(event_type2000_mev));
201 histograms_.fill("event_type_compact", static_cast<int>(event_type_comp));
202 histograms_.fill("event_type_compact_500mev",
203 static_cast<int>(event_type_comp500_mev));
204 histograms_.fill("event_type_compact_2000mev",
205 static_cast<int>(event_type_comp2000_mev));
206
207 switch (event_type) {
208 case EventType::single_neutron:
209 if (pn_daughters.size() > 1) {
210 auto second_hardest_pdg{std::abs(pn_daughters[1]->getPdgID())};
211 int n_event_type{-10};
212 if (second_hardest_pdg == 2112)
213 n_event_type = 0;
214 else if (second_hardest_pdg == 2212)
215 n_event_type = 1;
216 else if (second_hardest_pdg == 211)
217 n_event_type = 2;
218 else if (second_hardest_pdg == 111)
219 n_event_type = 3;
220 else
221 n_event_type = 4;
222 histograms_.fill("1n_event_type", n_event_type);
223 }
224 [[fallthrough]]; // Remaining code is important for 1n as well
225 case EventType::two_neutrons:
226 case EventType::charged_kaon:
227 case EventType::klong:
228 case EventType::kshort:
229 findSubleadingKinematics(pn_gamma, pn_daughters, event_type);
230 break;
231 default: // Nothing to do
232 break;
233 }
234
235 // Analyze detailed photonuclear interaction tracking if available
237}
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:24

◆ 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 25 of file PhotoNuclearDQM.cxx.

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

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

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

◆ findRecoilProperties()

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

Fill recoil-electron vertex histograms.

Definition at line 17 of file PhotoNuclearDQM.cxx.

17 {
18 histograms_.fill("recoil_vertex_x", recoil->getVertex()[0]);
19 histograms_.fill("recoil_vertex_y", recoil->getVertex()[1]);
20 histograms_.fill("recoil_vertex_z", recoil->getVertex()[2]);
21 histograms_.fill("recoil_vertex_x:recoil_vertex_y", recoil->getVertex()[0],
22 recoil->getVertex()[1]);
23}
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 28 of file PhotoNuclearDQM.h.

◆ pn_pass_name_

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

Definition at line 29 of file PhotoNuclearDQM.h.


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