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