LDMX Software
dqm::PhotoNuclearDQM Class Reference

Public Member Functions

 PhotoNuclearDQM (const std::string &name, framework::Process &process)
 Constructor.
 
virtual ~PhotoNuclearDQM ()=default
 Destructor.
 
void configure (framework::config::Parameters &parameters) override
 Configure this analyzer using the user specified parameters.
 
void analyze (const framework::Event &event) override
 Process the event and create the histogram summaries.
 
constexpr bool isLightIon (const int pdgCode) const
 Check if the PDG code corresponds to a light ion.
 
- 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.
 

Public Attributes

bool count_light_ions_
 

Private Types

enum class  CompactEventType {
  single_neutron = 0 , single_charged_kaon = 1 , single_neutral_kaon = 2 , two_neutrons = 3 ,
  soft = 4 , other = 5
}
 
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
}
 

Private Member Functions

EventType classifyEvent (const std::vector< const ldmx::SimParticle * > daughters, double threshold)
 Method used to classify events.
 
CompactEventType classifyCompactEvent (const ldmx::SimParticle *pnGamma, const std::vector< const ldmx::SimParticle * > daughters, double threshold)
 Method used to classify events in a compact manner.
 
void findRecoilProperties (const ldmx::SimParticle *recoil)
 Fill the recoil electron-histograms.
 
std::vector< const ldmx::SimParticle * > findDaughters (const std::map< int, ldmx::SimParticle > &particleMap, const ldmx::SimParticle *parent) const
 Find all daughter particles of a parent.
 
void findParticleKinematics (const std::vector< const ldmx::SimParticle * > &pnDaughters)
 Fill histograms related to kinematics of PN products.
 
void findSubleadingKinematics (const ldmx::SimParticle *pnGamma, const std::vector< const ldmx::SimParticle * > &pnDaughters, const EventType eventType)
 Fill histograms related to the kinematics and subleading particles for 1n, kaon, and 2n type events.
 
void analyzeInteractionDetails (const framework::Event &event)
 Analyze detailed photonuclear interaction tracking data.
 

Private Attributes

std::string sim_particles_coll_name_
 
std::string sim_particles_passname_
 
std::string pn_collection_name_
 
std::string pn_pass_name_
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- 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 23 of file PhotoNuclearDQM.h.

Member Enumeration Documentation

◆ CompactEventType

enum class dqm::PhotoNuclearDQM::CompactEventType
strongprivate

Definition at line 25 of file PhotoNuclearDQM.h.

25 {
26 single_neutron = 0,
27 single_charged_kaon = 1,
28 single_neutral_kaon = 2,
29 two_neutrons = 3,
30 soft = 4,
31 other = 5,
32 };

◆ EventType

enum class dqm::PhotoNuclearDQM::EventType
strongprivate

Definition at line 33 of file PhotoNuclearDQM.h.

33 {
34 nothing_hard = 0,
35 single_neutron = 1,
36 two_neutrons = 2,
37 three_or_more_neutrons = 3,
38 single_charged_pion = 4,
39 two_charged_pions = 5,
40 single_neutral_pion = 6,
41 single_charged_pion_and_nucleon = 7,
42 single_charged_pion_and_two_nucleons = 8,
43 two_charged_pions_and_nucleon = 9,
44 single_neutral_pion_and_nucleon = 10,
45 single_neutral_pion_and_two_nucleons = 11,
46 single_neutral_pion_charged_pion_and_nucleon = 12,
47 single_proton = 13,
48 two_protons = 14,
49 proton_neutron = 15,
50 klong = 16,
51 charged_kaon = 17,
52 kshort = 18,
53 exotics = 19,
54 multibody = 20,
55 };

Constructor & Destructor Documentation

◆ PhotoNuclearDQM()

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

Constructor.

Definition at line 6 of file PhotoNuclearDQM.cxx.

Base class for a module which does not produce a data product.
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 create the histogram summaries.

Parameters
eventThe event to analyze.

Implements framework::Analyzer.

Definition at line 226 of file PhotoNuclearDQM.cxx.

