LDMX Software
HcalDigiProducer.cxx
Go to the documentation of this file.
1
10#include "Hcal/HcalDigiProducer.h"
11
12#include "DetDescr/HcalDigiID.h"
14#include "DetDescr/HcalID.h"
17#include "Recon/Event/HgcrocPulseTruth.h"
19
20namespace hcal {
21
22HcalDigiProducer::HcalDigiProducer(const std::string& name,
23 framework::Process& process)
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}
34
35double HcalDigiProducer::makeTimeDelta(TimeSpreadType kind,
36 std::vector<double>& parameters) const {
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}
47
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_of_flight_correction_ = ps.get<bool>("time_of_flight_correction");
88 // Time spread parameters
89 // Per hit
90 const auto& time_spread_per_hit{
91 ps.get<framework::config::Parameters>("time_spread_per_hit")};
92 int kind = time_spread_per_hit.get<int>("kind");
93 time_spread_per_hit_parameters_ =
94 time_spread_per_hit.get<std::vector<double>>("parameters");
95 do_time_spread_per_hit_ = kind != -1;
96 time_spread_per_hit_type_ = static_cast<TimeSpreadType>(kind);
97 // Per spill / event
98 const auto& time_spread_per_spill{
99 ps.get<framework::config::Parameters>("time_spread_per_spill")};
100 kind = time_spread_per_spill.get<int>("kind");
101 time_spread_per_spill_parameters_ =
102 time_spread_per_spill.get<std::vector<double>>("parameters");
103 do_time_spread_per_spill_ = kind != -1;
104 time_spread_per_spill_type_ = static_cast<TimeSpreadType>(kind);
105}
106
108 // rms noise in mV
109 noise_generator_->setNoise(gain_ * noise_rms_);
110 // mean noise amplitude (if using Gaussian Model for the noise) in mV
111 noise_generator_->setPedestal(gain_ * pedestal_);
112 // threshold for readout in mV
113 noise_generator_->setNoiseThreshold(gain_ * readout_threshold_);
114
115 // Set up seeds
118 noise_generator_->seedGenerator(
119 rseed.getSeed("HcalDigiProducer::NoiseGenerator"));
120
121 // Random number generator for layer_ / module_ / cell
122 rng_.seed(rseed.getSeed("HcalDigiProducer"));
123 // Setting up the read-out chip
124 hgcroc_->seedGenerator(rseed.getSeed("HcalDigiProducer::HgcrocEmulator"));
125
126 // Random number generator for time shifts
127 random_time_ =
128 std::make_unique<TRandom2>(rseed.getSeed("HcalDigiProducer::randomTime"));
129}
130
132 // Get the Hgcroc Conditions
133 hgcroc_->condition(
134 getCondition<conditions::DoubleTableCondition>("HcalHgcrocConditions"));
135
136 // Get the Hcal Geometry
137 const auto& hcal_geometry = getCondition<ldmx::HcalGeometry>(
139
140 // Empty collection to be filled
142 hcal_digis.setNumSamplesPerDigi(n_adcs_);
144
145 std::map<unsigned int, std::vector<const ldmx::SimCalorimeterHit*>>
146 hits_by_id;
147
148 // get simulated hcal hits from Geant4 and group them by id
149 auto hcal_sim_hits{event.getCollection<ldmx::SimCalorimeterHit>(
151
152 for (auto const& sim_hit : hcal_sim_hits) {
153 // get ID
154 unsigned int hit_id = sim_hit.getID();
155
156 auto idh = hits_by_id.find(hit_id);
157 if (idh == hits_by_id.end()) {
158 hits_by_id[hit_id] =
159 std::vector<const ldmx::SimCalorimeterHit*>(1, &sim_hit);
160 } else {
161 idh->second.push_back(&sim_hit);
162 }
163 }
164
165 ldmx::HgcrocPulseTruthCollection hcal_pulse_truth_coll;
167 hgcroc_->pulse_truth_coll_ = &hcal_pulse_truth_coll;
168 hgcroc_->save_pulse_truth_info_ = true;
169 }
170
171 /******************************************************************************************
172 * HGCROC Emulation on Simulated Hits (grouped by HcalID)
173 ******************************************************************************************/
174 double time_delta{flat_time_shift_};
175 if (do_time_spread_per_spill_) {
176 time_delta += makeTimeDelta(time_spread_per_spill_type_,
177 time_spread_per_spill_parameters_);
178 }
179 const bool explicit_layout{hcal_geometry.hasExplicitLayout()};
180 for (auto const& sim_bar : hits_by_id) {
181 ldmx::HcalID det_id(sim_bar.first);
182 int section = det_id.section();
183 int layer = det_id.layer();
184 int strip = det_id.strip();
185
186 // get position
187 double half_total_width = hcal_geometry.getHalfTotalWidth(section, layer);
188 double ecal_dx = hcal_geometry.getEcalDx();
189 double ecal_dy = hcal_geometry.getEcalDy();
190
191 // contributions
192 std::vector<std::pair<double, double>> pulses_posend;
193 std::vector<std::pair<double, double>> pulses_negend;
194
195 for (auto psim_hit : sim_bar.second) {
196 const ldmx::SimCalorimeterHit& sim_hit = *psim_hit;
197
198 std::vector<float> position = sim_hit.getPosition();
199
228 float distance_along_bar, distance_ecal;
229 float distance_close, distance_far;
230 int end_close;
231 const auto orientation{hcal_geometry.getScintillatorOrientation(det_id)};
232 if (explicit_layout) {
233 // relative to the strip center, end 0 on the positive side
234 distance_along_bar = hcal_geometry.getDistanceAlongBar(
235 det_id, position[0], position[1], position[2]);
236 end_close = (distance_along_bar > 0) ? 0 : 1;
237 distance_close = hcal_geometry.getScintillatorLength(det_id) / 2;
238 distance_far = distance_close;
239 } else if (section == ldmx::HcalID::HcalSection::BACK) {
240 distance_along_bar =
241 (orientation ==
242 ldmx::HcalGeometry::ScintillatorOrientation::horizontal)
243 ? position[0]
244 : position[1];
245 end_close = (distance_along_bar > 0) ? 0 : 1;
246 distance_close = half_total_width;
247 distance_far = half_total_width;
248 } else {
249 if ((section == ldmx::HcalID::HcalSection::TOP) ||
250 ((section == ldmx::HcalID::HcalSection::BOTTOM))) {
251 distance_along_bar = position[0];
252 distance_ecal = ecal_dx;
253 } else if ((section == ldmx::HcalID::HcalSection::LEFT) ||
254 (section == ldmx::HcalID::HcalSection::RIGHT)) {
255 distance_along_bar = position[1];
256 distance_ecal = ecal_dy;
257 } else {
258 distance_along_bar = -9999.;
259 EXCEPTION_RAISE(
260 "BadCode",
261 "We should never end up here "
262 "All cases of HCAL considered, end_close is meaningless");
263 }
264 end_close = (distance_along_bar > half_total_width) ? 0 : 1;
265 distance_close = (end_close == 0)
266 ? 2 * half_total_width - distance_ecal / 2
267 : distance_ecal / 2;
268 distance_far = (end_close == 0)
269 ? distance_ecal / 2
270 : 2 * half_total_width - distance_ecal / 2;
271 }
272
273 // Calculate voltage attenuation and time shift for the close and far
274 // pulse.
275 // velocity of light in Polystyrene, n = 1.6 = c/v mm/ns
276 float v = 299.792 / 1.6;
277 double att_close =
278 exp(-1. * ((distance_close - fabs(distance_along_bar)) / 1000.) /
279 attlength_);
280 double att_far =
281 exp(-1. * ((distance_far + fabs(distance_along_bar)) / 1000.) /
282 attlength_);
283 double shift_close =
284 fabs((distance_close - fabs(distance_along_bar)) / v);
285 double shift_far = fabs((distance_far + fabs(distance_along_bar)) / v);
286
287 // Get voltages and times.
288 for (int i_contrib = 0; i_contrib < sim_hit.getNumberOfContribs();
289 i_contrib++) {
290 double voltage = sim_hit.getContrib(i_contrib).edep_ * mev_;
291 // global time (t=0ns at target)
292 double time = sim_hit.getContrib(i_contrib).time_;
293 // shift light-speed particle traveling along z_
294 if (time_of_flight_correction_) time -= position.at(2) / 299.702547;
295 if (do_time_spread_per_hit_) {
296 time += makeTimeDelta(time_spread_per_hit_type_,
297 time_spread_per_hit_parameters_);
298 }
299 time += time_delta;
300
301 if (end_close == 0) {
302 pulses_posend.emplace_back(voltage * att_close, time + shift_close);
303 pulses_negend.emplace_back(voltage * att_far, time + shift_far);
304 } else {
305 pulses_posend.emplace_back(voltage * att_far, time + shift_far);
306 pulses_negend.emplace_back(voltage * att_close, time + shift_close);
307 }
308 }
309 }
310
320 if (hcal_geometry.isDoubleEnded(section)) {
321 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add_posend,
322 digi_to_add_negend;
323 ldmx::HcalDigiID posend_id(section, layer, strip, 0);
324 ldmx::HcalDigiID negend_id(section, layer, strip, 1);
325
326 bool pos_end_activity =
327 hgcroc_->digitize(posend_id.raw(), pulses_posend, digi_to_add_posend);
328 bool neg_end_activity =
329 hgcroc_->digitize(negend_id.raw(), pulses_negend, digi_to_add_negend);
330
331 if (pos_end_activity && neg_end_activity && zero_suppression_) {
332 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
333 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
334 } // If zeroSuppression == true, Back Hcal needs to digitize both
335 // pulses or none
336
337 if (!zero_suppression_) {
338 if (pos_end_activity) {
339 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
340 } else {
341 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
342 hgcroc_->noiseDigi(posend_id.raw(), 0.0);
343 hcal_digis.addDigi(posend_id.raw(), digi);
344 }
345 if (neg_end_activity) {
346 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
347 } else {
348 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
349 hgcroc_->noiseDigi(negend_id.raw(), 0.0);
350 hcal_digis.addDigi(negend_id.raw(), digi);
351 }
352 }
353
354 } else {
355 bool is_posend = false;
356 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add;
357 if (explicit_layout || (section == ldmx::HcalID::HcalSection::TOP) ||
358 (section == ldmx::HcalID::HcalSection::LEFT)) {
359 is_posend = true;
360 } else if ((section == ldmx::HcalID::HcalSection::BOTTOM) ||
361 (section == ldmx::HcalID::HcalSection::RIGHT)) {
362 is_posend = false;
363 }
364 if (is_posend) {
365 ldmx::HcalDigiID digi_id(section, layer, strip, 0);
366 if (hgcroc_->digitize(digi_id.raw(), pulses_posend, 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 } else {
374 ldmx::HcalDigiID digi_id(section, layer, strip, 1);
375 if (hgcroc_->digitize(digi_id.raw(), pulses_negend, digi_to_add)) {
376 hcal_digis.addDigi(digi_id.raw(), digi_to_add);
377 } else if (!zero_suppression_) {
378 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
379 hgcroc_->noiseDigi(digi_id.raw(), 0.0);
380 hcal_digis.addDigi(digi_id.raw(), digi);
381 }
382 }
383 }
384 }
385
386 /******************************************************************************************
387 * Noise Simulation on Empty Channels
388 *****************************************************************************************/
389 if (noise_) {
390 std::vector<ldmx::HcalDigiID> channel_map;
391 int num_channels = 0;
392 for (int section = 0; section < hcal_geometry.getNumSections(); section++) {
393 for (int layer = 1; layer <= hcal_geometry.getNumLayers(section);
394 layer++) {
395 // Note zero-indexed strip numbering...
396 for (int strip = 0; strip < hcal_geometry.getNumStrips(section, layer);
397 strip++) {
398 if (hcal_geometry.isDoubleEnded(section)) {
399 auto digi_i_dend0 = ldmx::HcalDigiID(section, layer, strip, 0);
400 auto digi_i_dend1 = ldmx::HcalDigiID(section, layer, strip, 1);
401 channel_map.push_back(digi_i_dend0);
402 channel_map.push_back(digi_i_dend1);
403 num_channels += 2;
404 } else {
405 auto digi_id = ldmx::HcalDigiID(section, layer, strip, 0);
406 channel_map.push_back(digi_id);
407 num_channels++;
408 }
409 }
410 }
411 }
412
413 // Uniform distributions for integer generation
414 std::uniform_int_distribution<int> section_dist(
415 0, hcal_geometry.getNumSections() - 1);
416 std::uniform_int_distribution<int> end_dist(0, 1);
417 std::uniform_int_distribution<int> clock_dist(0, clock_cycle_);
418 // explicit layout: draw only sections that have layers
419 std::vector<int> live_sections;
420 for (int section = 0; section < hcal_geometry.getNumSections(); section++) {
421 if (hcal_geometry.getNumLayers(section) > 0) {
422 live_sections.push_back(section);
423 }
424 }
425 std::uniform_int_distribution<int> live_section_dist(
426 0, static_cast<int>(live_sections.size()) - 1);
427
428 // Fast noise sim
429 if (zero_suppression_) {
430 int num_empty_channels = num_channels - hcal_digis.getNumDigis();
431 // noise generator gives us a list of noise amplitudes [mV] that randomly
432 // populate the empty channels and are above the readout threshold
433 auto noise_hit_amplitudes{
434 noise_generator_->generateNoiseHits(num_empty_channels)};
435 std::vector<std::pair<double, double>> fake_pulse(1, {0., 0.});
436
437 for (double noise_hit : noise_hit_amplitudes) {
438 // generate detector ID for noise hit
439 // making sure that it is in an empty channel
440 unsigned int noise_id;
441 int section_id, layer_id, strip_id, end_id;
442 do {
443 if (explicit_layout) {
444 section_id = live_sections[live_section_dist(rng_)];
445 layer_id = std::uniform_int_distribution<int>(
446 1, hcal_geometry.getNumLayers(section_id))(rng_);
447 strip_id = std::uniform_int_distribution<int>(
448 0, hcal_geometry.getNumStrips(section_id, layer_id) - 1)(rng_);
449 end_id =
450 hcal_geometry.isDoubleEnded(section_id) ? end_dist(rng_) : 0;
451 noise_id =
452 ldmx::HcalDigiID(section_id, layer_id, strip_id, end_id).raw();
453 continue;
454 }
455 // Get a random section value
456 section_id = section_dist(rng_);
457
458 // Get a random value for the layer_
459 std::uniform_int_distribution<int> layer_dist(
460 0, hcal_geometry.getNumLayers(section_id) - 1);
461 layer_id = layer_dist(rng_);
462 // set layer_ to 1 if the generator says it is 0 (geometry map starts
463 // from 1)
464 if (layer_id == 0) layer_id = 1;
465
466 // Get a random value for the strip
467 std::uniform_int_distribution<int> strips_dist(
468 0, hcal_geometry.getNumStrips(section_id, layer_id) - 1);
469 strip_id = strips_dist(rng_);
470
471 // Get a random value for the end
472 if ((section_id == ldmx::HcalID::HcalSection::TOP) ||
473 (section_id == ldmx::HcalID::HcalSection::LEFT)) {
474 end_id = 0;
475 } else if ((section_id == ldmx::HcalID::HcalSection::BOTTOM) ||
476 (section_id == ldmx::HcalID::HcalSection::RIGHT)) {
477 end_id = 1;
478 } else {
479 end_id = end_dist(rng_);
480 }
481 auto det_id =
482 ldmx::HcalDigiID(section_id, layer_id, strip_id, end_id);
483 noise_id = det_id.raw();
484 } while (hits_by_id.find(noise_id) != hits_by_id.end());
485 hits_by_id[noise_id] =
486 std::vector<const ldmx::SimCalorimeterHit*>(); // mark this as used
487
488 // get a time for this noise hit
489 fake_pulse[0].second = clock_dist(rng_);
490
491 // noise generator gives the amplitude above the readout threshold
492 // we need to convert it to the amplitude above the pedestal
493 double gain = hgcroc_->gain(noise_id);
494 fake_pulse[0].first = noise_hit +
495 gain * hgcroc_->readoutThreshold(noise_id) -
496 gain * hgcroc_->pedestal(noise_id);
497
498 if (hcal_geometry.isDoubleEnded(section_id)) {
499 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add_posend,
500 digi_to_add_negend;
501 ldmx::HcalDigiID posend_id(section_id, layer_id, strip_id, 0);
502 ldmx::HcalDigiID negend_id(section_id, layer_id, strip_id, 1);
503 if (hgcroc_->digitize(posend_id.raw(), fake_pulse,
504 digi_to_add_posend) &&
505 hgcroc_->digitize(negend_id.raw(), fake_pulse,
506 digi_to_add_negend)) {
507 hcal_digis.addDigi(posend_id.raw(), digi_to_add_posend);
508 hcal_digis.addDigi(negend_id.raw(), digi_to_add_negend);
509 }
510 } else {
511 std::vector<ldmx::HgcrocDigiCollection::Sample> digi_to_add;
512 if (hgcroc_->digitize(noise_id, fake_pulse, digi_to_add)) {
513 hcal_digis.addDigi(noise_id, digi_to_add);
514 }
515 }
516 } // loop over noise amplitudes
517 } else { // If zero_suppression_ == false, add noise digis for all bars
518 // without simhits
519 for (auto digi_id : channel_map) {
520 // Convert from digi ID to det ID (since simhits don't know about
521 // different ends of the bar)
522 ldmx::HcalID detid(digi_id.section(), digi_id.layer(), digi_id.strip());
523 unsigned int rawdet_id = detid.raw();
524 if (hits_by_id.find(rawdet_id) == hits_by_id.end()) {
525 std::vector<ldmx::HgcrocDigiCollection::Sample> digi =
526 hgcroc_->noiseDigi(digi_id.raw(), 0.0);
527 hcal_digis.addDigi(digi_id.raw(), digi);
528 }
529 }
530 }
531 } // if we should add noise
532
533 event.add(digi_coll_name_, hcal_digis);
535 event.add(pulse_truth_coll_name_, hcal_pulse_truth_coll);
536
537 return;
538} // produce
539
540} // namespace hcal
541
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class that translates HCal ID into positions of strip hits.
Class that defines an HCal sensitive detector.
Class that represents a digitized hit in a calorimeter cell readout by an HGCROC.
Conditions object for random number seeds.
Class which stores simulated calorimeter hit information.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
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
Performs basic HCal digitization.
bool noise_
Put noise into empty channels, not configurable, only helpful in development.
double gain_
Read out gain.
HcalDigiProducer(const std::string &name, framework::Process &process)
Constructor Makes unique noise generator and injector for this class.
double attlength_
Strip attenuation length [m].
void produce(framework::Event &event) override
Simulates measurement of pulse and creates digi collection for input event.
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.
bool time_of_flight_correction_
Subtract z/c from the hit time.
std::mt19937 rng_
Generates Gaussian noise on top of real hits_.
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.
void configure(framework::config::Parameters &) override
Configure this producer from the python configuration.
double clock_cycle_
Time interval for chip clock in ns.
std::string input_pass_name_
input pass name
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.
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.
std::unique_ptr< ldmx::NoiseGenerator > noise_generator_
Generates noise hits based off of number of cells that are not hit.
RawValue raw() const
Definition DetectorID.h:69
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
unsigned int strip() const
Get the value of the 'strip' field from the ID.
Definition HcalID.h:108
unsigned int layer() const
Get the value of the layer field from the ID.
Definition HcalID.h:90
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.
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.
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.