Belle II Software development
PXDDigitizerModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <pxd/modules/pxdSimulation/PXDDigitizerModule.h>
10#include <vxd/geometry/GeoCache.h>
11#include <vxd/geometry/GeoTools.h>
12#include <pxd/reconstruction/PXDGainCalibrator.h>
13#include <pxd/reconstruction/PXDPixelMasker.h>
14
15#include <framework/logging/Logger.h>
16#include <framework/gearbox/Unit.h>
17#include <framework/gearbox/Const.h>
18#include <framework/datastore/DataStore.h>
19#include <framework/datastore/StoreArray.h>
20#include <framework/datastore/RelationArray.h>
21#include <framework/datastore/RelationIndex.h>
22
23#include <mdst/dataobjects/MCParticle.h>
24#include <pxd/dataobjects/PXDTrueHit.h>
25#include <pxd/dataobjects/PXDDigit.h>
26#include <cmath>
27
28#include <TRandom.h>
29
30using namespace std;
31using namespace Belle2;
32using namespace Belle2::PXD;
33
34//-----------------------------------------------------------------
35// Register the Module
36//-----------------------------------------------------------------
37REG_MODULE(PXDDigitizer);
38
39//-----------------------------------------------------------------
40// Implementation
41//-----------------------------------------------------------------
42
44 , m_noiseFraction(0), m_eToADU(0), m_chargeThreshold(0), m_chargeThresholdElectrons(0)
45 , m_currentHit(nullptr), m_currentParticle(0), m_currentTrueHit(0), m_currentSensor(nullptr)
46 , m_currentSensorInfo(nullptr), m_nGates(0), m_pxdIntegrationTime(0), m_timePerGate(0)
47 , m_triggerGate(0), m_gated(false)
48{
49 //Set module properties
50 setDescription("Digitize PXDSimHits");
52 addParam("ElectronicEffects", m_applyNoise, "Apply electronic effects?",
53 true);
54 addParam("ElectronicNoise", m_elNoise,
55 "Noise added by the electronics, set in ENC", 150.0);
56
57 addParam("MCParticles", m_storeMCParticlesName,
58 "MCParticle collection name", string(""));
59 addParam("Digits", m_storeDigitsName, "Digits collection name", string(""));
60 addParam("SimHits", m_storeSimHitsName, "SimHit collection name",
61 string(""));
62 addParam("TrueHits", m_storeTrueHitsName, "TrueHit collection name",
63 string(""));
64
65 addParam("PoissonSmearing", m_applyPoisson,
66 "Apply Poisson smearing of electrons collected on pixels?", true);
67 addParam("IntegrationWindow", m_applyWindow, "Use integration window?",
68 true);
69
70 addParam("SegmentLength", m_segmentLength, "Maximum segment length (in mm)",
71 0.005);
72 addParam("ElectronGroupSize", m_elGroupSize,
73 "Split Signalpoints in smaller groups of N electrons (in e)", 100);
74 addParam("ElectronStepTime", m_elStepTime,
75 "Time step for tracking electron groups in readout plane (in ns)",
76 1.0);
77 addParam("ElectronMaxSteps", m_elMaxSteps,
78 "Maximum number of steps when propagating electrons", 200);
79 addParam("Gq", m_gq, "Gq of a pixel in nA/electron", 0.6);
80 addParam("ADCUnit", m_ADCUnit, "Slope of the linear ADC transfer curve in nA/ADU", 130.0);
81 addParam("PedestalMean", m_pedestalMean, "Mean of pedestals in ADU", 100.0);
82 addParam("PedestalRMS", m_pedestalRMS, "RMS of pedestals in ADU", 30.0);
83 addParam("GatingTime", m_gatingTime,
84 "Time window during which the PXD is not collecting charge in nano seconds", 400.0);
85 addParam("GatingWithoutReadout", m_gatingWithoutReadout,
86 "Digits from gated rows not sent to DHH ", true);
87 addParam("GatingWithoutReadoutTime", m_gatingWithoutReadoutTime,
88 "Time window during which digits from gated rows are not sent to DHH in nano seconds", 1400.0);
89 addParam("HardwareDelay", m_hwdelay,
90 "Constant time delay between bunch crossing and switching on triggergate in nano seconds", 0.0);
91
92}
93
95{
96 //Register output collections
98 storeDigits.registerInDataStore();
100 storeDigits.registerRelationTo(storeParticles);
102 storeDigits.registerRelationTo(storeTrueHits);
103
104 m_storePXDTiming.isOptional();
105
106 //Set default names for the relations
108 DataStore::arrayName<MCParticle>(m_storeMCParticlesName),
109 DataStore::arrayName<PXDSimHit>(m_storeSimHitsName));
111 DataStore::arrayName<PXDTrueHit>(m_storeTrueHitsName),
112 DataStore::arrayName<PXDSimHit>(m_storeSimHitsName));
114 DataStore::arrayName<PXDDigit>(m_storeDigitsName),
115 DataStore::arrayName<MCParticle>(m_storeMCParticlesName));
117 DataStore::arrayName<PXDDigit>(m_storeDigitsName),
118 DataStore::arrayName<PXDTrueHit>(m_storeTrueHitsName));
119
120 //Convert parameters to correct units
125
126 // Get number of PXD gates
127 auto gTools = VXD::GeoCache::getInstance().getGeoTools();
128 m_nGates = gTools->getNumberOfPXDReadoutGates();
129
130 // Active integration time (per gate) in ns
131 m_pxdIntegrationTime = 20000.0;
132 // Readout time per gate (sample - clear - cycle of rolling shutter) in ns
134
135 B2DEBUG(20, "PXDDigitizer Parameters (in system units, *=calculated +=set in xml):");
136 B2DEBUG(20, " --> ElectronicEffects: " << (m_applyNoise ? "true" : "false"));
137 B2DEBUG(20, " --> ElectronicNoise: " << m_elNoise << " e-");
138 B2DEBUG(20, " --> +ChargeThreshold: " << "set in xml by sensor, nominal 4 ADU");
139 B2DEBUG(20, " --> *NoiseFraction: " << "set in xml by sensor, nominal 1.0e-5");
140 B2DEBUG(20,
141 " --> MCParticles: " << DataStore::arrayName<MCParticle>(m_storeMCParticlesName));
142 B2DEBUG(20,
143 " --> SimHits: " << DataStore::arrayName<PXDSimHit>(m_storeSimHitsName));
144 B2DEBUG(20,
145 " --> Digits: " << DataStore::arrayName<PXDDigit>(m_storeDigitsName));
146 B2DEBUG(20,
147 " --> TrueHits: " << DataStore::arrayName<PXDTrueHit>(m_storeTrueHitsName));
148 B2DEBUG(20, " --> MCSimHitRel: " << m_relMCParticleSimHitName);
149 B2DEBUG(20, " --> DigitMCRel: " << m_relDigitMCParticleName);
150 B2DEBUG(20, " --> TrueSimRel: " << m_relTrueHitSimHitName);
151 B2DEBUG(20, " --> DigitTrueRel: " << m_relDigitTrueHitName);
152 B2DEBUG(20, " --> PoissonSmearing: " << (m_applyPoisson ? "true" : "false"));
153 B2DEBUG(20, " --> +IntegrationWindow: " << (m_applyWindow ? "true" : "false") << ", size defined in xml");
154 B2DEBUG(20, " --> SegmentLength: " << m_segmentLength << " cm");
155 B2DEBUG(20, " --> ElectronGroupSize: " << m_elGroupSize << " e-");
156 B2DEBUG(20, " --> ElectronStepTime: " << m_elStepTime << " ns");
157 B2DEBUG(20, " --> ElectronMaxSteps: " << m_elMaxSteps);
158 B2DEBUG(20, " --> ADU unit: " << m_eToADU << " e-/ADU");
159}
160
162{
163 //Fill map with all possible sensors This is too slow to be done every event so
164 //we fill it once and only clear the content of the sensors per event, not
165 //the whole map.
166 // NOTE: Some VXDIDs will be added to the map on the way if we have multiple
167 // frames, but they will stay and will be cleared appropriately, so this is not
168 // a problem, and after a few events the performance will stabilize.
169 m_sensors.clear();
171 for (VxdID layer : geo.getLayers(SensorInfo::PXD)) {
172 for (VxdID ladder : geo.getLadders(layer)) {
173 for (VxdID sensor : geo.getSensors(ladder)) {
174 m_sensors[sensor] = Sensor();
175 }
176 }
177 }
178}
179
181{
182
183 //Check for injection vetos
184 if (m_storePXDTiming.isValid()) {
185 m_gated = (*m_storePXDTiming).isGated();
186 m_triggerGate = (*m_storePXDTiming).getTriggerGate();
187 m_gatingStartTimes = (*m_storePXDTiming).getGatingStartTimes();
189
190 B2DEBUG(20, "Reading from PXDInjectionBGTiming: Event has TriggerGate " << m_triggerGate << " and is gated " << m_gated);
191
193 for (auto gatingStartTime : m_gatingStartTimes) {
194 B2DEBUG(20, "Gating start time " << gatingStartTime << "ns ");
195
196 // Gated readout can only come from gating in the time period from t=0us to t=20us.
197 if (gatingStartTime >= 0) {
198 // Compute the gate where gating started. Note the wrap around of the rolling shutter
199 int firstGated = (m_triggerGate + int(gatingStartTime / m_timePerGate)) % m_nGates ;
200 // Compute the gate where gating stopped. Note the wrap around of the rolling shutter
201 int lastGated = (m_triggerGate + int((gatingStartTime + m_gatingWithoutReadoutTime) / m_timePerGate)) % m_nGates ;
202
203 if (lastGated >= firstGated) {
204 // Gated channels in the same frame
205 B2DEBUG(20, "Gated channel interval from " << firstGated << " to " << lastGated);
206 m_gatedChannelIntervals.push_back(pair<int, int>(firstGated, lastGated));
207 } else {
208 // Gated channels in two consecutive frames
209 B2DEBUG(20, "Gated channel interval from " << firstGated << " to " << m_nGates);
210 B2DEBUG(20, "Gated channel interval from " << 0 << " to " << lastGated);
211 m_gatedChannelIntervals.push_back(pair<int, int>(firstGated, m_nGates));
212 m_gatedChannelIntervals.push_back(pair<int, int>(0, lastGated));
213 }
214 }
215 }
216 }
217 } else {
218 m_gated = false;
219 m_triggerGate = gRandom->Integer(m_nGates);
220 m_gatingStartTimes.clear();
222 }
223
224 //Clear sensors and process SimHits
225 for (Sensors::value_type& sensor : m_sensors) {
226 sensor.second.clear();
227 }
228 m_currentSensor = 0;
230 //Clear return value
232
236
237 RelationArray mcParticlesToSimHits(storeMCParticles, storeSimHits,
239 RelationArray mcParticlesToTrueHits(storeMCParticles, storeTrueHits); // not used here
240 RelationArray trueHitsToSimHits(storeTrueHits, storeSimHits,
242
244 storeDigits.clear();
245
246 RelationArray relDigitMCParticle(storeDigits, storeMCParticles,
248 relDigitMCParticle.clear();
249
250 RelationArray relDigitTrueHit(storeDigits, storeTrueHits,
252 relDigitTrueHit.clear();
253
254 unsigned int nSimHits = storeSimHits.getEntries();
255 if (nSimHits == 0)
256 return;
257
258 RelationIndex<MCParticle, PXDSimHit> relMCParticleSimHit(storeMCParticles,
259 storeSimHits, m_relMCParticleSimHitName);
260 RelationIndex<PXDTrueHit, PXDSimHit> relTrueHitSimHit(storeTrueHits,
261 storeSimHits, m_relTrueHitSimHitName);
262
263 //Check sensor info and set pointers to current sensor
264 for (unsigned int i = 0; i < nSimHits; ++i) {
265 m_currentHit = storeSimHits[i];
266 if (!m_currentHit->getElectrons()) continue;
268 relMCParticleSimHit.getFirstElementTo(m_currentHit);
269 if (mcRel) {
271 if (mcRel->weight < 0) {
272 //This simhit is from a particle which was not saved by the simulation
273 //so we do not take it into account for relations. Otherwise we might
274 //end up adding positive and negative weights together
276 }
277 } else {
278 // Don't warn if this is a background SimHit
280 B2WARNING(
281 "Could not find MCParticle which produced PXDSimhit " << i);
283 }
285 relTrueHitSimHit.getFirstElementTo(m_currentHit);
286 //We only care about true hits from particles which have not been ignored
287 if (trueRel && trueRel->weight > 0) {
288 m_currentTrueHit = trueRel->indexFrom;
289 } else {
290 m_currentTrueHit = -1;
291 }
292
293 VxdID sensorID = m_currentHit->getSensorID();
294 if (!m_currentSensorInfo || sensorID != m_currentSensorInfo->getID()) {
295 m_currentSensorInfo = dynamic_cast<const SensorInfo*>(&VXD::GeoCache::getInstance().getSensorInfo(sensorID));
297 B2FATAL(
298 "SensorInformation for Sensor " << sensorID << " not found, make sure that the geometry is set up correctly");
299 m_currentSensor = &m_sensors[sensorID];
300 B2DEBUG(20, "Sensor Parameters for Sensor " << sensorID << ": " << endl
301 << " --> Width: " << m_currentSensorInfo->getWidth() << endl
302 << " --> Length: " << m_currentSensorInfo->getLength() << endl
303 << " --> uPitch: " << m_currentSensorInfo->getUPitch() << endl
304 << " --> vPitch " << m_currentSensorInfo->getVPitch(-m_currentSensorInfo->getLength() / 2.0)
305 << ", " << m_currentSensorInfo->getVPitch(m_currentSensorInfo->getLength() / 2.0) << endl
306 << " --> Thickness: " << m_currentSensorInfo->getThickness() << endl
307 << " --> BulkDoping: " << m_currentSensorInfo->getBulkDoping() << endl
308 << " --> BackVoltage: " << m_currentSensorInfo->getBackVoltage() << endl
309 << " --> TopVoltage: " << m_currentSensorInfo->getTopVoltage() << endl
310 << " --> SourceBorder: " << m_currentSensorInfo->getSourceBorder(-0.4 * m_currentSensorInfo->getLength())
312 << " --> ClearBorder: " << m_currentSensorInfo->getClearBorder(-0.4 * m_currentSensorInfo->getLength())
314 << " --> DrainBorder: " << m_currentSensorInfo->getDrainBorder(-0.4 * m_currentSensorInfo->getLength())
316 << " --> GateDepth: " << m_currentSensorInfo->getGateDepth() << endl
317 << " --> DoublePixel: " << m_currentSensorInfo->getDoublePixel() << endl);
318
319 }
320 B2DEBUG(10,
321 "Processing hit " << i << " in Sensor " << sensorID << ", related to MCParticle " << m_currentParticle);
322 processHit();
323 }
324
326 saveDigits();
327 //Return number of created digits
328 setReturnValue(storeDigits.getEntries());
329}
330
332{
333 if (m_applyWindow) {
334 //Ignore a hit which is outside of the active frame time of the hit gate
335 float currentHitTime = m_currentHit->getGlobalTime();
336
337 // First we have to now the current hit gate
338 const ROOT::Math::XYZVector startPoint = m_currentHit->getPosIn();
339 const ROOT::Math::XYZVector stopPoint = m_currentHit->getPosOut();
340 auto row = m_currentSensorInfo->getVCellID(0.5 * (stopPoint.Y() + startPoint.Y()));
341
343 row = 767 - row;
344 int gate = row / 4;
345
346 // Compute the distance in unit of gates to the trigger gate. Do it in
347 // direction of PXD rolling shutter.
348 int distanceToTriggerGate = 0;
349 if (gate >= m_triggerGate) distanceToTriggerGate = gate - m_triggerGate;
350 else distanceToTriggerGate = 192 - m_triggerGate + gate;
351
352 // The triggergate is switched ON at t0=0ns. Compute the integration time window for the current hit gate.
353 // Time intervals of subsequent readout gates are shifted by timePerGate.
354 float gateMinTime = -m_pxdIntegrationTime + m_timePerGate + m_hwdelay + distanceToTriggerGate * m_timePerGate ;
355 float gateMaxTime = gateMinTime + m_pxdIntegrationTime;
356
357 B2DEBUG(30,
358 "Checking if hit is in timeframe " << gateMinTime << " <= " << currentHitTime <<
359 " <= " << gateMaxTime);
360
361 if (currentHitTime
362 < gateMinTime
363 || currentHitTime
364 > gateMaxTime)
365 return;
366
367 if (m_gated) {
368 //Ignore simHits when the PXD is gated, i.e. PXD does not collect any charge.
369 for (auto gatingStartTime : m_gatingStartTimes) {
370 B2DEBUG(30,
371 "Checking if hit is in gated timeframe " << gatingStartTime << " <= " << currentHitTime <<
372 " <= " << gatingStartTime + m_gatingTime);
373
374 if (currentHitTime
375 > gatingStartTime
376 && currentHitTime
377 < gatingStartTime + m_gatingTime)
378 return;
379 }
380 }
381 }
382
383 //Get step length and direction
384 const ROOT::Math::XYZVector startPoint = m_currentHit->getPosIn();
385 ROOT::Math::XYZVector stopPoint = m_currentHit->getPosOut();
386 double dx = stopPoint.X() - startPoint.X();
387 double dy = stopPoint.Y() - startPoint.Y();
388 double dz = stopPoint.Z() - startPoint.Z();
389 double trackLength2 = dx * dx + dy * dy + dz * dz;
390
391 // Set magnetic field to save calls to getBField()
392 m_currentBField = m_currentSensorInfo->getBField(0.5 * (startPoint + stopPoint));
393
394 if (m_currentHit->getPDGcode() == Const::photon.getPDGCode() || trackLength2 <= 0.01 * Unit::um * Unit::um) {
395 //Photons deposit the energy at the end of their step
397 } else {
398 //Otherwise, split into segments of (default) max. 5µm and
399 //drift the charges from the center of each segment
401 double lastFraction {0};
402 double lastElectrons {0};
403
404 for (auto& segment : segments) {
405 //Simhit returns step fraction and cumulative electrons. We want the
406 //center of these steps and electrons in this step
407 const double f = (segment.first + lastFraction) * 0.5;
408 const double e = segment.second - lastElectrons;
409 //Update last values
410 std::tie(lastFraction, lastElectrons) = segment;
411
412 //And drift charge from that position
413 stopPoint.SetXYZ(startPoint.X() + f * dx, startPoint.Y() + f * dy, startPoint.Z() + f * dz);
414 driftCharge(stopPoint, e);
415 }
416 }
417}
418
419inline double pol3(double x, const double* c)
420{
421 return c[0] + x * (c[1] + x * (c[2] + x * c[3]));
422};
423
424void PXDDigitizerModule::driftCharge(const ROOT::Math::XYZVector& r, double electrons)
425{
426 //Get references to current sensor/info for ease of use
427 const SensorInfo& info = *m_currentSensorInfo;
428 Sensor& sensor = *m_currentSensor;
429
430 static const double cx[] = {0, 2.611995e-01, -1.948316e+01, 9.167064e+02};
431 static const double cu[] = {4.223817e-04, -1.041434e-03, 5.139596e-02, -1.180229e+00};
432 static const double cv[] = {4.085681e-04, -8.615459e-04, 5.706439e-02, -1.774319e+00};
433 static const double ct[] = {2.823743e-04, -1.138627e-06, 4.310888e-09, -1.559542e-11}; // temp range [250, 350] degrees with m_elStepTime = 1 ns
434
435 double dz = 0.5 * info.getThickness() - info.getGateDepth() - r.Z(), adz = fabs(dz);
436
437 double dx = fabs(m_currentBField.Y()) > Unit::T ? copysign(pol3(adz, cx),
438 dz) : 0; // two configurations: with default B field (B~1.5T) and B=0T
439 double sigmaDrift_u = pol3(adz, cu);
440 double sigmaDrift_v = pol3(adz, cv);
441 double sigmaDiffus = pol3(info.getTemperature() - 300.0,
442 ct); // sqrt(2 * Const::uTherm * info.getElectronMobility(0) * m_elStepTime);
443
444 int nGroups = (int)(electrons / m_elGroupSize) + 1;
445 double groupCharge = electrons / nGroups;
446 while (nGroups--) {
447 double du = gRandom->Gaus(0.0, sigmaDrift_u), dv = gRandom->Gaus(0.0, sigmaDrift_v);
448 double uPos = r.X() + du + dx;
449 double vPos = r.Y() + dv;
450 int step = 0;
451 for (; step < m_elMaxSteps; ++step) {
452 int id = info.getTrappedID(uPos, vPos);
453 //Check if cloud inside of IG region
454 if (id >= 0) {
455 // Trapped in the internal gate region
456 sensor[Digit(id % 250, id / 250)].add(groupCharge, m_currentParticle, m_currentTrueHit);
457 break;
458 }
459 //Random walk with drift
460 dv = gRandom->Gaus(0.0, sigmaDiffus), du = gRandom->Gaus(0.0, sigmaDiffus);
461 uPos += du;
462 vPos += dv;
463 }
464 if (step == m_elMaxSteps) {
465 // cloud is not trapped but save it anyway into the closest pixel
466 int iu = info.getUCellID(uPos, vPos, 1), iv = info.getVCellID(vPos, 1);
467 sensor[Digit(iu, iv)].add(groupCharge, m_currentParticle, m_currentTrueHit);
468 }
469 }
470}
471
472
473double PXDDigitizerModule::addNoise(double charge)
474{
475 if (charge <= 0) {
476 //Noise Pixel, add chargeThreshold electrons;
477 charge = 1.1 * m_chargeThresholdElectrons;
478 } else {
479 if (m_applyPoisson) {
480 // For big charge assume Gaussian distr.
481 if (charge > (1000. * Unit::e))
482 charge = gRandom->Gaus(charge, sqrt(charge));
483 else
484 // Otherwise Poisson distr.
485 charge = gRandom->Poisson(charge);
486 }
487 if (m_applyNoise) {
488 charge += gRandom->Gaus(0., m_elNoise);
489 }
490 }
491 return charge;
492}
493
495{
496 if (!m_applyNoise)
497 return;
498
499 for (Sensors::value_type& sensor : m_sensors) {
500 Sensor& s = sensor.second;
501
502 //Calculate the number of pixels on an empty sensor which will exceed the noise cut
503 const SensorInfo& info =
504 dynamic_cast<const SensorInfo&>(VXD::GeoCache::getInstance().getSensorInfo(sensor.first));
505 int nU = info.getUCells();
506 int nV = info.getVCells();
507 int nPixels = gRandom->Poisson(info.getNoiseFraction() * nU * nV);
508
509 // Existing digits will get noise in PXDDIgitizer::AddNoise.
510 // Here we add zero charge to nPixels digits.
511 // In part, this will create some new zero-charge digits.
512 // If we happen to select an existing (fired) digit, it remains unchanged.
513 for (int i = 0; i < nPixels; ++i) {
514 Digit d(gRandom->Integer(nU), gRandom->Integer(nV));
515 s[d].add(0.0);
516 }
517 }
518}
519
521{
522 return std::any_of(m_gatedChannelIntervals.begin(), m_gatedChannelIntervals.end(),
523 [gate](auto interval) {return gate >= interval.first && gate < interval.second;});
524}
525
527{
531 RelationArray relDigitMCParticle(storeDigits, storeMCParticles,
533 RelationArray relDigitTrueHit(storeDigits, storeTrueHits,
535
536
537 for (Sensors::value_type& sensor : m_sensors) {
538 auto sensorID = sensor.first;
539 const SensorInfo& info =
540 dynamic_cast<const SensorInfo&>(VXD::GeoCache::getInstance().getSensorInfo(sensorID));
541 m_chargeThreshold = info.getChargeThreshold();
543 for (Sensor::value_type& digitAndValue : sensor.second) {
544 const Digit& d = digitAndValue.first;
545 const DigitValue& v = digitAndValue.second;
546
547 //Add Noise where applicable
548 double charge = addNoise(v.charge());
549
550 // Draw a pedestal value
551 double pedestal = std::max(gRandom->Gaus(m_pedestalMean, m_pedestalRMS), 0.0);
552
553 // Get gain correction
554 double gain = PXDGainCalibrator::getInstance().getGainCorrection(sensorID, d.u(), d.v());
555
556 // Add pedestal to charge
557 charge = round(charge * gain / m_eToADU + pedestal);
558
559 // Clipping of ADC codes at 255
560 charge = std::min(charge, 255.0);
561
562 // Subtraction of integer pedestal in DHP
563 charge = charge - round(pedestal);
564
565 // Zero Suppression in DHP
566 if (charge <= m_chargeThreshold)
567 continue;
568
569 // Check if the readout digits is coming from a gated row
571 int row = d.v();
572 if (sensorID.getLayerNumber() == 1)
573 row = 767 - row;
574 int gate = row / 4;
575 if (checkIfGated(gate)) continue;
576 }
577
578 // Check if the readout digit is coming from a masked or dead area
579 if (PXD::PXDPixelMasker::getInstance().pixelDead(sensorID, d.u(), d.v())
580 || !PXD::PXDPixelMasker::getInstance().pixelOK(sensorID, d.u(), d.v())) {
581 continue;
582 }
583
584 //Add the digit to datastore
585 int digIndex = storeDigits.getEntries();
586 storeDigits.appendNew(
587 PXDDigit(sensorID, d.u(), d.v(), charge));
588
589 //If the digit has any relations to MCParticles, add the Relation
590 if (v.particles().size() > 0) {
591 relDigitMCParticle.add(digIndex, v.particles().begin(),
592 v.particles().end());
593 }
594 //If the digit has any truehits to TrueHit, add the Relation
595 if (v.truehits().size() > 0) {
596 relDigitTrueHit.add(digIndex, v.truehits().begin(),
597 v.truehits().end());
598 }
599 }
600 }
601}
602
603
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleType photon
photon particle
Definition: Const.h:673
static std::string relationName(const std::string &fromName, const std::string &toName, std::string const &namedRelation="")
Return storage name for a relation between two arrays of the given names.
Definition: DataStore.h:180
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition: Module.cc:220
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
The PXD digit class.
Definition: PXDDigit.h:27
Class representing the charge and particle contributions for one pixel.
const relations_map & truehits() const
Return the map containing all truehit contributions to the pixel charge.
const relations_map & particles() const
Return the map containing all particle contributions to the pixel charge.
double charge() const
Return the charge collected in the pixel.
Class to represent the coordinates of one pixel.
double m_pedestalRMS
RMS pedestal in ADU.
void processHit()
Process one PXDSimHit by dividing the step in smaller steps and drifting the charge.
double m_pxdIntegrationTime
Integration time for each gate of the PXD in ns.
double m_pedestalMean
Mean pedestal in ADU.
bool m_gatingWithoutReadout
Digits from gated rows not sent to DHH.
void initialize() override final
Initialize the module and check the parameters.
std::string m_relTrueHitSimHitName
Name of the relation between PXDTrueHits and PXDSimHits.
void saveDigits()
Save all digits to the datastore.
int m_currentParticle
Index of the particle which caused the current hit.
double m_ADCUnit
Slope of the linear ADC transfer curve in nA/ADU.
Sensors m_sensors
Structure containing all existing sensors.
double m_elStepTime
Timeframe for one random walk step.
std::string m_relDigitMCParticleName
Name of the relation between PXDDigits and MCParticles.
int m_elMaxSteps
Maximum number of random walks before abort.
bool m_applyWindow
Wether or not to apply a time window cut.
std::string m_storeTrueHitsName
Name of the collection for the PXDTrueHits.
double m_timePerGate
Time needed to sample and clear a readout gate
double m_gatingWithoutReadoutTime
Time window during which digits from gated rows are not sent to DHH.
void driftCharge(const ROOT::Math::XYZVector &position, double electrons)
Drift the charge inside the silicon.
const PXDSimHit * m_currentHit
Pointer to the PXDSimhit currently digitized.
std::vector< float > m_gatingStartTimes
Vector of start times for gating.
std::string m_storeMCParticlesName
Name of the collection for the MCParticles.
bool m_applyNoise
Wether or not to apply noise.
void addNoiseDigits()
Add pure noise digits to the Sensors.
void event() override final
Digitize one event.
int m_nGates
Number of readout gates (or total number of Switcher channels)
double m_chargeThreshold
Zero-suppression threshold in ADU.
bool m_applyPoisson
Wether or not to apply poission fluctuation of charge.
Sensor * m_currentSensor
Pointer to the sensor in which the current hit occured.
double m_chargeThresholdElectrons
... and its equivalent in electrons
std::vector< std::pair< int, int > > m_gatedChannelIntervals
Vector of gated readout channels
ROOT::Math::XYZVector m_currentBField
Current magnetic field.
double m_elNoise
Amount of noise to apply.
std::string m_storeDigitsName
Name of the collection for the PXDDigits.
const SensorInfo * m_currentSensorInfo
Pointer to the SensorInfo of the current sensor.
std::string m_relDigitTrueHitName
Name of the relation between PXDDigits and PXDTrueHits.
double m_gatingTime
Time window during which the PXD is not collecting charge.
void beginRun() override final
Initialize the list of existing PXD Sensors.
double m_eToADU
ENC equivalent of 1 ADU.
bool checkIfGated(int gate)
Check if gate was read while in gated mode.
double m_gq
g_q of a pixel in nA/electrons.
StoreObjPtr< PXDInjectionBGTiming > m_storePXDTiming
Input array for timings.
double m_hwdelay
Hardware delay between time of bunch crossing and switching on triggergate in ns.
int m_elGroupSize
Max number of electrons per random walk.
int m_currentTrueHit
Index of the TrueHit the current hit belongs to.
std::string m_relMCParticleSimHitName
Name of the relation between MCParticles and PXDSimHits.
double addNoise(double charge)
Calculate the noise contribution to one pixel with given charge.
std::string m_storeSimHitsName
Name of the collection for the PXDSimhits.
float getGainCorrection(VxdID id, unsigned int uid, unsigned int vid) const
Get gain correction.
static PXDGainCalibrator & getInstance()
Main (and only) way to access the PXDGainCalibrator.
bool pixelOK(VxdID id, unsigned int uid, unsigned int vid) const
Check whether a pixel on a given sensor is OK or not.
static PXDPixelMasker & getInstance()
Main (and only) way to access the PXDPixelMasker.
Specific implementation of SensorInfo for PXD Sensors which provides additional pixel specific inform...
Definition: SensorInfo.h:23
double getTopVoltage() const
Return the voltage at the top of the sensor.
Definition: SensorInfo.h:101
double getGateDepth() const
Return the gate depth for the sensor.
Definition: SensorInfo.h:123
double getSourceBorder(double v) const
Return the distance between the source side of the pixel and the start of the Gate for a pixel at v.
Definition: SensorInfo.h:105
double getDrainBorder(double v) const
Return the distance between the drain side of the pixel and the start of the Gate for a pixel at v.
Definition: SensorInfo.h:117
double getBulkDoping() const
Return the bulk doping of the Silicon sensor.
Definition: SensorInfo.h:97
bool getDoublePixel() const
Return true if the Sensor is a double pixel structure: every other pixel is mirrored along v.
Definition: SensorInfo.h:125
double getClearBorder(double v) const
Return the distance between the clear side of the pixel and the start of the Gate for a pixel at v.
Definition: SensorInfo.h:111
const ROOT::Math::XYZVector getBField(const ROOT::Math::XYZVector &point) const
Get B field value from the field map.
Definition: SensorInfo.cc:45
double getBackVoltage() const
Return the voltage at the backside of the sensor.
Definition: SensorInfo.h:99
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
void clear() override
Clear all elements from the relation.
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:76
const Element * getFirstElementTo(const TO &to) const
Return a pointer to the first relation Element of the given object.
virtual unsigned short getBackgroundTag() const
Get background tag.
Definition: SimHitBase.h:46
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
void clear() override
Delete all entries in this array.
Definition: StoreArray.h:207
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
static const double mm
[millimeters]
Definition: Unit.h:70
static const double e
Standard of [electric charge].
Definition: Unit.h:53
static const double um
[micrometers]
Definition: Unit.h:71
static const double ns
Standard of [time].
Definition: Unit.h:48
static const double T
[tesla]
Definition: Unit.h:120
float getGlobalTime() const override
Return the time of the electron deposition.
Definition: VXDSimHit.h:78
int getPDGcode() const
Return the PDG code of the particle causing the electron deposition.
Definition: VXDSimHit.h:68
ROOT::Math::XYZVector getPosOut() const
Return the end point of the electron deposition in local coordinates.
Definition: VXDSimHit.h:72
std::vector< std::pair< float, float > > getElectronsConstantDistance(double length) const
Get the electron deposition along constant stepsize.
Definition: VXDSimhit.cc:32
float getElectrons() const
Return the number of created electrons.
Definition: VXDSimhit.cc:15
ROOT::Math::XYZVector getPosIn() const
Return the start point of the electron deposition in local coordinates.
Definition: VXDSimHit.h:70
VxdID getSensorID() const
Return the sensorID of the sensor the electron was deposited in.
Definition: VXDSimHit.h:66
Class to faciliate easy access to sensor information of the VXD like coordinate transformations or pi...
Definition: GeoCache.h:39
const std::set< Belle2::VxdID > getLayers(SensorInfoBase::SensorType sensortype=SensorInfoBase::VXD)
Return a set of all known Layers.
Definition: GeoCache.cc:176
const SensorInfoBase & getSensorInfo(Belle2::VxdID id) const
Return a referecne to the SensorInfo of a given SensorID.
Definition: GeoCache.cc:67
const std::set< Belle2::VxdID > & getSensors(Belle2::VxdID ladder) const
Return a set of all sensor IDs belonging to a given ladder.
Definition: GeoCache.cc:204
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition: GeoCache.cc:214
const GeoTools * getGeoTools()
Return a raw pointer to a GeoTools object.
Definition: GeoCache.h:142
const std::set< Belle2::VxdID > & getLadders(Belle2::VxdID layer) const
Return a set of all ladder IDs belonging to a given layer.
Definition: GeoCache.cc:193
double getUPitch(double v=0) const
Return the pitch of the sensor.
double getWidth(double v=0) const
Return the width of the sensor.
VxdID getID() const
Return the ID of the Sensor.
double getVPitch(double v=0) const
Return the pitch of the sensor.
double getThickness() const
Return the thickness of the sensor.
int getVCellID(double v, bool clamp=false) const
Return the corresponding pixel/strip ID of a given v coordinate.
double getLength() const
Return the length of the sensor.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
baseType getLayerNumber() const
Get the layer id.
Definition: VxdID.h:96
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Namespace to encapsulate code needed for simulation and reconstrucion of the PXD.
std::map< Digit, DigitValue > Sensor
Map of all hits in one Sensor.
Abstract base class for different kinds of events.
STL namespace.
RelationElement::index_type indexFrom
index of the element from which the relation points.
RelationElement::weight_type weight
weight of the relation.