226 {
227 // Get the particle map from the event. If the particle map is empty,
228 // don't process the event.
229 auto particle_map{event.getMap<int, ldmx::SimParticle>(
230 sim_particles_coll_name_, sim_particles_passname_)};
231 if (particle_map.size() == 0) {
232 return;
233 }
234
235 // Get the recoil electron
236 auto [trackID, recoil] = analysis::getRecoil(particle_map);
237 findRecoilProperties(recoil);
238
239 // Use the recoil electron to retrieve the gamma that underwent a
240 // photo-nuclear reaction.
241 auto pn_gamma{analysis::getPNGamma(particle_map, recoil, 2500.)};
242 if (pn_gamma == nullptr) {
243 ldmx_log(warn) << "PN Daughter is lost, skipping";
244 return;
245 }
246
247 const auto pn_daughters{findDaughters(particle_map, pn_gamma)};
248
249 if (!pn_daughters.empty()) {
250 auto pn_vertex_volume{pn_daughters[0]->getVertexVolume()};
251 auto pn_interaction_material{pn_daughters[0]->getInteractionMaterial()};
252
253 // Let's start with the PN vertex volume
254 if (pn_vertex_volume.find("W_cooling") != std::string::npos) {
255 // W_cooling_volume_X
256 histograms_.fill("pn_vertex_volume", 2);
257 } else if (pn_vertex_volume.find("C_volume") != std::string::npos) {
258 // C_volume_X
259 histograms_.fill("pn_vertex_volume", 3);
260 } else if (pn_vertex_volume.find("PCB_volume") != std::string::npos) {
261 histograms_.fill("pn_vertex_volume", 4);
262 } else if (pn_vertex_volume.find("CarbonBasePlate") != std::string::npos) {
263 // CarbonBasePlate_volume
264 histograms_.fill("pn_vertex_volume", 5);
265 } else if (pn_vertex_volume.find("W_front") != std::string::npos) {
266 // W_front_volume_X
267 histograms_.fill("pn_vertex_volume", 6);
268 } else if (pn_vertex_volume.find("Si_volume") != std::string::npos) {
269 histograms_.fill("pn_vertex_volume", 7);
270 } else if (pn_vertex_volume.find("Glue") != std::string::npos) {
271 histograms_.fill("pn_vertex_volume", 8);
272 } else if (pn_vertex_volume.find("motherboard") != std::string::npos) {
273 histograms_.fill("pn_vertex_volume", 9);
274
275 } else {
276 ldmx_log(debug) << " Else pn_vertex_volume = " << pn_vertex_volume
277 << " with pn_interaction_material = "
278 << pn_interaction_material;
279 histograms_.fill("pn_vertex_volume", 1);
280 }
281
282 // Now the interaction material
283 if (pn_interaction_material.find("Silicon") != std::string::npos ||
284 pn_interaction_material.find("G4_Si") != std::string::npos) {
285 histograms_.fill("pn_interaction_material", 2);
286 } else if (pn_interaction_material.find("Tungsten") != std::string::npos ||
287 pn_interaction_material.find("G4_W") != std::string::npos) {
288 histograms_.fill("pn_interaction_material", 3);
289 } else if (pn_interaction_material.find("FR4") != std::string::npos) {
290 // Glass epoxy
291 histograms_.fill("pn_interaction_material", 4);
292 } else if (pn_interaction_material.find("Steel") != std::string::npos) {
293 histograms_.fill("pn_interaction_material", 5);
294 } else if (pn_interaction_material.find("Epoxy") != std::string::npos) {
295 // CarbonEpoxyComposite
296 histograms_.fill("pn_interaction_material", 6);
297 } else if (pn_interaction_material.find("Scintillator") !=
298 std::string::npos) {
299 // This is the notion for PVT
300 histograms_.fill("pn_interaction_material", 7);
301 } else if (pn_interaction_material.find("Glue") != std::string::npos) {
302 // This is the notion for PVT
303 histograms_.fill("pn_interaction_material", 8);
304 } else if (pn_interaction_material.find("Air") != std::string::npos ||
305 pn_interaction_material.find("G4_AIR") != std::string::npos) {
306 // Air
307 histograms_.fill("pn_interaction_material", 9);
308 } else {
309 ldmx_log(debug) << " Else pn_interaction_material = "
310 << pn_interaction_material
311 << " with pn_vertex_volume = " << pn_vertex_volume;
312 histograms_.fill("pn_interaction_material", 1);
313 }
314 } else {
315 histograms_.fill("pn_vertex_volume", 0);
316 histograms_.fill("pn_interaction_material", 0);
317 }
318
319 findParticleKinematics(pn_daughters);
320
321 histograms_.fill("pn_particle_mult", pn_gamma->getDaughters().size());
322 histograms_.fill("pn_gamma_energy", pn_gamma->getEnergy());
323 histograms_.fill("pn_gamma_int_x", pn_gamma->getEndPoint()[0]);
324 histograms_.fill("pn_gamma_int_y", pn_gamma->getEndPoint()[1]);
325 histograms_.fill("pn_gamma_int_x:pn_gamma_int_y", pn_gamma->getEndPoint()[0],
326 pn_gamma->getEndPoint()[1]);
327 histograms_.fill("pn_gamma_int_z", pn_gamma->getEndPoint()[2]);
328 histograms_.fill("pn_gamma_vertex_x", pn_gamma->getVertex()[0]);
329 histograms_.fill("pn_gamma_vertex_y", pn_gamma->getVertex()[1]);
330 histograms_.fill("pn_gamma_vertex_z", pn_gamma->getVertex()[2]);
331
332 // Classify the event
333 auto event_type{classifyEvent(pn_daughters, 200)};
334 auto event_type500_me_v{classifyEvent(pn_daughters, 500)};
335 auto event_type2000_me_v{classifyEvent(pn_daughters, 2000)};
336
337 auto event_type_comp{classifyCompactEvent(pn_gamma, pn_daughters, 200)};
338 auto event_type_comp500_me_v{
339 classifyCompactEvent(pn_gamma, pn_daughters, 500)};
340 auto event_type_comp2000_me_v{
341 classifyCompactEvent(pn_gamma, pn_daughters, 2000)};
342
343 histograms_.fill("event_type", static_cast<int>(event_type));
344 histograms_.fill("event_type_500mev", static_cast<int>(event_type500_me_v));
345 histograms_.fill("event_type_2000mev", static_cast<int>(event_type2000_me_v));
346
347 histograms_.fill("event_type_compact", static_cast<int>(event_type_comp));
348 histograms_.fill("event_type_compact_500mev",
349 static_cast<int>(event_type_comp500_me_v));
350 histograms_.fill("event_type_compact_2000mev",
351 static_cast<int>(event_type_comp2000_me_v));
352
353 switch (event_type) {
354 case EventType::single_neutron:
355 if (pn_daughters.size() > 1) {
356 auto second_hardest_pdg_id{abs(pn_daughters[1]->getPdgID())};
357 auto n_event_type{-10};
358 if (second_hardest_pdg_id == 2112) {
359 n_event_type = 0; // n + n
360 } else if (second_hardest_pdg_id == 2212) {
361 n_event_type = 1; // p + n
362 } else if (second_hardest_pdg_id == 211) {
363 n_event_type = 2; // Pi+/- + n
364 } else if (second_hardest_pdg_id == 111) {
365 n_event_type = 3; // Pi0 + n
366 } else {
367 n_event_type = 4; // other
368 }
369 histograms_.fill("1n_event_type", n_event_type);
370 }
371 [[fallthrough]]; // Remaining code is important for 1n as well
372 case EventType::two_neutrons:
373 case EventType::charged_kaon:
374 case EventType::klong:
375 case EventType::kshort:
376 findSubleadingKinematics(pn_gamma, pn_daughters, event_type);
377 break;
378 default: // Nothing to do
379 break;
380 }
381
382 // Analyze detailed photonuclear interaction tracking if available
384}
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.
void findSubleadingKinematics(const ldmx::SimParticle *pnGamma, const std::vector< const ldmx::SimParticle * > &pnDaughters, const EventType eventType)
Fill histograms related to the kinematics and subleading particles for 1n, kaon, and 2n type events.
std::vector< const ldmx::SimParticle * > findDaughters(const std::map< int, ldmx::SimParticle > &particleMap, const ldmx::SimParticle *parent) const
Find all daughter particles of a parent.
EventType classifyEvent(const std::vector< const ldmx::SimParticle * > daughters, double threshold)
Method used to classify events.
CompactEventType classifyCompactEvent(const ldmx::SimParticle *pnGamma, const std::vector< const ldmx::SimParticle * > daughters, double threshold)
Method used to classify events in a compact manner.
void findRecoilProperties(const ldmx::SimParticle *recoil)
Fill the recoil electron-histograms.
void findParticleKinematics(const std::vector< const ldmx::SimParticle * > &pnDaughters)
Fill histograms related to kinematics of PN products.
void analyzeInteractionDetails(const framework::Event &event)
Analyze detailed photonuclear interaction tracking data.
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

