LDMX Software
TrigScintQIEDigiProducer.cxx
2
3#include <map>
4
5#include "DetDescr/TrigScintID.h"
6#include "Framework/Logger.h"
9#include "SimCore/Event/SimParticle.h"
10#include "TrigScint/Event/TrigScintQIEDigis.h"
11
12namespace trigscint {
13
14TrigScintQIEDigiProducer::TrigScintQIEDigiProducer(const std::string& name,
15 framework::Process& process)
16 : Producer(name, process) {}
17
18void TrigScintQIEDigiProducer::configure(
20 // Configure this instance of the producer
21 strips_per_array_ = parameters.get<int>("number_of_strips");
22 // number_of_arrays_ = parameters.get<int>("number_of_arrays");
23 mean_noise_ = parameters.get<double>("mean_noise");
24 mev_per_mip_ = parameters.get<double>("mev_per_mip");
25 pe_per_mip_ = parameters.get<double>("pe_per_mip");
26 input_collection_ = parameters.get<std::string>("input_collection");
27 input_pass_name_ = parameters.get<std::string>("input_pass_name");
28 output_collection_ = parameters.get<std::string>("output_collection");
29 sim_particles_coll_name_ =
30 parameters.get<std::string>("sim_particles_coll_name");
31 sim_particles_passname_ =
32 parameters.get<std::string>("sim_particles_passname");
33
34 // QIE specific parameters initialization
35 maxts_ = parameters.get<int>("maxts");
36 toff_overall_ = parameters.get<double>("toff_overall");
37 input_pulse_shape_ = parameters.get<std::string>("input_pulse_shape");
38 tdc_thr_ = parameters.get<double>("tdc_thr");
39 pedestal_ = parameters.get<double>("pedestal");
40 elec_noise_ = parameters.get<double>("elec_noise");
41 sipm_gain_ = parameters.get<double>("sipm_gain");
42 s_freq_ = parameters.get<double>("qie_sf");
43 zero_supp_cut_ = parameters.get<double>("zero_supp_in_pe");
44
45 if (input_pulse_shape_ == "Expo") {
46 pulse_params_.clear();
47 pulse_params_.push_back(parameters.get<double>("expo_k"));
48 pulse_params_.push_back(parameters.get<double>("expo_tmax"));
49
50 ldmx_log(debug) << "expo_k =" << pulse_params_[0];
51 ldmx_log(debug) << "expo_tmax =" << pulse_params_[1];
52 }
53
54 // Debug mode: print parameter values.
55 ldmx_log(debug) << "maxts_ =" << maxts_;
56 ldmx_log(debug) << "toff_overall_ =" << toff_overall_;
57 ldmx_log(debug) << "input_pulse_shape_ =" << input_pulse_shape_;
58 ldmx_log(debug) << "tdc_thr =" << tdc_thr_;
59 ldmx_log(debug) << "pedestal =" << pedestal_;
60 ldmx_log(debug) << "elec_noise =" << elec_noise_;
61 ldmx_log(debug) << "sipm_gain =" << sipm_gain_;
62 ldmx_log(debug) << "qie_sf =" << s_freq_;
63 ldmx_log(debug) << "zero_supp_in_pe =" << zero_supp_cut_;
64 ldmx_log(debug) << "pe_per_mip =" << pe_per_mip_;
65 ldmx_log(debug) << "mev_per_mip =" << mev_per_mip_;
66}
67
68void TrigScintQIEDigiProducer::produce(framework::Event& event) {
69 // no sim hits, e.g. real data
70 if (!event.exists(input_collection_, input_pass_name_)) {
71 ldmx_log(warn) << "No input collection " << input_collection_ << "_"
72 << input_pass_name_ << " found; skipping";
73 return;
74 }
75
76 // Need to handle seeding on the first event
77 if (random_.get() == nullptr) {
78 const auto& rseed = getCondition<framework::RandomNumberSeedService>(
80 const auto& rseed2 = getCondition<framework::RandomNumberSeedService>(
82
83 random_ = std::make_unique<TRandom3>(rseed.getSeed(output_collection_));
84
85 // Initialize SimQIE instance with
86 // pedestal, electronic noise and the random seed
87 smq_ = new SimQIE(pedestal_, elec_noise_,
88 rseed2.getSeed(output_collection_ + "SimQIE"));
89
90 smq_->setGain(sipm_gain_);
91 smq_->setFreq(s_freq_);
92 smq_->setNTimeSamples(maxts_);
93 smq_->setTDCThreshold(tdc_thr_);
94 }
95
96 // To simulate multiple pulses coming at different times, SiPMS
97 // Initialize with strips_per_array_ zeros
98 std::vector<float> true_edep(strips_per_array_, 0.);
99
100 // The part of true_edep deposited by beam electrons
101 std::vector<float> beam_edep(strips_per_array_, 0.);
102
103 // Initialize with strips_per_array_ nullptrs
104 std::vector<Expo*> ex(strips_per_array_, nullptr);
105 for (int i = 0; i < strips_per_array_; i++) {
106 // Set the pulse shape with fixed parameters given by config. file
107 ex[i] = new Expo(pulse_params_[0], pulse_params_[1]);
108 true_edep[i] = 0;
109 }
110
111 // loop over sim hits and aggregate energy depositions for each detID
112 const auto sim_hits{event.getCollection<ldmx::SimCalorimeterHit>(
113 input_collection_, input_pass_name_)};
114 const bool has_sim_particles{
115 event.exists(sim_particles_coll_name_, sim_particles_passname_)};
116 if (!has_sim_particles) {
117 ldmx_log(debug) << "No " << sim_particles_coll_name_
118 << " found; beamEfrac set to -1";
119 }
120 const auto particle_map{
121 has_sim_particles ? event.getMap<int, ldmx::SimParticle>(
122 sim_particles_coll_name_, sim_particles_passname_)
123 : std::map<int, ldmx::SimParticle>{}};
124
125 for (const auto& sim_hit : sim_hits) {
126 ldmx::TrigScintID id(sim_hit.getID());
127
128 ldmx_log(debug) << "Processing sim hit with bar ID: " << id.bar();
129
130 // tag the edep coming from beam electrons
131 for (int i = 0; i < sim_hit.getNumberOfContribs(); i++) {
132 const auto contrib{sim_hit.getContrib(i)};
133 const auto particle{particle_map.find(contrib.track_id_)};
134 if (particle == particle_map.end()) continue;
135
136 ldmx_log(trace) << "contrib " << i << " trackID: " << contrib.track_id_
137 << " pdgID: " << contrib.pdg_code_
138 << " edep: " << contrib.edep_;
139 ldmx_log(trace) << "\t particle id: " << particle->second.getPdgID()
140 << " particle status: "
141 << particle->second.getGenStatus();
142
143 if (particle->second.getPdgID() == 11 &&
144 particle->second.getGenStatus() == 1) {
145 beam_edep[id.bar()] += contrib.edep_;
146 }
147 }
148
149 // Simulating the noise corresponding to uncertainity in
150 // detecting scintillating photons.
151 // Poissonian distribution with mean = mean PEs generated
152 double pulse_amp =
153 random_->Poisson(sim_hit.getEdep() / mev_per_mip_ * pe_per_mip_);
154
155 // Adding a pulse for every sim hit recorded.
156 // time offset = global offset+simhit time
157 ex[id.bar()]->addPulse(toff_overall_ + sim_hit.getTime(), pulse_amp);
158
159 // incrementing true energy deposited in appropriate bar.
160 true_edep[id.bar()] += sim_hit.getEdep();
161 }
162
163 // A container to hold the digitized trigger scintillator hits.
164 std::vector<trigscint::TrigScintQIEDigis> q_digis;
165
166 double total_noise = mean_noise_ * maxts_;
167
168 // time period[ns] = 1000/sampling freq.[MHz]
169 double sampling_time = 1000 / s_freq_;
170
171 // Loop over all the bars available.
172 for (int bar_id = 0; bar_id < strips_per_array_; bar_id++) {
173 // Dark current simulation
174 // e-hole pairs may be generated at random times in SiPM
175 // due to thermal fluctuations.
176 // Every e- thus generated, mimicks a Photo Electron.
177 // Hence we will creat 1PE pulses for each electron generated.
178 int n_noise_pulses = random_->Poisson(total_noise);
179 for (int i = 0; i < n_noise_pulses; i++) {
180 ex[bar_id]->addPulse(random_->Uniform(0, maxts_ * sampling_time), 1);
181 }
182
183 // Storing the "good" digis
184 if (smq_->pulseCut(ex[bar_id], zero_supp_cut_)) {
186
187 qie_info.setChanID(bar_id);
188 qie_info.setADC(smq_->outAdc(ex[bar_id]));
189 qie_info.setTDC(smq_->outTdc(ex[bar_id]));
190 qie_info.setCID(smq_->capId(ex[bar_id]));
191
192 // sim truth; dark-current-only bars get 0, no SimParticles get -1
193 if (has_sim_particles) {
194 qie_info.setBeamEfrac(
195 true_edep[bar_id] > 0 ? beam_edep[bar_id] / true_edep[bar_id] : 0.);
196 }
197
198 q_digis.push_back(qie_info);
199 }
200 }
201 event.add(output_collection_, q_digis);
202}
203
204} // namespace trigscint
205
#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 simulates QIE chip of the trigger scintillator.
Implements an event buffer system for storing event data.
Definition Event.h:40
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
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
Stores simulated calorimeter hit information.
Class representing a simulated particle.
Definition SimParticle.h:25
Class that defines the detector ID of the trigger scintillator.
Definition TrigScintID.h:14
piece-wise exponential pulse, modelled as an output of a capacitor
class for simulating QIE chip output
Definition SimQIE.h:14
Class that simulates QIE chip of the trigger scintillator.
class for storing QIE output
void setCID(const std::vector< int > cid)
Store cids of all time samples.
void setTDC(const std::vector< int > tdc)
Store tdcs of all time samples.
void setChanID(const int chanid)
Store the channel ID.
void setBeamEfrac(const float beamEfrac)
Store the beam energy fraction.
void setADC(const std::vector< int > adc)
Store adcs of all time samples.