LDMX Software
TrigScintDigiProducer.cxx
2
5#include "SimCore/Event/SimParticle.h"
6#include "TrigScint/Event/TrigScintHit.h"
7
8namespace trigscint {
9
10TrigScintDigiProducer::TrigScintDigiProducer(const std::string& name,
11 framework::Process& process)
12 : Producer(name, process) {}
13
14void TrigScintDigiProducer::configure(framework::config::Parameters& ps) {
15 // Configure this instance of the producer
16 strips_per_array_ = ps.get<int>("number_of_strips");
17 number_of_arrays_ = ps.get<int>("number_of_arrays");
18 mean_noise_ = ps.get<double>("mean_noise");
19 mev_per_mip_ = ps.get<double>("mev_per_mip");
20 pe_per_mip_ = ps.get<double>("pe_per_mip");
21 input_collection_ = ps.get<std::string>("input_collection");
22 input_pass_name_ = ps.get<std::string>("input_pass_name");
23 output_collection_ = ps.get<std::string>("output_collection");
24 sim_particles_coll_name_ = ps.get<std::string>("sim_particles_coll_name");
25 sim_particles_passname_ = ps.get<std::string>("sim_particles_passname");
26}
27
28void TrigScintDigiProducer::onNewRun(const ldmx::RunHeader&) {
29 noise_generator_ = std::make_unique<ldmx::NoiseGenerator>(mean_noise_, false);
30 noise_generator_->setNoiseThreshold(1);
31 // Set up seeds
32 const auto& rseed = getCondition<framework::RandomNumberSeedService>(
34
35 noise_generator_->seedGenerator(
36 rseed.getSeed("TrigScintDigiProducer::NoiseGenerator"));
37 // Random number generator for module id
38 rng_.seed(rseed.getSeed("TrigScintDigiProducer"));
39}
40
41ldmx::TrigScintID TrigScintDigiProducer::generateRandomID(int module) {
42 // Uniform distributions for integer generation
43 std::uniform_int_distribution<int> strips_dist(0, strips_per_array_ - 1);
44 ldmx::TrigScintID temp_id(module, strips_dist(rng_));
45 if (module >= TrigScintSection::NUM_SECTIONS) {
46 ldmx_log(fatal) << "TrigScintSection is not known";
47 }
48
49 return temp_id;
50}
51
52void TrigScintDigiProducer::produce(framework::Event& event) {
53 std::map<ldmx::TrigScintID, int> cell_pes, cell_min_p_es;
54 std::map<ldmx::TrigScintID, float> xpos, ypos, zpos, edep, time, beam_frac;
55 std::set<ldmx::TrigScintID> noise_hit_i_ds;
56
57 auto num_rec_hits{0};
58
59 // looper over sim hits and aggregate energy depositions for each detID
60 const auto sim_hits{event.getCollection<ldmx::SimCalorimeterHit>(
61 input_collection_, input_pass_name_)};
62 auto particle_map{event.getMap<int, ldmx::SimParticle>(
63 sim_particles_coll_name_, sim_particles_passname_)};
64
65 int module{-1};
66 for (const auto& sim_hit : sim_hits) {
67 ldmx::TrigScintID id(sim_hit.getID());
68
69 // Just set the module ID to use for noise hits here. Given that
70 // we are currently processing a single module at a time, setting
71 // it within the loop shouldn't matter.
72 module = id.module();
73 std::vector<float> position = sim_hit.getPosition();
74 ldmx_log(trace) << " Module ID = " << id.raw();
75
76 // check if hits is from beam electron and, if so, add to beamFrac
77 for (int i = 0; i < sim_hit.getNumberOfContribs(); i++) {
78 auto contrib = sim_hit.getContrib(i);
79
80 ldmx_log(trace) << "contrib " << i << " trackID: " << contrib.track_id_
81 << " pdgID: " << contrib.pdg_code_
82 << " edep: " << contrib.edep_;
83 ldmx_log(trace) << "\t particle id: "
84 << particle_map[contrib.track_id_].getPdgID()
85 << " particle status: "
86 << particle_map[contrib.track_id_].getGenStatus();
87
88 if (particle_map[contrib.track_id_].getPdgID() == 11 &&
89 particle_map[contrib.track_id_].getGenStatus() == 1) {
90 if (beam_frac.find(id) == beam_frac.end()) {
91 beam_frac[id] = contrib.edep_;
92 } else {
93 beam_frac[id] += contrib.edep_;
94 }
95 }
96 }
97
98 // for now, we take an energy weighted average of the hit in each strip to
99 // simulate the hit position. AJW: these should be dropped, they are likely
100 // to lead to a problem since we can't measure them anyway except roughly y
101 // and z, which is encoded in the ids.
102 if (edep.find(id) == edep.end()) {
103 // first hit, initialize
104 edep[id] = sim_hit.getEdep();
105 time[id] = sim_hit.getTime() * sim_hit.getEdep();
106 xpos[id] = position[0] * sim_hit.getEdep();
107 ypos[id] = position[1] * sim_hit.getEdep();
108 zpos[id] = position[2] * sim_hit.getEdep();
109 num_rec_hits++;
110
111 } else {
112 // not first hit, aggregate, and store the largest radius hit
113 xpos[id] += position[0] * sim_hit.getEdep();
114 ypos[id] += position[1] * sim_hit.getEdep();
115 zpos[id] += position[2] * sim_hit.getEdep();
116 edep[id] += sim_hit.getEdep();
117 // AJW: need to figure out a better way to model this...
118 time[id] += sim_hit.getTime() * sim_hit.getEdep();
119 }
120 }
121
122 // Create the container to hold the digitized trigger scintillator hits.
123 std::vector<ldmx::TrigScintHit> trig_scint_hits;
124
125 // loop over detIDs and simulate number of PEs
126 for (std::map<ldmx::TrigScintID, float>::iterator it = edep.begin();
127 it != edep.end(); ++it) {
128 ldmx::TrigScintID id(it->first);
129
130 double dep_energy = edep[id];
131 time[id] = time[id] / edep[id];
132 xpos[id] = xpos[id] / edep[id];
133 ypos[id] = ypos[id] / edep[id];
134 zpos[id] = zpos[id] / edep[id];
135 // mean number of photoelectrons produced for the given deposited energy
136 double mean_pe = dep_energy / mev_per_mip_ * pe_per_mip_;
137 std::poisson_distribution<int> poisson_dist(mean_pe + mean_noise_);
138 cell_pes[id] = poisson_dist(rng_);
139 // energy corresponding to the number of PEs observed
140 // the minimum number of PEs is the mean number of PEs minus the noise
141 double energy_per_pe = mev_per_mip_ / pe_per_mip_;
142 double cell_energy = energy_per_pe * cell_pes[id];
143
144 // If a cell has a PE count above threshold, persit the hit.
145 // Thresholds are introduced (and configurable) in clustering.
146 // the cell PE >=1 suppresses artifical noise that is below one light
147 // quantum in the SiPM and unphysical.
148 if (cell_pes[id] >= 1) {
150 hit.setID(id.raw());
151 hit.setPE(cell_pes[id]);
152 hit.setMinPE(cell_min_p_es[id]);
153 hit.setAmplitude(cell_pes[id]);
154 hit.setEnergy(cell_energy);
155 hit.setTime(time[id]);
156 hit.setXPos(xpos[id]);
157 hit.setYPos(ypos[id]);
158 hit.setZPos(zpos[id]);
159 hit.setModuleID(module);
160 hit.setBarID(id.bar()); // getFieldValue("bar"));
161 hit.setNoise(false);
162 hit.setBeamEfrac(beam_frac[id] / dep_energy);
163
164 trig_scint_hits.push_back(hit);
165 }
166
167 ldmx_log(debug) << " ID = " << id.raw() << " Edep: " << edep[id]
168 << " numPEs: " << cell_pes[id] << " time: " << time[id]
169 << " z: " << zpos[id] << "\t X: " << xpos[id]
170 << " Y: " << ypos[id] << " Z: " << zpos[id];
171 } // end of loop over detIDs
172
173 // ------------------------------- Noise simulation -----------------------//
174 // ------------------------------------------------------------------------//
175 // only simulating for single array until
176 // all arrays are merged into one collection
177 int num_empty_cells = strips_per_array_ - num_rec_hits;
178 std::vector<double> noise_hits_pe =
179 noise_generator_->generateNoiseHits(num_empty_cells);
180
181 ldmx::TrigScintID temp_id;
182
183 for (auto& noise_hit_pe : noise_hits_pe) {
185 // generate random ID from remaining cells
186 do {
187 temp_id = generateRandomID(module);
188 } while (edep.find(temp_id) != edep.end() ||
189 noise_hit_i_ds.find(temp_id) != noise_hit_i_ds.end());
190
191 ldmx::TrigScintID noise_id = temp_id;
192
193 noise_hit_i_ds.insert(noise_id);
194 hit.setID(noise_id.raw());
195 hit.setPE(noise_hit_pe);
196 hit.setMinPE(noise_hit_pe);
197 hit.setAmplitude(noise_hit_pe);
198 hit.setEnergy(0.);
199 hit.setTime(0.);
200 hit.setXPos(0.);
201 hit.setYPos(0.);
202 hit.setZPos(0.);
203 hit.setModuleID(module);
204 hit.setBarID(noise_id.bar());
205 hit.setNoise(true);
206 hit.setBeamEfrac(0.);
207
208 trig_scint_hits.push_back(hit);
209 }
210 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211 // - -
212
213 event.add(output_collection_, trig_scint_hits);
214}
215} // namespace trigscint
216
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Conditions object for random number seeds.
Class which stores simulated calorimeter hit information.
Class that performs digitization of simulated trigger sctintillator.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class which represents the process under execution.
Definition Process.h:34
static const std::string CONDITIONS_OBJECT_NAME
Conditions object name.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
void setYPos(float ypos)
Set the Y position of the hit [mm].
void setID(int id)
Set the detector ID.
void setZPos(float zpos)
Set the Z position of the hit [mm].
void setXPos(float xpos)
Set the X position of the hit [mm].
void setTime(float time)
Set the time of the hit [ns].
void setAmplitude(float amplitude)
Set the amplitude of the hit, which is proportional to the signal in the calorimeter cell without sam...
void setEnergy(float energy)
Set the calorimetric energy of the hit, corrected for sampling factors [MeV].
void setNoise(bool yes)
Set if this hit is a noise hit.
RawValue raw() const
Definition DetectorID.h:69
void setMinPE(float minpe)
Set the minimum number of photoelectrons estimated for this hit.
Definition HcalHit.h:160
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:68
Stores simulated calorimeter hit information.
Class representing a simulated particle.
Definition SimParticle.h:25
void setPE(const float PE)
Set hit pe.
void setBarID(const int barID)
Set hit bar ID.
void setBeamEfrac(const float beamEfrac)
Set beam energy fraction of hit.
void setModuleID(const int moduleID)
Set hit module ID.
Class that defines the detector ID of the trigger scintillator.
Definition TrigScintID.h:14
int bar() const
Get the value of the bar field from the ID.
Definition TrigScintID.h:64
Performs digitization of simulated Trigger Scintillator data.