References analyzeInteractionDetails(), classifyCompactEvent(), classifyEvent(), framework::HistogramPool::fill(), findDaughters(), findParticleKinematics(), findRecoilProperties(), findSubleadingKinematics(), and framework::EventProcessor::histograms_.

◆ analyzeInteractionDetails()

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

Analyze detailed photonuclear interaction tracking data.

If the PhotonuclearInteraction collection is present in the event, analyze the detailed cascade and descendant information.

Parameters
eventThe event to analyze

Definition at line 157 of file PhotoNuclearDQM.cxx.

157 {
158 // Check if PhotonuclearInteraction collection exists
159 if (!event.exists(pn_collection_name_, pn_pass_name_)) {
160 // Collection not present - PN tracing was not enabled
161 return;
162 }
163
164 // Get the PhotonuclearInteraction collection
165 const auto &pn_interactions =
166 event.getCollection<ldmx::PhotonuclearInteraction>(pn_collection_name_,
167 pn_pass_name_);
168
169 // Analyze full cascade genealogy information not available from SimParticles:
170 // - Target nucleus Z/A
171 // - Immediate cascade multiplicity
172 // - Full descendant genealogy tree (ALL particles, not just final state)
173
174 int n_interactions = pn_interactions.size();
175 histograms_.fill("pn_interaction_count", n_interactions);
176
177 for (const auto &interaction : pn_interactions) {
178 // Target nucleus information - UNIQUE to PhotonuclearInteraction
179 histograms_.fill("pn_target_z", interaction.getTargetZ());
180 histograms_.fill("pn_target_a", interaction.getTargetA());
181 histograms_.fill("pn_target_z:target_a", interaction.getTargetZ(),
182 interaction.getTargetA());
183
184 // Cascade multiplicity: how many particles created in initial cascade
185 int n_cascade_secondaries = interaction.getNumImmediateSecondaries();
186 histograms_.fill("pn_cascade_multiplicity", n_cascade_secondaries);
187
188 // Full cascade genealogy tree - includes ALL descendants (intermediate +
189 // final) This shows the complete cascade evolution, not just final state
190 // particles
191 auto descendant_map = interaction.getDescendantMap();
192 int total_descendants = 0;
193 for (const auto &[secondary_id, descendants] : descendant_map) {
194 int n_desc = descendants.size();
195 total_descendants += n_desc;
196 // How many particles (intermediate + final) descended from each cascade
197 // particle
198 histograms_.fill("pn_descendants_per_cascade_particle", n_desc);
199 }
200 histograms_.fill("pn_total_final_state_descendants", total_descendants);
201
202 // Cascade compactness: ratio shows what fraction of tree are immediate
203 // secondaries ~1.0 → Compact cascade, few branches (most particles are
204 // immediate secondaries) ~0.5 → Moderate branching (half the particles are
205 // from further generations) ~0.1 → Highly branched cascade with extensive
206 // decay/rescatter chains ~0.0 → Extreme branching (the "tungsten bomb"
207 // scenarios)
208 if (total_descendants > 0) {
209 double compactness_ratio =
210 static_cast<double>(n_cascade_secondaries) / total_descendants;
211 histograms_.fill("pn_cascade_evolution_ratio", compactness_ratio);
212 }
213 }
214}
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(), framework::HistogramPool::fill(), and framework::EventProcessor::histograms_.

