LDMX Software
hcal::HcalDigiProducer Class Reference

Performs basic HCal digitization. More...

#include <HcalDigiProducer.h>

Public Types

enum class  TimeSpreadType { GAUSSIAN = 0 , UNIFORM = 1 , CONSTANT = 2 }
 

Public Member Functions

 HcalDigiProducer (const std::string &name, framework::Process &process)
 Constructor Makes unique noise generator and injector for this class.
 
virtual ~HcalDigiProducer ()=default
 Default destructor.
 
void configure (framework::config::Parameters &) override
 Configure this producer from the python configuration.
 
void produce (framework::Event &event) override
 Simulates measurement of pulse and creates digi collection for input event.
 
virtual void onNewRun (const ldmx::RunHeader &runHeader) override
 Random number generation.
 
double makeTimeDelta (TimeSpreadType kind, std::vector< double > &parameters) const
 Create a randomized time delta based on the configured time spread type.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- 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 beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
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.
 

Private Attributes

std::string input_coll_name_
 input hit collection name
 
std::string input_pass_name_
 input pass name
 
std::string digi_coll_name_
 output hit collection name
 
std::string pulse_truth_coll_name_
 output pulse truth collection name
 
double clock_cycle_
 Time interval for chip clock in ns.
 
int n_adcs_
 Depth of ADC buffer.
 
int i_soi_
 Index for the Sample Of Interest in the list of digi samples.
 
double mev_
 Conversion from energy in MeV to voltage in mV.
 
double attlength_
 Strip attenuation length [m].
 
bool noise_ {true}
 Put noise into empty channels, not configurable, only helpful in development.
 
bool save_pulse_truth_info_ {false}
 If true, save the "analog" composite pulse shape in the HGCROC emulator before it gets digitized.
 
bool zero_suppression_ {true}
 If false, save digis from all channels, even pure noise in empty bars Helpful when comparing with test beam data.
 
std::unique_ptr< ldmx::HgcrocEmulator > hgcroc_
 Hgcroc Emulator to digitize analog voltage signals.
 
double ns_
 Conversion from time in ns to ticks of the internal clock.
 
std::unique_ptr< TRandom2 > random_time_
 
bool do_time_spread_per_spill_ {false}
 
TimeSpreadType time_spread_per_spill_type_ {TimeSpreadType::UNIFORM}
 
std::vector< double > time_spread_per_spill_parameters_ {}
 
bool do_time_spread_per_hit_ {false}
 
TimeSpreadType time_spread_per_hit_type_ {TimeSpreadType::GAUSSIAN}
 
std::vector< double > time_spread_per_hit_parameters_ {}
 
double flat_time_shift_ {0.}
 
double readout_threshold_
 Read out threshold.
 
double pedestal_
 Read out pedestal.
 
double gain_
 Read out gain.
 
double noise_rms_
 Noise RMS.
 
std::unique_ptr< ldmx::NoiseGenerator > noise_generator_
 Generates noise hits based off of number of cells that are not hit.
 
std::mt19937 rng_
 Generates Gaussian noise on top of real hits_.
 

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
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Performs basic HCal digitization.

Definition at line 25 of file HcalDigiProducer.h.

Member Enumeration Documentation

◆ TimeSpreadType

enum class hcal::HcalDigiProducer::TimeSpreadType
strong

Definition at line 53 of file HcalDigiProducer.h.

53 {
54 GAUSSIAN = 0,
55 UNIFORM = 1,
56 CONSTANT = 2,
57 };

Constructor & Destructor Documentation

◆ HcalDigiProducer()

hcal::HcalDigiProducer::HcalDigiProducer ( const std::string & name,
framework::Process & process )

Constructor Makes unique noise generator and injector for this class.

Definition at line 22 of file HcalDigiProducer.cxx.

24 : Producer(name, process) {
25 /*
26 * Noise generator by default uses a Gausian model for noise
27 * i.e. it assumes the noise is distributed around a mean (setPedestal)
28 * with a certain RMS (setNoise) and then calculates
29 * how many hits should be generated for a given number of empty
30 * channels and a minimum readout value (setNoiseThreshold)
31 */
32 noise_generator_ = std::make_unique<ldmx::NoiseGenerator>();
33}
Producer(const std::string &name, Process &process)
Class constructor.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.
std::unique_ptr< ldmx::NoiseGenerator > noise_generator_
Generates noise hits based off of number of cells that are not hit.

References noise_generator_.

Member Function Documentation

◆ configure()

