LDMX Software
EcalDigiProducer.cxx
Go to the documentation of this file.
1
10
13
14namespace ecal {
15
17 // settings of readout chip
18 // used in actual digitization
19 auto hgcrocParams = ps.getParameter<framework::config::Parameters>("hgcroc");
20 hgcroc_ = std::make_unique<ldmx::HgcrocEmulator>(hgcrocParams);
21 clockCycle_ = hgcrocParams.getParameter<double>("clockCycle");
22 nADCs_ = hgcrocParams.getParameter<int>("nADCs");
23 iSOI_ = hgcrocParams.getParameter<int>("iSOI");
24 noise_ = hgcrocParams.getParameter<bool>("noise");
25
26 // collection names
27 inputCollName_ = ps.getParameter<std::string>("inputCollName");
28 inputPassName_ = ps.getParameter<std::string>("inputPassName");
29 digiCollName_ = ps.getParameter<std::string>("digiCollName");
30
31 zero_suppression_ = ps.getParameter<bool>("zero_suppression");
32
33 // physical constants
34 // used to calculate unit conversions
35 MeV_ = ps.getParameter<double>("MeV");
36
37 // Time -> clock counts conversion
38 // time [ns] * ( 2^10 / max time in ns ) = clock counts
39 ns_ = 1024. / clockCycle_;
40
41 readoutThreshold_ = ps.getParameter<double>("avgReadoutThreshold");
42 pedestal_ = ps.getParameter<double>("avgPedestal");
43 noiseRMS_ = ps.getParameter<double>("avgNoiseRMS");
44}
45
47 // noise generator by default uses a Gausian model for noise
48 // i.e. It assumes the noise is distributed around a mean (setPedestal)
49 // with a certain RMS (setNoise) and then calculates
50 // how many hits should be generated for a given number of empty
51 // channels and a minimum readout value (setNoiseThreshold)
52 noiseGenerator_ = std::make_unique<ldmx::NoiseGenerator>();
53 // Configure generator that will produce noise hits in empty channels
54 // rms noise in mV
55 noiseGenerator_->setNoise(noiseRMS_);
56 // mean noise amplitude (if using Gaussian Model for the noise) in mV
57 noiseGenerator_->setPedestal(pedestal_);
58 // threshold for readout in mV
59 noiseGenerator_->setNoiseThreshold(readoutThreshold_);
60 // Set up seeds
63 noiseGenerator_->seedGenerator(
64 rseed.getSeed("EcalDigiProducer::NoiseGenerator"));
65 // Random number generator for layer / module / cell
66 rng_.seed(rseed.getSeed("EcalDigiProducer"));
67 // Setting up the read-out chip
68 hgcroc_->seedGenerator(rseed.getSeed("EcalDigiProducer::HgcrocEmulator"));
69 hgcroc_->condition(
71}
72
74 // Empty collection to be filled
78
79 // detector IDs that already have a hit in them
80 std::set<unsigned int> filledDetIDs;
81
82 /******************************************************************************************
83 * HGCROC Emulation on Simulated Hits
84 *****************************************************************************************/
85 // std::cout << "Sim Hits" << std::endl;
86 // get simulated ecal hits from Geant4
87 // the class EcalHitIO in the SimApplication module handles the translation
88 // from G4CalorimeterHits to SimCalorimeterHits this class ensures that only
89 // one SimCalorimeterHit is generated per cell, but multiple "contributions"
90 // are still handled within SimCalorimeterHit
91 auto ecalSimHits{event.getCollection<ldmx::SimCalorimeterHit>(
93
94 /* debug printout
95 std::cout << "Energy to Voltage Conversion: " << MeV_ << " mV/MeV" <<
96 std::endl;
97 */
98
99 for (auto const& simHit : ecalSimHits) {
100 std::vector<std::pair<double, double>> pulses_at_chip;
101 for (int iContrib = 0; iContrib < simHit.getNumberOfContribs();
102 iContrib++) {
103 /* debug printout
104 std::cout << simHit.getContrib(iContrib).edep << " MeV" << std::endl;
105 */
112 pulses_at_chip.emplace_back(
113 simHit.getContrib(iContrib).edep * MeV_,
114 simHit.getContrib(iContrib).time // global time (t=0ns at target)
115 - simHit.getPosition().at(2) /
116 299.702547 // shift light-speed particle traveling along z
117 );
118 }
119
120 unsigned int hitID = simHit.getID();
121 filledDetIDs.insert(hitID);
122
123 ldmx_log(debug) << " Emulation of hitID = " << hitID
124 << " with energy = " << simHit.getEdep()
125 << " MeV at time = "
126 << simHit.getTime() -
127 simHit.getPosition().at(2) / 299.702547;
128
129 // container emulator uses to write out samples and
130 // transfer samples into the digi collection
131 std::vector<ldmx::HgcrocDigiCollection::Sample> digiToAdd;
132 if (hgcroc_->digitize(hitID, pulses_at_chip, digiToAdd)) {
133 ldmx_log(debug) << " --> The HGCROC will read-out this hit!";
134 ecalDigis.addDigi(hitID, digiToAdd);
135 }
136 }
137
138 /******************************************************************************************
139 * Noise Simulation on Empty Channels
140 *****************************************************************************************/
141 if (noise_) {
142 // put noise into some empty channels
143
144 // geometry constants
145 // These are used in the noise generation so that we can randomly
146 // distribute the noise uniformly throughout the ECal channels.
147 const auto& geom = getCondition<ldmx::EcalGeometry>(
148 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
149 int nEcalLayers = geom.getNumLayers();
150 int nModulesPerLayer = geom.getNumModulesPerLayer();
151 int nCellsPerModule = geom.getNumCellsPerModule();
152 int numEmptyChannels = nEcalLayers * nModulesPerLayer * nCellsPerModule -
153 ecalDigis.getNumDigis();
154
155 // Uniform distributions for integer generation
156 std::uniform_int_distribution<int> layer_dist(0, nEcalLayers - 1);
157 std::uniform_int_distribution<int> module_dist(0, nModulesPerLayer - 1);
158 std::uniform_int_distribution<int> cell_dist(0, nCellsPerModule - 1);
159
160 if (zero_suppression_) {
161 // noise generator gives us a list of noise amplitudes [mV] that randomly
162 // populate the empty channels and are above the readout threshold
163 auto noiseHitAmplitudes{
164 noiseGenerator_->generateNoiseHits(numEmptyChannels)};
165 std::vector<std::pair<double, double>> fake_pulse(1, {0., 0.});
166 for (double noiseHit : noiseHitAmplitudes) {
167 // generate detector ID for noise hit
168 // making sure that it is in an empty channel
169 unsigned int noiseID;
170 do {
171 int layerID = layer_dist(rng_);
172 int moduleID = module_dist(rng_);
173 int cellID = cell_dist(rng_);
174 auto detID = ldmx::EcalID(layerID, moduleID, cellID);
175 noiseID = detID.raw();
176 } while (filledDetIDs.find(noiseID) != filledDetIDs.end());
177 filledDetIDs.insert(noiseID);
178
179 // noise generator gives the amplitude above the readout threshold
180 // we need to convert it to the amplitude above the pedestal
181 noiseHit +=
182 hgcroc_->gain(noiseID) *
183 (hgcroc_->readoutThreshold(noiseID) - hgcroc_->pedestal(noiseID));
184
185 // create a digi as put it into the collection
186 ecalDigis.addDigi(noiseID, hgcroc_->noiseDigi(noiseID, noiseHit));
187 } // loop over noise amplitudes
188 } else {
189 // no zero suppression, put some noise emulation in **all** empty channels
190 // loop through all channels
191 for (int layer{0}; layer < nEcalLayers; layer++) {
192 for (int module{0}; module < nModulesPerLayer; module++) {
193 for (int cell{0}; cell < nCellsPerModule; cell++) {
194 unsigned int channel{ldmx::EcalID(layer, module, cell).raw()};
195 // check if channel already has a (real) hit in it
196 if (filledDetIDs.find(channel) != filledDetIDs.end()) continue;
197 // create a digi as put it into the collection
198 ecalDigis.addDigi(channel, hgcroc_->noiseDigi(channel));
199 } // cells in each module
200 } // modules in each layer
201 } // layers in ECal
202 } // yes or no zero suppression
203 } // if we should do the noise
204
205 event.add(digiCollName_, ecalDigis);
206
207 return;
208} // produce
209
210} // namespace ecal
211
212DECLARE_PRODUCER_NS(ecal, EcalDigiProducer);
Class that performs basic ECal digitization.
Class that translates raw positions of ECal module hits into cells in a hexagonal readout.
#define DECLARE_PRODUCER_NS(NS, CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Conditions object for random number seeds.
int iSOI_
Index for the Sample Of Interest in the list of digi samples.
bool noise_
Put noise into empty channels, not configurable, only helpful in development.
std::mt19937 rng_
Generates random numbers for which channels to fill up with noise.
std::string inputCollName_
input hit collection name
double clockCycle_
Time interval for chip clock in ns.
int nADCs_
Depth of ADC buffer.
double readoutThreshold_
Read out threshold.
virtual void produce(framework::Event &event) override
Simulates measurement of pulse and creates digi collection for input event.
double pedestal_
Read out pedestal.
std::unique_ptr< ldmx::NoiseGenerator > noiseGenerator_
Generates noise hits based off of number of cells that are not hit.
virtual void configure(framework::config::Parameters &) override
Configure this producer from the python configuration.
double noiseRMS_
Noise RMS.
double ns_
Conversion from time in ns to ticks of the internal clock.
std::string digiCollName_
output hit collection name
double MeV_
Conversion from energy in MeV to voltage in mV.
virtual void onNewRun(const ldmx::RunHeader &runHeader) override
Set up random number / noise generation.
std::string inputPassName_
input pass name
std::unique_ptr< ldmx::HgcrocEmulator > hgcroc_
Hgcroc Emulator to digitize analog voltage signals.
bool zero_suppression_
When emulating noise in empty channels, do we zero suppress?
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:42
static const std::string CONDITIONS_OBJECT_NAME
Conditions object name.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
RawValue raw() const
Definition DetectorID.h:68
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Definition EcalID.h:20
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:57
Stores simulated calorimeter hit information.