Referenced by analyze().

◆ classifyCompactEvent()

PhotoNuclearDQM::CompactEventType dqm::PhotoNuclearDQM::classifyCompactEvent ( const ldmx::SimParticle * pnGamma,
const std::vector< const ldmx::SimParticle * > daughters,
double threshold )
private

Method used to classify events in a compact manner.

Definition at line 492 of file PhotoNuclearDQM.cxx.

494 {
495 short n{0}, n_t{0}, k0l{0}, kp{0}, k0s{0}, soft{0};
496
497 // Loop through all of the PN daughters and extract kinematic
498 // information.
499 for (const auto &daughter : daughters) {
500 // Calculate the kinetic energy
501 auto ke{daughter->getEnergy() - daughter->getMass()};
502
503 // Get the PDG ID
504 auto pdg_id{abs(daughter->getPdgID())};
505
506 if (ke < 500) {
507 soft++;
508 continue;
509 }
510
511 if (ke >= 0.8 * pnGamma->getEnergy()) {
512 if (pdg_id == 2112) {
513 n++;
514 } else if (pdg_id == 130) {
515 k0l++;
516 } else if (pdg_id == 321) {
517 kp++;
518 } else if (pdg_id == 310) {
519 k0s++;
520 }
521 continue;
522 }
523
524 if ((pdg_id == 2112) && ke > threshold) {
525 n_t++;
526 }
527 }
528
529 int neutral_kaons{k0l + k0s};
530
531 if (n != 0) {
532 return PhotoNuclearDQM::CompactEventType::single_neutron;
533 }
534 if (kp != 0) {
535 return PhotoNuclearDQM::CompactEventType::single_charged_kaon;
536 }
537 if (neutral_kaons != 0) {
538 return PhotoNuclearDQM::CompactEventType::single_neutral_kaon;
539 }
540 if (n_t == 2) {
541 return PhotoNuclearDQM::CompactEventType::two_neutrons;
542 }
543 if (soft == daughters.size()) {
544 return PhotoNuclearDQM::CompactEventType::soft;
545 }
546
547 return PhotoNuclearDQM::CompactEventType::other;
548}
double getEnergy() const
Get the energy of this particle [MeV].
Definition SimParticle.h:73