void hcal::HcalDigiProducer::configure ( framework::config::Parameters & ps)
overridevirtual

Configure this producer from the python configuration.

Sets event constants and configures the noise generator, noise injector, and pulse function. Creates digi collection

Reimplemented from framework::EventProcessor.

Definition at line 48 of file HcalDigiProducer.cxx.

48 {
49 // settings of readout chip
50 // used in actual digitization
51 auto hgcroc_params = ps.get<framework::config::Parameters>("hgcroc");
52 hgcroc_ = std::make_unique<ldmx::HgcrocEmulator>(hgcroc_params);
53 clock_cycle_ = hgcroc_params.get<double>("clock_cycle");
54 n_adcs_ = hgcroc_params.get<int>("n_adcs");
55 i_soi_ = hgcroc_params.get<int>("i_soi");
56 noise_ = hgcroc_params.get<bool>("noise");
57
58 // If true, ignore readout threshold
59 // and generate pedestal noise digis in every empty channel
60 zero_suppression_ = ps.get<bool>("zero_suppression");
61
62 // Save full analog pulse shapes from the HGCROC emulation
63 save_pulse_truth_info_ = ps.get<bool>("save_pulse_truth_info");
64
65 // collection names
66 input_coll_name_ = ps.get<std::string>("input_coll_name");
67 input_pass_name_ = ps.get<std::string>("input_pass_name");
68 digi_coll_name_ = ps.get<std::string>("digi_coll_name");
69 pulse_truth_coll_name_ = ps.get<std::string>("pulse_truth_coll_name");
70
71 // physical constants
72 // used to calculate unit conversions
73 mev_ = ps.get<double>("mev");
74 attlength_ = ps.get<double>("attenuation_length");
75
76 // Time -> clock counts conversion
77 // time [ns] * ( 2^10 / max time in ns ) = clock counts
78 ns_ = 1024. / clock_cycle_;
79
80 // Configure generator that will produce noise hits in empty channels
81 gain_ = ps.get<double>("avg_gain");
82 readout_threshold_ = ps.get<double>("avg_readout_threshold");
83 pedestal_ = ps.get<double>("avg_pedestal");
84 noise_rms_ = ps.get<double>("avg_noise_rms");
85
86 flat_time_shift_ = ps.get<double>("flat_time_shift");
87 // Time spread parameters
88 // Per hit
89 const auto& time_spread_per_hit{
90 ps.get<framework::config::Parameters>("time_spread_per_hit")};
91 int kind = time_spread_per_hit.get<int>("kind");
92 time_spread_per_hit_parameters_ =
93 time_spread_per_hit.get<std::vector<double>>("parameters");
94 do_time_spread_per_hit_ = kind != -1;
95 time_spread_per_hit_type_ = static_cast<TimeSpreadType>(kind);
96 // Per spill / event
97 const auto& time_spread_per_spill{
98 ps.get<framework::config::Parameters>("time_spread_per_spill")};
99 kind = time_spread_per_spill.get<int>("kind");
100 time_spread_per_spill_parameters_ =
101 time_spread_per_spill.get<std::vector<double>>("parameters");
102 do_time_spread_per_spill_ = kind != -1;
103 time_spread_per_spill_type_ = static_cast<TimeSpreadType>(kind);
104}
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
bool noise_
Put noise into empty channels, not configurable, only helpful in development.
double gain_
Read out gain.
double attlength_
Strip attenuation length [m].
bool zero_suppression_
If false, save digis from all channels, even pure noise in empty bars Helpful when comparing with tes...
std::string pulse_truth_coll_name_
output pulse truth collection name
std::string digi_coll_name_
output hit collection name
double mev_
Conversion from energy in MeV to voltage in mV.
double ns_
Conversion from time in ns to ticks of the internal clock.
double noise_rms_
Noise RMS.
int n_adcs_
Depth of ADC buffer.
std::unique_ptr< ldmx::HgcrocEmulator > hgcroc_
Hgcroc Emulator to digitize analog voltage signals.
std::string input_coll_name_
input hit collection name
double readout_threshold_
Read out threshold.
double clock_cycle_
Time interval for chip clock in ns.
std::string input_pass_name_
input pass name
bool save_pulse_truth_info_
If true, save the "analog" composite pulse shape in the HGCROC emulator before it gets digitized.
int i_soi_
Index for the Sample Of Interest in the list of digi samples.
double pedestal_
Read out pedestal.

