LDMX Software
DarkBremInteraction.cxx
1#include "DQM/DarkBremInteraction.h"
2
3namespace dqm {
4
17static double energy(const std::vector<double>& p, const double& m) {
18 return sqrt(p.at(0) * p.at(0) + p.at(1) * p.at(1) + p.at(2) * p.at(2) +
19 m * m);
20}
21
28static double quadsum(const std::initializer_list<double>& list) {
29 double sum{0};
30 for (const double& elem : list) sum += elem * elem;
31 return sqrt(sum);
32}
33
35 const std::string& name, const std::vector<std::string>& labels) {
41 auto h{histograms_.get(name)};
42 for (std::size_t ibin{1}; ibin <= labels.size(); ibin++) {
43 h->GetXaxis()->SetBinLabel(ibin, labels[ibin - 1].c_str());
44 }
45}
46
48 setHistLabels("dark_brem_material",
49 {"Unknown", "C", "PCB", "Glue", "Si", "Al", "W / LYSO", "PVT"});
50
51 setHistLabels("dark_brem_element",
52 {"did not happen", "H 1", "C 6", "O 8", "Na 11", "Si 14",
53 "Ca 20", "Cu 29", "W / LYSO 74", "unlisted"});
54}
55
58 const auto& particle_map{
59 event.getMap<int, ldmx::SimParticle>("SimParticles")};
60 const ldmx::SimParticle *recoil{nullptr}, *aprime{nullptr}, *beam{nullptr};
61 for (const auto& [track_id, particle] : particle_map) {
62 if (track_id == 1) beam = &particle;
63 if (particle.getProcessType() ==
64 ldmx::SimParticle::ProcessType::eDarkBrem) {
65 if (particle.getPdgID() == 622) {
66 if (aprime != nullptr) {
67 EXCEPTION_RAISE("BadEvent", "Found multiple A' in event.");
68 }
69 aprime = &particle;
70 } else {
71 recoil = &particle;
72 }
73 }
74 }
75
76 if (recoil == nullptr and aprime == nullptr) {
77 /* dark brem did not occur during the simulation
78 * IF PROPERLY CONFIGURED, this occurs because the simulation
79 * exhausted the maximum number of tries to get a dark brem
80 * to occur. We just leave early so that the entries in the
81 * ntuple are the unphysical numeric minimum.
82 *
83 * This can also happen during development, so I leave a debug
84 * printout here to be uncommented when developing the dark
85 * brem simulation.
86 std::cout << "Event " << e.getEventNumber()
87 << " did not have a dark brem occur within it." << std::endl;
88 */
89 return;
90 }
91
92 if (recoil == nullptr or aprime == nullptr or beam == nullptr) {
93 // we are going to end processing so let's take our time to
94 // construct a nice error message
95 std::stringstream err_msg;
96 err_msg
97 << "Unable to find all necessary particles for DarkBrem interaction."
98 << " Missing: [ " << (recoil == nullptr ? "recoil " : "")
99 << (aprime == nullptr ? "aprime " : "")
100 << (beam == nullptr ? "beam " : "") << "]" << std::endl;
101 EXCEPTION_RAISE("BadEvent", err_msg.str());
102 return;
103 }
104
105 const auto& recoil_p = recoil->getMomentum();
106 const auto& aprime_p = aprime->getMomentum();
107
108 std::vector<double> incident_p = recoil_p;
109 for (std::size_t i{0}; i < recoil_p.size(); ++i)
110 incident_p[i] += aprime_p.at(i);
111
112 double incident_energy = energy(incident_p, recoil->getMass());
113 double recoil_energy = energy(recoil_p, recoil->getMass());
114
115 std::vector<double> ap_vertex{aprime->getVertex()};
116 std::string ap_vertex_volume{aprime->getVertexVolume()};
117 auto ap_vertex_material_it = std::find_if(
118 known_materials_.begin(), known_materials_.end(),
119 [&](const auto& mat_pair) {
120 return ap_vertex_volume.find(mat_pair.first) != std::string::npos;
121 });
122 int ap_vertex_material = (ap_vertex_material_it != known_materials_.end())
123 ? ap_vertex_material_it->second
124 : 0;
125
126 int ap_parent_id{-1};
127 if (aprime->getParents().size() > 0) {
128 ap_parent_id = aprime->getParents().at(0);
129 } else {
130 ldmx_log(error) << "Found A' without a parent ID!";
131 }
132
133 float aprime_energy = energy(aprime_p, aprime->getMass());
134 int aprime_genstatus = aprime->getGenStatus();
135 double aprime_px{aprime_p.at(0)}, aprime_py{aprime_p.at(1)},
136 aprime_pz{aprime_p.at(2)};
137 event.add("APrimeEnergy", aprime_energy);
138 event.add("APrimePx", aprime_px);
139 event.add("APrimePy", aprime_py);
140 event.add("APrimePz", aprime_pz);
141 event.add("APrimeParentID", ap_parent_id);
142 event.add("APrimeGenStatus", aprime_genstatus);
143
144 histograms_.fill("aprime_energy", aprime_energy);
145 histograms_.fill("aprime_pt", quadsum({aprime_px, aprime_py}));
146
147 int recoil_genstatus = recoil->getGenStatus();
148 double recoil_px{recoil_p.at(0)}, recoil_py{recoil_p.at(1)},
149 recoil_pz{recoil_p.at(2)};
150 event.add("RecoilEnergy", recoil_energy);
151 event.add("RecoilPx", recoil_px);
152 event.add("RecoilPy", recoil_py);
153 event.add("RecoilPz", recoil_pz);
154 event.add("RecoilGenStatus", recoil_genstatus);
155
156 histograms_.fill("recoil_energy", recoil_energy);
157 histograms_.fill("recoil_pt", quadsum({recoil_px, recoil_py}));
158
159 event.add("IncidentEnergy", incident_energy);
160 double incident_px{incident_p.at(0)}, incident_py{incident_p.at(1)},
161 incident_pz{incident_p.at(2)};
162 event.add("IncidentPx", incident_px);
163 event.add("IncidentPy", incident_py);
164 event.add("IncidentPz", incident_pz);
165
166 histograms_.fill("incident_energy", incident_energy);
167 histograms_.fill("incident_pt", quadsum({incident_px, incident_py}));
168
169 double vtx_x{aprime->getVertex().at(0)}, vtx_y{aprime->getVertex().at(1)},
170 vtx_z{aprime->getVertex().at(2)};
171 event.add("DarkBremX", vtx_x);
172 event.add("DarkBremY", vtx_y);
173 event.add("DarkBremZ", vtx_z);
174 event.add("DarkBremVertexMaterial", ap_vertex_material);
175 float db_material_z =
176 event.getEventHeader().getFloatParameter("db_material_z");
177 event.add("DarkBremVertexMaterialZ", db_material_z);
178
179 histograms_.fill("dark_brem_z", vtx_z);
180
181 int i_element = 0;
182 if (db_material_z > 0) {
183 if (known_elements_.find(static_cast<int>(db_material_z)) ==
184 known_elements_.end()) {
185 i_element = known_elements_.size();
186 } else {
187 i_element = known_elements_.at(static_cast<int>(db_material_z));
188 }
189 }
190
191 histograms_.fill("dark_brem_element", i_element);
192 histograms_.fill("dark_brem_material", ap_vertex_material);
193}
194
195} // namespace dqm
196
197DECLARE_ANALYZER_NS(dqm, DarkBremInteraction);
#define DECLARE_ANALYZER_NS(NS, CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
void setHistLabels(const std::string &name, const std::vector< std::string > &labels)
Set the labels of the histogram of the input name with the input labels.
virtual void onProcessStart() override
update the labels of some categorial histograms
std::map< std::string, int > known_materials_
the list of known materials assigning them to material ID numbers
virtual void produce(framework::Event &e) override
extract the kinematics of the dark brem interaction from the SimParticles
std::map< int, int > known_elements_
The list of known elements assigning them to the bins that we are putting them into.
HistogramHelper histograms_
Interface class for making and filling histograms.
Implements an event buffer system for storing event data.
Definition Event.h:41
ldmx::EventHeader & getEventHeader()
Get the event header.
Definition Event.h:58
TH1 * get(const std::string &name)
Get a pointer to a histogram by name.
Definition Histograms.h:194
void fill(const std::string &name, const double &val)
Fill a 1D histogram.
Definition Histograms.h:166
void setWeight(double w)
Set the weight for filling the histograms.
Definition Histograms.h:91
double getWeight() const
Get the event weight (default of 1.0).
Definition EventHeader.h:98
Class representing a simulated particle.
Definition SimParticle.h:23