References ldmx::SimParticle::getEnergy().

Referenced by analyze().

◆ classifyEvent()

PhotoNuclearDQM::EventType dqm::PhotoNuclearDQM::classifyEvent ( const std::vector< const ldmx::SimParticle * > daughters,
double threshold )
private

Method used to classify events.

Note: Assumes that daughters is sorted by kinetic energy.

Definition at line 386 of file PhotoNuclearDQM.cxx.

387 {
388 short n{0}, p{0}, pi{0}, pi0{0}, exotic{0}, k0l{0}, kp{0}, k0s{0};
389
390 // Loop through all of the PN daughters and extract kinematic
391 // information.
392 for (const auto &daughter : daughters) {
393 // Calculate the kinetic energy
394 auto ke{daughter->getEnergy() - daughter->getMass()};
395
396 // Assuming the daughters are sorted by kinetic energy, if the kinetic
397 // energy is below threshold, we don't need to look at any further
398 // particles.
399 if (ke <= threshold) {
400 break;
401 }
402
403 // Get the PDG ID
404 auto pdg_id{abs(daughter->getPdgID())};
405
406 if (pdg_id == 2112) {
407 n++;
408 } else if (pdg_id == 2212) {
409 p++;
410 } else if (pdg_id == 211) {
411 pi++;
412 } else if (pdg_id == 111) {
413 pi0++;
414 } else if (pdg_id == 130) {
415 k0l++;
416 } else if (pdg_id == 321) {
417 kp++;
418 } else if (pdg_id == 310) {
419 k0s++;
420 } else {
421 exotic++;
422 }
423 }
424
425 int kaons = k0l + kp + k0s;
426 int nucleons = n + p;
427 int pions = pi + pi0;
428 int count = nucleons + pions + exotic + kaons;
429
430 if (count == 0) {
431 return EventType::nothing_hard;
432 }
433 if (count == 1) {
434 if (n == 1) {
435 return EventType::single_neutron;
436 } else if (p == 1) {
437 return EventType::single_proton;
438 } else if (pi0 == 1) {
439 return EventType::single_neutral_pion;
440 } else if (pi == 1) {
441 return EventType::single_charged_pion;
442 }
443 }
444 if (count == 2) {
445 if (n == 2) {
446 return EventType::two_neutrons;
447 } else if (n == 1 && p == 1) {
448 return EventType::proton_neutron;
449 } else if (p == 2) {
450 return EventType::two_protons;
451 } else if (pi == 2) {
452 return EventType::two_charged_pions;
453 } else if (pi == 1 && nucleons == 1) {
454 return EventType::single_charged_pion_and_nucleon;
455 } else if (pi0 == 1 && nucleons == 1) {
456 return EventType::single_neutral_pion_and_nucleon;
457 }
458 }
459
460 if (count == 3) {
461 if (pi == 1 && nucleons == 2) {
462 return EventType::single_charged_pion_and_two_nucleons;
463 } else if (pi == 2 && nucleons == 1) {
464 return EventType::two_charged_pions_and_nucleon;
465 } // else
466 else if (pi0 == 1 && nucleons == 2) {
467 return EventType::single_neutral_pion_and_two_nucleons;
468 } else if (pi0 == 1 && nucleons == 1 && pi == 1) {
469 return EventType::single_neutral_pion_charged_pion_and_nucleon;
470 }
471 }
472 if (count >= 3 && count == n) {
473 return EventType::three_or_more_neutrons;
474 }
475
476 if (kaons == 1) {
477 if (k0l == 1) {
478 return EventType::klong;
479 } else if (kp == 1) {
480 return EventType::charged_kaon;
481 } else if (k0s == 1) {
482 return EventType::kshort;
483 }
484 }
485 if (exotic == count && count != 0) {
486 return EventType::exotics;
487 }
488
489 return EventType::multibody;
490}