References attlength_, clock_cycle_, digi_coll_name_, gain_, framework::config::Parameters::get(), hgcroc_, i_soi_, input_coll_name_, input_pass_name_, mev_, n_adcs_, noise_, noise_rms_, ns_, pedestal_, pulse_truth_coll_name_, readout_threshold_, save_pulse_truth_info_, and zero_suppression_.

◆ makeTimeDelta()

double hcal::HcalDigiProducer::makeTimeDelta ( TimeSpreadType kind,
std::vector< double > & parameters ) const

Create a randomized time delta based on the configured time spread type.

Currently defined options are: 0: Gaussian -> parameters[0] = mean, parameters[1] = sigma 1: Uniform -> parameters[0] = min, parameters[1] = max 2: Constant -> parameters[0] = value

Definition at line 35 of file HcalDigiProducer.cxx.

36 {
37 switch (kind) {
38 case TimeSpreadType::UNIFORM:
39 return random_time_->Uniform(parameters[0], parameters[1]);
40 case TimeSpreadType::CONSTANT:
41 return parameters[0];
42 case TimeSpreadType::GAUSSIAN:
43 return random_time_->Gaus(parameters[0], parameters[1]);
44 }
45 return 0;
46}

Referenced by produce().

◆ onNewRun()

void hcal::HcalDigiProducer::onNewRun ( const ldmx::RunHeader & runHeader)
overridevirtual

Random number generation.

Reimplemented from framework::EventProcessor.

Definition at line 106 of file HcalDigiProducer.cxx.

106 {
107 // rms noise in mV
108 noise_generator_->setNoise(gain_ * noise_rms_);
109 // mean noise amplitude (if using Gaussian Model for the noise) in mV
110 noise_generator_->setPedestal(gain_ * pedestal_);
111 // threshold for readout in mV
112 noise_generator_->setNoiseThreshold(gain_ * readout_threshold_);
113
114 // Set up seeds
117 noise_generator_->seedGenerator(
118 rseed.getSeed("HcalDigiProducer::NoiseGenerator"));
119
120 // Random number generator for layer_ / module_ / cell
121 rng_.seed(rseed.getSeed("HcalDigiProducer"));
122 // Setting up the read-out chip
123 hgcroc_->seedGenerator(rseed.getSeed("HcalDigiProducer::HgcrocEmulator"));
124
125 // Random number generator for time shifts
126 random_time_ =
127 std::make_unique<TRandom2>(rseed.getSeed("HcalDigiProducer::randomTime"));
128}
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
static const std::string CONDITIONS_OBJECT_NAME
Conditions object name.
std::mt19937 rng_
Generates Gaussian noise on top of real hits_.

References framework::RandomNumberSeedService::CONDITIONS_OBJECT_NAME, gain_, framework::EventProcessor::getCondition(), hgcroc_, noise_generator_, noise_rms_, pedestal_, readout_threshold_, and rng_.

◆ produce()

void hcal::HcalDigiProducer::produce ( framework::Event & event)
overridevirtual

Simulates measurement of pulse and creates digi collection for input event.

Define two pulses: with positive and negative ends. For this we need to: (1) Find the position along the bar: For back Hcal: x (y) for horizontal (vertical) layers. For side Hcal: x (top,bottom) and y (left,right).

(2) Define the end of the bar: The end of an HcalDigiID is based on its distance (x,y) along the bar.

  • A positive end (endID=0), corresponds to top,left.
  • A negative end (endID=1), corresponds to bottom,right. For back Hcal:
  • if the position along the bar > 0, the close pulse's end is 0, else 1. For side Hcal:
  • if the position along the bar > half_width point of the bar, the close pulse's end is 0, else 1. The far pulse's end will be opposite to the close pulse's end.

(3) Find the distance to each end (positive and negative) from the origin. For the back Hcal, the half point of the bar coincides with the coordinates of the origin. For the side Hcal, the length of the bar from the origin is:

  • 2 *(half_width) - Ecal_dx(y_)/2 away from the positive end, and,
  • Ecal_dx(y_) away from the negative end.

Now we have all the sub-hits from all the simhits Digitize: For back Hcal return two digis. For side Hcal we choose which pulse to readout based on the position of the hit and the sub-section. For Top and Left we read the positive end digi. For Bottom and Right we read the negative end digi.

Implements framework::Producer.

Definition at line 130 of file HcalDigiProducer.cxx.