Referenced by analyze().

◆ configure()

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

Configure this analyzer using the user specified parameters.

Parameters
parametersSet of parameters used to configure this analyzer.

Reimplemented from framework::EventProcessor.

Definition at line 216 of file PhotoNuclearDQM.cxx.

216 {
217 count_light_ions_ = parameters.get<bool>("count_light_ions", true);
218 sim_particles_coll_name_ =
219 parameters.get<std::string>("sim_particles_coll_name");
220 sim_particles_passname_ =
221 parameters.get<std::string>("sim_particles_passname");
222 pn_collection_name_ = parameters.get<std::string>("pn_collection_name");
223 pn_pass_name_ = parameters.get<std::string>("pn_pass_name");
224}
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78

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

◆ findDaughters()

std::vector< const ldmx::SimParticle * > dqm::PhotoNuclearDQM::findDaughters ( const std::map< int, ldmx::SimParticle > & particleMap,
const ldmx::SimParticle * parent ) const
private

Find all daughter particles of a parent.

Particles are included if they>

  • Are in the particle map,
  • Are not photons or nuclear fragment, and
  • Are not a light ion (Z < 4) if the count_light_ions_ parameter is set to false

The products are sorted by kinetic energy, in descending order.

Definition at line 10 of file PhotoNuclearDQM.cxx.

12 {
13 std::vector<const ldmx::SimParticle *> pn_daughters;
14 for (const auto &daughter_track_id : parent->getDaughters()) {
15 // skip daughters that weren't saved
16 if (particleMap.count(daughter_track_id) == 0) {
17 continue;
18 }
19
20 auto daughter{&(particleMap.at(daughter_track_id))};
21
22 // Get the PDG ID
23 auto pdg_id{daughter->getPdgID()};
24
25 // Ignore photons and nuclei
26 if (pdg_id == 22 ||
27 (pdg_id > 10000 && (!count_light_ions_ || !isLightIon(pdg_id)))) {
28 continue;
29 }
30 pn_daughters.push_back(daughter);
31 }
32
33 std::sort(pn_daughters.begin(), pn_daughters.end(),
34 [](const auto &lhs, const auto &rhs) {
35 double lhs_ke = lhs->getEnergy() - lhs->getMass();
36 double rhs_ke = rhs->getEnergy() - rhs->getMass();
37 return lhs_ke > rhs_ke;
38 });
39
40 return pn_daughters;
41}
constexpr bool isLightIon(const int pdgCode) const
Check if the PDG code corresponds to a light ion.
std::vector< int > getDaughters() const
Get a vector containing the track IDs of all daughter particles.

References ldmx::SimParticle::getDaughters(), and isLightIon().

Referenced by analyze().

◆ findParticleKinematics()

void dqm::PhotoNuclearDQM::findParticleKinematics ( const std::vector< const ldmx::SimParticle * > & pnDaughters)
private

Fill histograms related to kinematics of PN products.

Definition at line 49 of file PhotoNuclearDQM.cxx.

50 {
51 double hardest_ke{-1}, hardest_theta{-1};
52 double hardest_proton_ke{-1}, hardest_proton_theta{-1};
53 double hardest_neutron_ke{-1}, hardest_neutron_theta{-1};
54 double hardest_pion_ke{-1}, hardest_pion_theta{-1};
55 double total_ke{0};
56 double total_neutron_ke{0};
57 int neutron_multiplicity{0};
58 // Loop through all of the PN daughters and extract kinematic
59 // information.
60 for (const auto *daughter : pnDaughters) {
61 // skip daughters that weren't saved
62
63 // Get the PDG ID
64 auto pdg_id{daughter->getPdgID()};
65
66 // Calculate the kinetic energy
67 double ke{daughter->getEnergy() - daughter->getMass()};
68 total_ke += ke;
69
70 std::vector<double> vec{daughter->getMomentum()};
71 ROOT::Math::XYZVector pvec(vec[0], vec[1], vec[2]);
72
73 // Calculate the polar angle
74 auto theta{pvec.Theta() * (180 / 3.14159)};
75
76 if (hardest_ke < ke) {
77 hardest_ke = ke;
78 hardest_theta = theta;
79 }
80
81 if (pdg_id == 2112) {
82 total_neutron_ke += ke;
83 neutron_multiplicity++;
84 if (hardest_neutron_ke < ke) {
85 hardest_neutron_ke = ke;
86 hardest_neutron_theta = theta;
87 }
88 }
89
90 if ((pdg_id == 2212) && (hardest_proton_ke < ke)) {
91 hardest_proton_ke = ke;
92 hardest_proton_theta = theta;
93 }
94
95 if (((std::abs(pdg_id) == 211) || (pdg_id == 111)) &&
96 (hardest_pion_ke < ke)) {
97 hardest_pion_ke = ke;
98 hardest_pion_theta = theta;
99 }
100 }
101 histograms_.fill("hardest_ke", hardest_ke);
102 histograms_.fill("hardest_theta", hardest_theta);
103 histograms_.fill("h_ke_h_theta", hardest_ke, hardest_theta);
104 histograms_.fill("hardest_p_ke", hardest_proton_ke);
105 histograms_.fill("hardest_p_theta", hardest_proton_theta);
106 histograms_.fill("hardest_n_ke", hardest_neutron_ke);
107 histograms_.fill("hardest_n_theta", hardest_neutron_theta);
108 histograms_.fill("hardest_pi_ke", hardest_pion_ke);
109 histograms_.fill("hardest_pi_theta", hardest_pion_theta);
110
111 histograms_.fill("pn_neutron_mult", neutron_multiplicity);
112 histograms_.fill("pn_total_ke", total_ke);
113 histograms_.fill("pn_total_neutron_ke", total_neutron_ke);
114}

References framework::HistogramPool::fill(), and framework::EventProcessor::histograms_.

Referenced by analyze().

◆ findRecoilProperties()

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

Fill the recoil electron-histograms.

Definition at line 42 of file PhotoNuclearDQM.cxx.

42 {
43 histograms_.fill("recoil_vertex_x", recoil->getVertex()[0]);
44 histograms_.fill("recoil_vertex_y", recoil->getVertex()[1]);
45 histograms_.fill("recoil_vertex_z", recoil->getVertex()[2]);
46 histograms_.fill("recoil_vertex_x:recoil_vertex_y", recoil->getVertex()[0],
47 recoil->getVertex()[1]);
48}
std::vector< double > getVertex() const
Get a vector containing the vertex of this particle in mm.

References framework::HistogramPool::fill(), ldmx::SimParticle::getVertex(), and framework::EventProcessor::histograms_.