130 {
131 // Get the Hgcroc Conditions
132 hgcroc_->condition(
133 getCondition<conditions::DoubleTableCondition>("HcalHgcrocConditions"));
134
135 // Get the Hcal Geometry
136 const auto& hcal_geometry = getCondition<ldmx::HcalGeometry>(
138
139 // Empty collection to be filled
141 hcal_digis.setNumSamplesPerDigi(n_adcs_);
143
144 std::map<unsigned int, std::vector<const ldmx::SimCalorimeterHit*>>
145 hits_by_id;
146
147 // get simulated hcal hits from Geant4 and group them by id
148 auto hcal_sim_hits{event.getCollection<ldmx::SimCalorimeterHit>(
150
151 for (auto const& sim_hit : hcal_sim_hits) {
152 // get ID
153 unsigned int hit_id = sim_hit.getID();
154
155 auto idh = hits_by_id.find(hit_id);
156 if (idh == hits_by_id.end()) {
157 hits_by_id[hit_id] =
158 std::vector<const ldmx::SimCalorimeterHit*>(1, &sim_hit);
159 } else {
160 idh->second.push_back(&sim_hit);
161 }
162 }
163
164 ldmx::HgcrocPulseTruthCollection hcal_pulse_truth_coll;
166 hgcroc_->pulse_truth_coll_ = &hcal_pulse_truth_coll;
167 hgcroc_->save_pulse_truth_info_ = true;
168 }
169
170 /******************************************************************************************
171 * HGCROC Emulation on Simulated Hits (grouped by HcalID)
172 ******************************************************************************************/
173 double time_delta{flat_time_shift_};
174 if (do_time_spread_per_spill_) {
175 time_delta += makeTimeDelta(time_spread_per_spill_type_,
176 time_spread_per_spill_parameters_);
177 }
178 for (auto const& sim_bar : hits_by_id) {
179 ldmx::HcalID det_id(sim_bar.first);
180 int section = det_id.section();
181 int layer = det_id.layer();
182 int strip = det_id.strip();
183
184 // get position
185 double half_total_width = hcal_geometry.getHalfTotalWidth(section, layer);
186 double ecal_dx = hcal_geometry.getEcalDx();
187 double ecal_dy = hcal_geometry.getEcalDy();
188
189 // contributions
190 std::vector<std::pair<double, double>> pulses_posend;
191 std::vector<std::pair<double, double>> pulses_negend;
192
193 for (auto psim_hit : sim_bar.second) {
194 const ldmx::SimCalorimeterHit& sim_hit = *psim_hit;
195
196 std::vector<float> position = sim_hit.getPosition();
197
226 float distance_along_bar, distance_ecal;
227 float distance_close, distance_far;
228 int end_close;
229 const auto orientation{hcal_geometry.getScintillatorOrientation(det_id)};
230 if (section == ldmx::HcalID::HcalSection::BACK) {
231 distance_along_bar =
232 (orientation ==
233 ldmx::HcalGeometry::ScintillatorOrientation::horizontal)
234 ? position[0]
235 : position[1];
236 end_close = (distance_along_bar > 0) ? 0 : 1;
237 distance_close = half_total_width;
238 distance_far = half_total_width;
239 } else {
240 if ((section == ldmx::HcalID::HcalSection::TOP) ||
241 ((section == ldmx::HcalID::HcalSection::BOTTOM))) {
242 distance_along_bar = position[0];
243 distance_ecal = ecal_dx;
244 } else if ((section == ldmx::HcalID::HcalSection::LEFT) ||
245 (section == ldmx::HcalID::HcalSection::RIGHT)) {
246 distance_along_bar = position[1];
247 distance_ecal = ecal_dy;
248 } else {
249 distance_along_bar = -9999.;
250 EXCEPTION_RAISE(
251 "BadCode",
252 "We should never end up here "
253 "All cases of HCAL considered, end_close is meaningless");
254 }
255 end_close = (distance_along_bar > half_total_width) ? 0 : 1;
256 distance_close = (end_close == 0)
257 ? 2 * half_total_width - distance_ecal / 2
258 : distance_ecal / 2;
259 distance_far = (end_close == 0)
260 ? distance_ecal / 2
261 : 2 * half_total_width - distance_ecal / 2;
262 }
263
264 // Calculate voltage attenuation and time shift for the close and far
265 // pulse.
266 // velocity of light in Polystyrene, n = 1.6 = c/v mm/ns
267 float v = 299.792 / 1.6;
268 double att_close =
269 exp(-1. * ((distance_close - fabs(distance_along_bar)) / 1000.) /
270 attlength_);
271 double att_far =
272 exp(-1. * ((distance_far + fabs(distance_along_bar)) / 1000.) /
273 attlength_);
274 double shift_close =
275 fabs((distance_close - fabs(distance_along_bar)) / v);
276 double shift_far = fabs((distance_far + fabs(distance_along_bar)) / v);
277
278 // Get voltages and times.
279 for (int i_contrib = 0; i_contrib < sim_hit.getNumberOfContribs();
280 i_contrib++) {
281 double voltage = sim_hit.getContrib(i_contrib).edep_ * mev_;
282 // global time (t=0ns at target)
283 double time = sim_hit.getContrib(i_contrib).time_;
284 // shift light-speed particle traveling along z_
285 time -= position.at(2) / 299.702547;
286 if (do_time_spread_per_hit_) {
287 time += makeTimeDelta(time_spread_per_hit_type_,
288 time_spread_per_hit_parameters_);
289 }
290 time += time_delta;
291
292 if (end_close == 0) {
293 pulses_posend.emplace_back(voltage * att_close, time + shift_close);
294 pulses_negend.emplace_back(voltage * att_far, time + shift_far);
295 } else {
296 pulses_posend.emplace_back(voltage * att_far, time + shift_far);
297 pulses_negend.emplace_back(voltage * att_close, time + shift_close);
298 }
299 }
300 }
301
311 if (section == ldmx::HcalID::HcalSection::BACK) {
312 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add_posend,
313 digi_to_add_negend;
314 ldmx::HcalDigiID posend_id(section, layer, strip, 0);
315 ldmx::HcalDigiID negend_id(section, layer, strip, 1);
316
317 bool pos_end_activity =
318 hgcroc_->digitize(posend_id.raw(), pulses_posend, digi_to_add_posend);
319 bool neg_end_activity =
320 hgcroc_->digitize(negend_id.raw(), pulses_negend, digi_to_add_negend);
321
322 if (pos_end_activity && neg_end_activity && zero_suppression_) {
323 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
324 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
325 } // If zeroSuppression == true, Back Hcal needs to digitize both
326 // pulses or none
327
328 if (!zero_suppression_) {
329 if (pos_end_activity) {
330 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
331 } else {
332 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
333 hgcroc_->noiseDigi(posend_id.raw(), 0.0);
334 hcal_digis.addDigi(posend_id.raw(), digi);
335 }
336 if (neg_end_activity) {
337 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
338 } else {
339 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
340 hgcroc_->noiseDigi(negend_id.raw(), 0.0);
341 hcal_digis.addDigi(negend_id.raw(), digi);
342 }
343 }
344
345 } else {
346 bool is_posend = false;
347 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add;
348 if ((section == ldmx::HcalID::HcalSection::TOP) ||
349 (section == ldmx::HcalID::HcalSection::LEFT)) {
350 is_posend = true;
351 } else if ((section == ldmx::HcalID::HcalSection::BOTTOM) ||
352 (section == ldmx::HcalID::HcalSection::RIGHT)) {
353 is_posend = false;
354 }
355 if (is_posend) {
356 ldmx::HcalDigiID digi_id(section, layer, strip, 0);
357 if (hgcroc_->digitize(digi_id.raw(), pulses_posend, digi_to_add)) {
358 hcal_digis.addDigi(digi_id.raw(), digi_to_add);
359 } else if (!zero_suppression_) {
360 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
361 hgcroc_->noiseDigi(digi_id.raw(), 0.0);
362 hcal_digis.addDigi(digi_id.raw(), digi);
363 }
364 } else {
365 ldmx::HcalDigiID digi_id(section, layer, strip, 1);
366 if (hgcroc_->digitize(digi_id.raw(), pulses_negend, digi_to_add)) {
367 hcal_digis.addDigi(digi_id.raw(), digi_to_add);
368 } else if (!zero_suppression_) {
369 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
370 hgcroc_->noiseDigi(digi_id.raw(), 0.0);
371 hcal_digis.addDigi(digi_id.raw(), digi);
372 }
373 }
374 }
375 }
376
377 /******************************************************************************************
378 * Noise Simulation on Empty Channels
379 *****************************************************************************************/
380 if (noise_) {
381 std::vector<ldmx::HcalDigiID> channel_map;
382 int num_channels = 0;
383 for (int section = 0; section < hcal_geometry.getNumSections(); section++) {
384 for (int layer = 1; layer <= hcal_geometry.getNumLayers(section);
385 layer++) {
386 // Note zero-indexed strip numbering...
387 for (int strip = 0; strip < hcal_geometry.getNumStrips(section, layer);
388 strip++) {
389 if (section == ldmx::HcalID::HcalSection::BACK) {
390 auto digi_i_dend0 = ldmx::HcalDigiID(section, layer, strip, 0);
391 auto digi_i_dend1 = ldmx::HcalDigiID(section, layer, strip, 1);
392 channel_map.push_back(digi_i_dend0);
393 channel_map.push_back(digi_i_dend1);
394 num_channels += 2;
395 } else {
396 auto digi_id = ldmx::HcalDigiID(section, layer, strip, 0);
397 channel_map.push_back(digi_id);
398 num_channels++;
399 }
400 }
401 }
402 }
403
404 // Uniform distributions for integer generation
405 std::uniform_int_distribution<int> section_dist(
406 0, hcal_geometry.getNumSections() - 1);
407 std::uniform_int_distribution<int> end_dist(0, 1);
408 std::uniform_int_distribution<int> clock_dist(0, clock_cycle_);
409
410 // Fast noise sim
411 if (zero_suppression_) {
412 int num_empty_channels = num_channels - hcal_digis.getNumDigis();
413 // noise generator gives us a list of noise amplitudes [mV] that randomly
414 // populate the empty channels and are above the readout threshold
415 auto noise_hit_amplitudes{
416 noise_generator_->generateNoiseHits(num_empty_channels)};
417 std::vector<std::pair<double, double>> fake_pulse(1, {0., 0.});
418
419 for (double noise_hit : noise_hit_amplitudes) {
420 // generate detector ID for noise hit
421 // making sure that it is in an empty channel
422 unsigned int noise_id;
423 int section_id, layer_id, strip_id, end_id;
424 do {
425 // Get a random section value
426 section_id = section_dist(rng_);
427
428 // Get a random value for the layer_
429 std::uniform_int_distribution<int> layer_dist(
430 0, hcal_geometry.getNumLayers(section_id) - 1);
431 layer_id = layer_dist(rng_);
432 // set layer_ to 1 if the generator says it is 0 (geometry map starts
433 // from 1)
434 if (layer_id == 0) layer_id = 1;
435
436 // Get a random value for the strip
437 std::uniform_int_distribution<int> strips_dist(
438 0, hcal_geometry.getNumStrips(section_id, layer_id) - 1);
439 strip_id = strips_dist(rng_);
440
441 // Get a random value for the end
442 if ((section_id == ldmx::HcalID::HcalSection::TOP) ||
443 (section_id == ldmx::HcalID::HcalSection::LEFT)) {
444 end_id = 0;
445 } else if ((section_id == ldmx::HcalID::HcalSection::BOTTOM) ||
446 (section_id == ldmx::HcalID::HcalSection::RIGHT)) {
447 end_id = 1;
448 } else {
449 end_id = end_dist(rng_);
450 }
451 auto det_id =
452 ldmx::HcalDigiID(section_id, layer_id, strip_id, end_id);
453 noise_id = det_id.raw();
454 } while (hits_by_id.find(noise_id) != hits_by_id.end());
455 hits_by_id[noise_id] =
456 std::vector<const ldmx::SimCalorimeterHit*>(); // mark this as used
457
458 // get a time for this noise hit
459 fake_pulse[0].second = clock_dist(rng_);
460
461 // noise generator gives the amplitude above the readout threshold
462 // we need to convert it to the amplitude above the pedestal
463 double gain = hgcroc_->gain(noise_id);
464 fake_pulse[0].first = noise_hit +
465 gain * hgcroc_->readoutThreshold(noise_id) -
466 gain * hgcroc_->pedestal(noise_id);
467
468 if (section_id == ldmx::HcalID::HcalSection::BACK) {
469 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add_posend,
470 digi_to_add_negend;
471 ldmx::HcalDigiID posend_id(section_id, layer_id, strip_id, 0);
472 ldmx::HcalDigiID negend_id(section_id, layer_id, strip_id, 1);
473 if (hgcroc_->digitize(posend_id.raw(), fake_pulse,
474 digi_to_add_posend) &&
475 hgcroc_->digitize(negend_id.raw(), fake_pulse,
476 digi_to_add_negend)) {
477 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
478 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
479 }
480 } else {
481 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add;
482 if (hgcroc_->digitize(noise_id, fake_pulse, digi_to_add)) {
483 hcal_digis.addDigi(noise_id, digi_to_add);
484 }
485 }
486 } // loop over noise amplitudes
487 } else { // If zero_suppression_ == false, add noise digis for all bars
488 // without simhits
489 for (auto digi_id : channel_map) {
490 // Convert from digi ID to det ID (since simhits don't know about
491 // different ends of the bar)
492 ldmx::HcalID detid(digi_id.section(), digi_id.layer(), digi_id.strip());
493 unsigned int rawdet_id = detid.raw();
494 if (hits_by_id.find(rawdet_id) == hits_by_id.end()) {
495 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
496 hgcroc_->noiseDigi(digi_id.raw(), 0.0);
497 hcal_digis.addDigi(digi_id.raw(), digi);
498 }
499 }
500 }
501 } // if we should add noise
502
503 event.add(digi_coll_name_, hcal_digis);
505 event.add(pulse_truth_coll_name_, hcal_pulse_truth_coll);
506
507 return;
508} // produce
double makeTimeDelta(TimeSpreadType kind, std::vector< double > &parameters) const
Create a randomized time delta based on the configured time spread type.
Extension of HcalAbstractID providing access to HCal digi information.
Definition HcalDigiID.h:13
static constexpr const char * CONDITIONS_OBJECT_NAME
Conditions object: The name of the python configuration calling this class (Hcal/python/HcalGeometry....
Implements detector ids for HCal subdetector.
Definition HcalID.h:19
Represents a collection of the digi hits readout by an HGCROC.
void setNumSamplesPerDigi(unsigned int n)
Set number of samples for each digi.
void setSampleOfInterestIndex(unsigned int n)
Set index of sample of interest.
void addDigi(unsigned int id, const std::vector< Sample > &digi)
Add samples to collection.
unsigned int getNumDigis() const
Get total number of digis.
Stores simulated calorimeter hit information.
unsigned getNumberOfContribs() const
Get the number of hit contributions.
std::vector< float > getPosition() const
Get the XYZ position of the hit [mm].
Contrib getContrib(int i) const
Get a hit contribution by index_.
float time_
Time this contributor made the hit (global Geant4 time)
float edep_
Energy depostied by this contributor.

References ldmx::HgcrocDigiCollection::addDigi(), attlength_, clock_cycle_, ldmx::HcalGeometry::CONDITIONS_OBJECT_NAME, digi_coll_name_, ldmx::SimCalorimeterHit::Contrib::edep_, framework::EventProcessor::getCondition(), ldmx::SimCalorimeterHit::getContrib(), ldmx::SimCalorimeterHit::getNumberOfContribs(), ldmx::HgcrocDigiCollection::getNumDigis(), ldmx::SimCalorimeterHit::getPosition(), hgcroc_, i_soi_, input_coll_name_, input_pass_name_, ldmx::HcalID::layer(), makeTimeDelta(), mev_, n_adcs_, noise_, noise_generator_, pulse_truth_coll_name_, ldmx::DetectorID::raw(), rng_, save_pulse_truth_info_, ldmx::HgcrocDigiCollection::setNumSamplesPerDigi(), ldmx::HgcrocDigiCollection::setSampleOfInterestIndex(), ldmx::HcalID::strip(), ldmx::SimCalorimeterHit::Contrib::time_, and zero_suppression_.

Member Data Documentation

◆ attlength_

double hcal::HcalDigiProducer::attlength_
private

Strip attenuation length [m].

Definition at line 97 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ clock_cycle_

double hcal::HcalDigiProducer::clock_cycle_
private

Time interval for chip clock in ns.

Definition at line 85 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ digi_coll_name_

std::string hcal::HcalDigiProducer::digi_coll_name_
private

output hit collection name

Definition at line 79 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ do_time_spread_per_hit_

bool hcal::HcalDigiProducer::do_time_spread_per_hit_ {false}
private

Definition at line 125 of file HcalDigiProducer.h.

125{false};

◆ do_time_spread_per_spill_

bool hcal::HcalDigiProducer::do_time_spread_per_spill_ {false}
private

Definition at line 121 of file HcalDigiProducer.h.

121{false};

◆ flat_time_shift_

double hcal::HcalDigiProducer::flat_time_shift_ {0.}
private

Definition at line 129 of file HcalDigiProducer.h.

129{0.};

◆ gain_

double hcal::HcalDigiProducer::gain_
private

Read out gain.

Definition at line 136 of file HcalDigiProducer.h.

Referenced by configure(), and onNewRun().

◆ hgcroc_

std::unique_ptr<ldmx::HgcrocEmulator> hcal::HcalDigiProducer::hgcroc_
private

Hgcroc Emulator to digitize analog voltage signals.

Definition at line 115 of file HcalDigiProducer.h.

Referenced by configure(), onNewRun(), and produce().

◆ i_soi_

int hcal::HcalDigiProducer::i_soi_
private

Index for the Sample Of Interest in the list of digi samples.

Definition at line 91 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ input_coll_name_

std::string hcal::HcalDigiProducer::input_coll_name_
private

input hit collection name

Definition at line 73 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ input_pass_name_

std::string hcal::HcalDigiProducer::input_pass_name_
private

input pass name

Definition at line 76 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ mev_

double hcal::HcalDigiProducer::mev_
private

Conversion from energy in MeV to voltage in mV.

Definition at line 94 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ n_adcs_

int hcal::HcalDigiProducer::n_adcs_
private

Depth of ADC buffer.

Definition at line 88 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ noise_

bool hcal::HcalDigiProducer::noise_ {true}
private

Put noise into empty channels, not configurable, only helpful in development.

Definition at line 104 of file HcalDigiProducer.h.

104{true};

Referenced by configure(), and produce().

◆ noise_generator_

std::unique_ptr<ldmx::NoiseGenerator> hcal::HcalDigiProducer::noise_generator_
private

Generates noise hits based off of number of cells that are not hit.

Definition at line 141 of file HcalDigiProducer.h.

Referenced by HcalDigiProducer(), onNewRun(), and produce().

◆ noise_rms_

double hcal::HcalDigiProducer::noise_rms_
private

Noise RMS.

Definition at line 138 of file HcalDigiProducer.h.

Referenced by configure(), and onNewRun().

◆ ns_

double hcal::HcalDigiProducer::ns_
private

Conversion from time in ns to ticks of the internal clock.

Definition at line 118 of file HcalDigiProducer.h.

Referenced by configure().

◆ pedestal_

double hcal::HcalDigiProducer::pedestal_
private

Read out pedestal.

Definition at line 134 of file HcalDigiProducer.h.

Referenced by configure(), and onNewRun().

◆ pulse_truth_coll_name_

std::string hcal::HcalDigiProducer::pulse_truth_coll_name_
private

output pulse truth collection name

Definition at line 82 of file HcalDigiProducer.h.

Referenced by configure(), and produce().

◆ random_time_

std::unique_ptr<TRandom2> hcal::HcalDigiProducer::random_time_
private

Definition at line 120 of file HcalDigiProducer.h.

◆ readout_threshold_

double hcal::HcalDigiProducer::readout_threshold_
private

Read out threshold.

Definition at line 132 of file HcalDigiProducer.h.

Referenced by configure(), and onNewRun().

◆ rng_

std::mt19937 hcal::HcalDigiProducer::rng_
private

Generates Gaussian noise on top of real hits_.

Definition at line 144 of file HcalDigiProducer.h.

Referenced by onNewRun(), and produce().

◆ save_pulse_truth_info_

bool hcal::HcalDigiProducer::save_pulse_truth_info_ {false}
private

If true, save the "analog" composite pulse shape in the HGCROC emulator before it gets digitized.

Definition at line 108 of file HcalDigiProducer.h.

108{false};

Referenced by configure(), and produce().

◆ time_spread_per_hit_parameters_

std::vector<double> hcal::HcalDigiProducer::time_spread_per_hit_parameters_ {}
private

Definition at line 127 of file HcalDigiProducer.h.

127{};

◆ time_spread_per_hit_type_

TimeSpreadType hcal::HcalDigiProducer::time_spread_per_hit_type_ {TimeSpreadType::GAUSSIAN}
private

Definition at line 126 of file HcalDigiProducer.h.

126{TimeSpreadType::GAUSSIAN};

◆ time_spread_per_spill_parameters_

std::vector<double> hcal::HcalDigiProducer::time_spread_per_spill_parameters_ {}
private

Definition at line 123 of file HcalDigiProducer.h.

123{};

◆ time_spread_per_spill_type_

TimeSpreadType hcal::HcalDigiProducer::time_spread_per_spill_type_ {TimeSpreadType::UNIFORM}
private

Definition at line 122 of file HcalDigiProducer.h.

122{TimeSpreadType::UNIFORM};

◆ zero_suppression_

bool hcal::HcalDigiProducer::zero_suppression_ {true}
private

If false, save digis from all channels, even pure noise in empty bars Helpful when comparing with test beam data.

Definition at line 112 of file HcalDigiProducer.h.

112{true};

Referenced by configure(), and produce().


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