Referenced by analyze().

◆ findSubleadingKinematics()

void dqm::PhotoNuclearDQM::findSubleadingKinematics ( const ldmx::SimParticle * pnGamma,
const std::vector< const ldmx::SimParticle * > & pnDaughters,
const EventType eventType )
private

Fill histograms related to the kinematics and subleading particles for 1n, kaon, and 2n type events.

Note: This assumes that the daughter particles are sorted by energy.

Definition at line 116 of file PhotoNuclearDQM.cxx.

119 {
120 // Note: Assumes sorted by energy
121
122 double subleading_ke{-9999};
123 double n_energy{-9999}, energy_diff{-9999}, energy_frac{-9999};
124
125 n_energy = pnDaughters[0]->getEnergy() - pnDaughters[0]->getMass();
126 subleading_ke = -9999;
127 if (pnDaughters.size() > 1) {
128 subleading_ke = pnDaughters[1]->getEnergy() - pnDaughters[1]->getMass();
129 }
130 energy_diff = pnGamma->getEnergy() - n_energy;
131 energy_frac = n_energy / pnGamma->getEnergy();
132
133 if (eventType == EventType::single_neutron) {
134 histograms_.fill("1n_ke:2nd_h_ke", n_energy, subleading_ke);
135 histograms_.fill("1n_neutron_energy", n_energy);
136 histograms_.fill("1n_energy_diff", energy_diff);
137 histograms_.fill("1n_energy_frac", energy_frac);
138 } else if (eventType == EventType::two_neutrons) {
139 histograms_.fill("2n_n2_energy", subleading_ke);
140 auto energy_frac2n = (n_energy + subleading_ke) / pnGamma->getEnergy();
141 histograms_.fill("2n_energy_frac", energy_frac2n);
142 histograms_.fill("2n_energy_other", pnGamma->getEnergy() - energy_frac2n);
143
144 } else if (eventType == EventType::charged_kaon) {
145 histograms_.fill("1kp_ke:2nd_h_ke", n_energy, subleading_ke);
146 histograms_.fill("1kp_energy", n_energy);
147 histograms_.fill("1kp_energy_diff", energy_diff);
148 histograms_.fill("1kp_energy_frac", energy_frac);
149 } else if (eventType == EventType::klong || eventType == EventType::kshort) {
150 histograms_.fill("1k0_ke:2nd_h_ke", n_energy, subleading_ke);
151 histograms_.fill("1k0_energy", n_energy);
152 histograms_.fill("1k0_energy_diff", energy_diff);
153 histograms_.fill("1k0_energy_frac", energy_frac);
154 }
155}

References framework::HistogramPool::fill(), ldmx::SimParticle::getEnergy(), and framework::EventProcessor::histograms_.

Referenced by analyze().

◆ isLightIon()

bool dqm::PhotoNuclearDQM::isLightIon ( const int pdgCode) const
inlineconstexpr

Check if the PDG code corresponds to a light ion.

Nuclear PDG codes are given by ±10LZZZAAAI So to find the atomic number, we first divide by 10 (to lose the I-component) and then take the modulo with 1000.

TODO: Repeated code from SimCore, could probably live elsewhere.

Definition at line 157 of file PhotoNuclearDQM.h.

157 {
158 if (pdgCode > 1000000000) {
159 // Check if the atomic number is less than or equal to 4
160 return ((pdgCode / 10) % 1000) <= 4;
161 }
162 return false;
163 }

Referenced by findDaughters().

Member Data Documentation

◆ count_light_ions_

bool dqm::PhotoNuclearDQM::count_light_ions_

Definition at line 165 of file PhotoNuclearDQM.h.

◆ pn_collection_name_

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

Definition at line 88 of file PhotoNuclearDQM.h.

◆ pn_pass_name_

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

Definition at line 89 of file PhotoNuclearDQM.h.

◆ sim_particles_coll_name_

std::string dqm::PhotoNuclearDQM::sim_particles_coll_name_
private

Definition at line 85 of file PhotoNuclearDQM.h.

◆ sim_particles_passname_

std::string dqm::PhotoNuclearDQM::sim_particles_passname_
private

Definition at line 86 of file PhotoNuclearDQM.h.


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