Belle II Software  release-08-01-10
SVDDigitizerModule.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 <svd/modules/svdSimulation/SVDDigitizerModule.h>
10 #include <vxd/geometry/GeoCache.h>
11 
12 #include <framework/dataobjects/EventMetaData.h>
13 #include <framework/logging/Logger.h>
14 #include <framework/gearbox/Unit.h>
15 #include <framework/gearbox/Const.h>
16 #include <framework/datastore/DataStore.h>
17 #include <framework/datastore/StoreArray.h>
18 #include <framework/datastore/StoreObjPtr.h>
19 #include <framework/datastore/RelationArray.h>
20 #include <framework/datastore/RelationIndex.h>
21 #include <mdst/dataobjects/MCParticle.h>
22 #include <svd/dataobjects/SVDTrueHit.h>
23 #include <svd/dataobjects/SVDShaperDigit.h>
24 #include <svd/dataobjects/SVDEventInfo.h>
25 #include <fstream>
26 #include <sstream>
27 #include <regex>
28 #include <algorithm>
29 #include <deque>
30 #include <cmath>
31 #include <root/TMath.h>
32 #include <root/TRandom.h>
33 
34 using namespace std;
35 using namespace Belle2;
36 using namespace Belle2::SVD;
37 
38 //-----------------------------------------------------------------
39 // Auxiliaries for waveform storage
40 //-----------------------------------------------------------------
41 // FIXME: I believe this is wrong, these things must be created separately for
42 // each instance of the digitizer, otherwise it can crash in parallel mode.
43 int tree_vxdID = 0; // VXD ID of a sensor
44 int tree_uv = 0; // U or V coordinate
45 int tree_strip = 0; // number of strip
46 double tree_signal[20]; // array for 20 samples of 10 ns
47 
48 //-----------------------------------------------------------------
49 // Register the Module
50 //-----------------------------------------------------------------
51 REG_MODULE(SVDDigitizer);
52 
53 //-----------------------------------------------------------------
54 // Implementation
55 //-----------------------------------------------------------------
56 
57 std::string Belle2::SVD::SVDDigitizerModule::m_xmlFileName = std::string("SVDChannelMapping.xml");
58 SVDDigitizerModule::SVDDigitizerModule() : Module(),
59  m_currentSensorWaveforms(nullptr),
60  m_mapping(m_xmlFileName)
61 {
62  //Set module properties
63  setDescription("Creates SVDShaperDigits from SVDSimHits");
65 
66  // Define module parameters
67 
68  // 1. Collections
69  addParam("MCParticles", m_storeMCParticlesName,
70  "MCParticle collection name", m_storeMCParticlesName);
71  addParam("SimHits", m_storeSimHitsName, "SimHit collection name",
73  addParam("TrueHits", m_storeTrueHitsName, "TrueHit collection name",
75  addParam("ShaperDigits", m_storeShaperDigitsName, "ShaperDigits collection name", m_storeShaperDigitsName);
76  addParam("SVDEventInfo", m_svdEventInfoName, "SVDEventInfo name", m_svdEventInfoName);
77 
78  // 2. Physics
79  addParam("SegmentLength", m_segmentLength,
80  "Maximum segment length (in millimeters)", m_segmentLength);
81 
82  // 3. Noise
83  addParam("PoissonSmearing", m_applyPoisson,
84  "Apply Poisson smearing on chargelets", m_applyPoisson);
85  addParam("ZeroSuppressionCut", m_SNAdjacent,
86  "Zero suppression cut in sigmas of strip noise", m_SNAdjacent);
87  addParam("FADCmode", m_roundZS,
88  "FADC mode: if True, ZS cut is rounded to nearest ADU ", m_roundZS);
89  addParam("numberOfSamples", m_nSamplesOverZS,
90  "Keep digit if numberOfSamples or more samples are over ZS threshold",
92 
93  // 4. Timing
94  addParam("BetaPrimeDecayTimeU", m_betaPrimeDecayTimeU, "Decay time of betaprime waveform in ns, U-side",
96  addParam("BetaPrimeDecayTimeV", m_betaPrimeDecayTimeV, "Decay time of betaprime waveform in ns, V-side",
98  addParam("ADCSamplingTime", m_samplingTime,
99  "Interval between ADC samples in ns, if = -1 taken from HardwareClockSettings payload (default).", m_samplingTime);
100  addParam("StartSampling", m_startSampling,
101  "Start of the sampling window, in ns. Used to tune the SVD latency.", m_startSampling);
102  addParam("RandomizeEventTimes", m_randomizeEventTimes,
103  "Randomize event times over a frame interval", m_randomizeEventTimes);
104  addParam("TimeFrameLow", m_minTimeFrame,
105  "Left edge of event time randomization window, ns", m_minTimeFrame);
106  addParam("TimeFrameHigh", m_maxTimeFrame,
107  "Right edge of event time randomization window, ns", m_maxTimeFrame);
108 
109 
110  // 6. Reporting
111  addParam("statisticsFilename", m_rootFilename,
112  "ROOT Filename for statistics generation. If filename is empty, no statistics will be produced",
114  addParam("storeWaveforms", m_storeWaveforms,
115  "Store waveforms in a TTree in the statistics file.", m_storeWaveforms);
116  addParam("signalsList", m_signalsList,
117  "Store signals (time/charge/tau) in a tab-delimited file",
118  m_signalsList);
119 }
120 
122 {
123 
124  //Register all required collections
126 
128 
130  storeShaperDigits.registerInDataStore();
131  storeShaperDigits.registerRelationTo(storeMCParticles);
132  storeShaperDigits.registerRelationTo(storeTrueHits);
133 
135  DataStore::arrayName<SVDShaperDigit>(m_storeShaperDigitsName),
136  DataStore::arrayName<MCParticle>(m_storeMCParticlesName));
138  DataStore::arrayName<SVDShaperDigit>(m_storeShaperDigitsName),
139  DataStore::arrayName<SVDTrueHit>(m_storeTrueHitsName));
140 
142  StoreObjPtr<EventMetaData> storeEvents;
143 
144  //Set names in case default was used. We need the names to initialize the RelationIndices.
146  DataStore::arrayName<MCParticle>(m_storeMCParticlesName),
147  DataStore::arrayName<SVDSimHit>(m_storeSimHitsName));
149  DataStore::arrayName<SVDTrueHit>(m_storeTrueHitsName),
150  DataStore::arrayName<SVDSimHit>(m_storeSimHitsName));
151 
152  // Convert parameters to correct units
154  m_noiseFraction = TMath::Freq(m_SNAdjacent); // 0.9... !
160 
161  B2DEBUG(29,
162  "SVDDigitizer parameters (in default system units, *=cannot be set directly):");
163  B2DEBUG(29, " DATASTORE COLLECTIONS:");
164  B2DEBUG(29,
165  " --> MCParticles: " << DataStore::arrayName<MCParticle>(m_storeMCParticlesName));
166  B2DEBUG(29,
167  " --> Digits: " << DataStore::arrayName<SVDShaperDigit>(m_storeShaperDigitsName));
168  B2DEBUG(29,
169  " --> SimHits: " << DataStore::arrayName<SVDSimHit>(m_storeSimHitsName));
170  B2DEBUG(29,
171  " --> TrueHits: " << DataStore::arrayName<SVDTrueHit>(m_storeTrueHitsName));
172  B2DEBUG(29, " --> MCSimHitRel: " << m_relMCParticleSimHitName);
173  B2DEBUG(29, " --> DigitMCRel: " << m_relShaperDigitMCParticleName);
174  B2DEBUG(29, " --> TrueSimRel: " << m_relTrueHitSimHitName);
175  B2DEBUG(29, " --> DigitTrueRel: " << m_relShaperDigitTrueHitName);
176  B2DEBUG(29, " PHYSICS: ");
177  B2DEBUG(29, " --> SegmentLength: " << m_segmentLength);
178  B2DEBUG(29, " NOISE: ");
179  B2DEBUG(29, " --> Add Poisson noise " << (m_applyPoisson ? "true" : "false"));
180  B2DEBUG(29, " --> Zero suppression cut" << m_SNAdjacent);
181  B2DEBUG(29, " --> Round ZS cut: " << (m_roundZS ? "true" : "false"));
182  B2DEBUG(29, " --> Samples over ZS cut:" << m_nSamplesOverZS);
183  B2DEBUG(29, " --> Noise fraction*: " << 1.0 - m_noiseFraction);
184  B2DEBUG(29, " TIMING: ");
185  B2DEBUG(29, " --> Sampling time: " << m_samplingTime);
186  B2DEBUG(29, " --> Start of int. wind.:" << m_startSampling);
187  B2DEBUG(29, " --> Random event times. " << (m_randomizeEventTimes ? "true" : "false"));
188  B2DEBUG(29, " REPORTING: ");
189  B2DEBUG(29, " --> statisticsFilename: " << m_rootFilename);
190  B2DEBUG(29,
191  " --> storeWaveforms: " << (m_storeWaveforms ? "true" : "false"));
192 
193  if (!m_rootFilename.empty()) {
194  m_rootFile = new TFile(m_rootFilename.c_str(), "RECREATE");
195  m_rootFile->cd();
196  m_histChargeSharing_v = new TH1D("h_Diffusion_v", " 'Diffusion' distance, v",
197  200, -500, 500);
198  m_histChargeSharing_v->GetXaxis()->SetTitle(" distance v [um]");
199  m_histChargeSharing_u = new TH1D("h_Diffusion_u",
200  " 'Diffusion' distance, u", 100, -200, 200);
201  m_histChargeSharing_u->GetXaxis()->SetTitle("distance u [um]");
202  m_histLorentz_u = new TH1D("h_LorentzAngle_u", "Lorentz angle, holes",
203  100, -0.08, 0);
204  m_histLorentz_u->GetXaxis()->SetTitle("Lorentz angle");
205  m_histLorentz_v = new TH1D("h_LorentzAngle_v",
206  "Lorentz angle, electrons", 100, -0.002, 0.002);
207  m_histLorentz_v->GetXaxis()->SetTitle("Lorentz angle");
208  m_signalDist_u = new TH1D("h_signalDist_u",
209  "Strip signals vs. TrueHits, holes", 100, -400, 400);
210  m_signalDist_u->GetXaxis()->SetTitle("U strip position - TrueHit u [um]");
211  m_signalDist_v = new TH1D("h_signalDist_v",
212  "Strip signals vs. TrueHits, electrons", 100, -400, 400);
213  m_signalDist_v->GetXaxis()->SetTitle("V strip position - TrueHit v [um]");
214 
215  m_histMobility_e = new TH1D("h_elecMobility", "electron Mobility",
216  30, 900, 1200);
217  m_histMobility_e->GetXaxis()->SetTitle("Electron Mobility");
218  m_histMobility_h = new TH1D("h_holeMobility", "hole Mobility",
219  30, 400, 500);
220  m_histMobility_h->GetXaxis()->SetTitle("Holes Mobility");
221 
222  m_histDistanceToPlane_e = new TH1D("h_elecDistToPlane", "electron Distance to Plane",
223  50, -0.05, 0.05);
224  m_histDistanceToPlane_e->GetXaxis()->SetTitle("Electron Distance To Plane [cm]");
225  m_histDistanceToPlane_h = new TH1D("h_holeDistToPlane", "holes Distance to Plane",
226  50, -0.05, 0.05);
227  m_histDistanceToPlane_h->GetXaxis()->SetTitle("Holes Distance To Plane [cm]");
228 
229  m_histVelocity_e = new TH1D("h_elecVelocity", "electrons Velocity (z)",
230  100, 0.001, 0.01);
231 
232  m_histVelocity_e->GetXaxis()->SetTitle("Electron Velocity [cm/s]");
233  m_histVelocity_h = new TH1D("h_holeVelocity", "holes Velocity (z)",
234  30, -0.002, -0.0004);
235  m_histVelocity_h->GetXaxis()->SetTitle("holes Velocity [cm/s]");
236 
237  m_histDriftTime_e = new TH1D("h_elecDriftTime", "electron Drift Time",
238  30, 0, 30);
239  m_histDriftTime_e->GetXaxis()->SetTitle("Electron Drift Time");
240  m_histDriftTime_h = new TH1D("h_holeDriftTime", "hole Drift Time",
241  30, 0, 30);
242  m_histDriftTime_h->GetXaxis()->SetTitle("Hole Drift Time");
243 
244  m_histHitTime = new TH1D("h_startAPVTime", "start APV Time",
245  200, -100, 100);
246  m_histHitTime->GetXaxis()->SetTitle("time (ns)");
247  m_histHitTimeTB = new TH2F("h_startAPVTimeTB", "start APV Time vs TB",
248  200, -100, 100, 4, -0.5, 3.5);
249  m_histHitTimeTB->GetXaxis()->SetTitle("time (ns)");
250  m_histHitTimeTB->GetYaxis()->SetTitle("TB");
251 
252  if (m_storeWaveforms) {
253  m_waveTree = new TTree("waveTree", "SVD waveforms");
254  m_waveTree->Branch("sensor", &tree_vxdID, "sensor/I");
255  m_waveTree->Branch("u_or_v", &tree_uv, "u_or_v/I");
256  m_waveTree->Branch("strip", &tree_strip, "strip/I");
257  m_waveTree->Branch("signal", tree_signal, "signal[20]/D");
258  }
259  } else {
260  // No waveforms can be stored if there is no statistics file.
261  m_storeWaveforms = false;
262  }
263 }
264 
266 {
267 
268  if (m_mapping.hasChanged()) { m_map = std::make_unique<SVDOnlineToOfflineMap>(m_mapping->getFileName()); }
269 
270  //read sampling time from HardwareClockSettings
271  if (m_samplingTime == -1 && m_hwClock.isValid())
272  m_samplingTime = 1. / m_hwClock->getClockFrequency(Const::EDetector::SVD, "sampling");
273  else if (m_samplingTime == -1)
274  m_samplingTime = 16000. / 509;
275 
276  //Fill map with all possible sensors This is too slow to be done every event so
277  //we fill it once and only clear the content of the sensors per event, not
278  //the whole map
279  m_waveforms.clear();
281  for (VxdID layer : geo.getLayers(SensorInfo::SVD)) {
282  for (VxdID ladder : geo.getLadders(layer)) {
283  for (VxdID sensor : geo.getSensors(ladder)) {
284  m_waveforms[sensor] = SensorWaveforms();
285  }
286  }
287  }
288 
289  if (!m_MaskedStr.isValid())
290  B2WARNING("No valid SVDFADCMaskedStrip for the requested IoV -> no strips masked");
291  if (!m_map)
292  B2WARNING("No valid channel mapping -> all APVs will be enabled");
293 
294 
295 }
296 
298 {
299 
300  //get number of samples and relativeShift
302  SVDModeByte modeByte = storeSVDEvtInfo->getModeByte();
303  m_relativeShift = storeSVDEvtInfo->getRelativeShift();
304  m_nAPV25Samples = storeSVDEvtInfo->getNSamples();
305 
306  //Compute time of the first sample, update latency
307  const double systemClockPeriod = 1. / m_hwClock->getGlobalClockFrequency();
308  int triggerBin = modeByte.getTriggerBin();
309 
310  m_initTime = m_startSampling - systemClockPeriod * triggerBin;
311 
312  m_is3sampleEvent = false;
313  if (m_nAPV25Samples == 3) {
314  m_is3sampleEvent = true;
316  B2DEBUG(25, "3-sample event, starting sample = " << m_startingSample);
317  } else m_startingSample = 0; //not used
318 
319  // set APV mode for background overlay
321 
322  // Generate current event time
323  if (m_randomizeEventTimes) {
324  StoreObjPtr<EventMetaData> storeEvent;
325  m_currentEventTime = gRandom->Uniform(m_minTimeFrame, m_maxTimeFrame);
326  // We have negative event times, so we have to encode!
327  storeEvent->setTime(static_cast<unsigned long>(1000 + m_currentEventTime));
328  } else
329  m_currentEventTime = 0.0;
330 
331  // Clear sensors' waveforms and process SimHits
332  for (Waveforms::value_type& sensorWaveforms : m_waveforms) {
333  sensorWaveforms.second.first.clear(); // u-side channels
334  sensorWaveforms.second.second.clear(); // v-side channels
335  }
336  // m_currentSensorWaveforms = 0;
337  // m_currentSensorInfo = 0;
338 
342 
343  RelationArray mcParticlesToSimHits(storeMCParticles, storeSimHits, m_relMCParticleSimHitName);
344  RelationArray trueHitsToSimHits(storeTrueHits, storeSimHits, m_relTrueHitSimHitName);
345 
346  RelationIndex<MCParticle, SVDSimHit> relMCParticleSimHit(storeMCParticles, storeSimHits, m_relMCParticleSimHitName);
347  RelationIndex<SVDTrueHit, SVDSimHit> relTrueHitSimHit(storeTrueHits, storeSimHits, m_relTrueHitSimHitName);
348 
349  unsigned int nSimHits = storeSimHits.getEntries();
350  if (nSimHits == 0) {
351  return;
352  }
353 
354  //Check sensor info and set pointers to current sensor
355  for (unsigned int i = 0; i < nSimHits; ++i) {
356  m_currentHit = storeSimHits[i];
358  relMCParticleSimHit.getFirstElementTo(m_currentHit);
359  if (mcRel) {
360  m_currentParticle = mcRel->indexFrom;
361  if (mcRel->weight < 0) {
362  //This simhit is from a particle which was not saved by the simulation
363  //so we do not take it into account for relations. Otherwise we might
364  //end up adding positive and negative weights together
365  m_currentParticle = -1;
366  }
367  } else {
368  // Don't bother with warnings for background SimHits
370  B2WARNING(
371  "Could not find MCParticle which produced SVDSimhit " << i);
372  m_currentParticle = -1;
373  }
375  relTrueHitSimHit.getFirstElementTo(m_currentHit);
376  //We only care about true hits from particles which have not been ignored
377  if (trueRel && trueRel->weight > 0) {
378  m_currentTrueHit = trueRel->indexFrom;
379  } else {
380  m_currentTrueHit = -1;
381  }
382 
383  VxdID sensorID = m_currentHit->getSensorID();
384  if (!m_currentSensorInfo || sensorID != m_currentSensorInfo->getID()) {
386  dynamic_cast<const SensorInfo*>(&VXD::GeoCache::get(sensorID));
387  if (!m_currentSensorInfo)
388  B2FATAL(
389  "Sensor Information for Sensor " << sensorID << " not found, make sure that the geometry is set up correctly");
390 
391  const SensorInfo& info = *m_currentSensorInfo;
392  // Publish some useful data
393  m_sensorThickness = info.getThickness();
395  B2DEBUG(29,
396  "Sensor Parameters for Sensor " << sensorID << ": " << endl
397  << " --> Width: " << m_currentSensorInfo->getWidth() << endl
398  << " --> Length: " << m_currentSensorInfo->getLength() << endl
399  << " --> uPitch: " << m_currentSensorInfo->getUPitch() << endl
400  << " --> vPitch: " << m_currentSensorInfo->getVPitch(-m_currentSensorInfo->getLength() / 2.0)
401  << ", " << m_currentSensorInfo->getVPitch(m_currentSensorInfo->getLength() / 2.0) << endl
402  << " --> Thickness: " << m_currentSensorInfo->getThickness() << endl
403  << " --> Deplet. voltage:" << m_currentSensorInfo->getDepletionVoltage() << endl
404  << " --> Bias voltage: " << m_currentSensorInfo->getBiasVoltage() << endl
405  );
406 
407  }
408  B2DEBUG(28,
409  "Processing hit " << i << " in Sensor " << sensorID << ", related to MCParticle " << m_currentParticle);
410  processHit();
411  }
412  // If storage of waveforms is required, store them in the statistics file.
413  if (m_storeWaveforms) {
414  m_rootFile->cd();
415  saveWaveforms();
416  }
417  if (m_signalsList != "")
418  saveSignals();
419 
420 
421  saveDigits();
422 
423 
424 
425 }
426 
428 {
429  // Set time of the hit
431 
432  //Get Steplength and direction
433  const ROOT::Math::XYZVector& startPoint = m_currentHit->getPosIn();
434  const ROOT::Math::XYZVector& stopPoint = m_currentHit->getPosOut();
435  ROOT::Math::XYZVector direction = stopPoint - startPoint;
436  double trackLength = direction.R();
437 
438  if (m_currentHit->getPDGcode() == Const::photon.getPDGCode() || trackLength < 0.1 * Unit::um) {
439  //Photons deposit energy at the end of their step
440  driftCharge(stopPoint, m_currentHit->getElectrons(), SVD::SensorInfo::electron);
442  } else {
443  //Otherwise, split into segments of (default) max. 5µm and
444  //drift the charges from the center of each segment
446  double lastFraction {0};
447  double lastElectrons {0};
448 
449  for (auto& segment : segments) {
450  //Simhit returns step fraction and cumulative electrons. We want the
451  //center of these steps and electrons in this step
452  const double f = (segment.first + lastFraction) / 2;
453  const double e = segment.second - lastElectrons;
454  //Update last values
455  std::tie(lastFraction, lastElectrons) = segment;
456 
457  //And drift charge from that position
458  const ROOT::Math::XYZVector position = startPoint + f * direction;
459  driftCharge(position, e, SVD::SensorInfo::electron);
460  driftCharge(position, e, SVD::SensorInfo::hole);
461  }
462  }
463 }
464 
465 
466 void SVDDigitizerModule::driftCharge(const ROOT::Math::XYZVector& position, double carriers,
467  SVD::SensorInfo::CarrierType carrierType)
468 {
469  bool have_electrons = (carrierType == SVD::SensorInfo::electron);
470 
471  string carrierName = (have_electrons) ? "electron" : "hole";
472  B2DEBUG(29,
473  "Drifting " << carriers << " " << carrierName << "s at position (" << position.X() << ", " << position.Y() << ", " << position.Z()
474  << ").");
475  B2DEBUG(29, "@@@ driftCharge: drifting " << carriers << " " << carrierName << "s at position (" << position.X() << ", " <<
476  position.Y() << ", " << position.Z()
477  << ").");
478 
479  // Get references to current sensor/info for ease of use
480  const SensorInfo& info = *m_currentSensorInfo;
481  StripWaveforms& waveforms = (!have_electrons) ? m_currentSensorWaveforms->first : m_currentSensorWaveforms->second;
482 
483  double distanceToPlane = (have_electrons) ?
484  0.5 * m_sensorThickness - position.Z() :
485  -0.5 * m_sensorThickness - position.Z(); //cm
486 
487  if (m_histDistanceToPlane_e && have_electrons) m_histDistanceToPlane_e->Fill(distanceToPlane);
488  if (m_histDistanceToPlane_h && !have_electrons) m_histDistanceToPlane_h->Fill(distanceToPlane);
489 
490  // Approximation: calculate drift velocity at the point halfway towards
491  // the respective sensor surface.
492  ROOT::Math::XYZVector mean_pos(position.X(), position.Y(), position.Z() + 0.5 * distanceToPlane);
493 
494  // Calculate drift times and widths of charge clouds.
495  ROOT::Math::XYZVector v = info.getVelocity(carrierType, mean_pos);
496  if (m_histVelocity_e && have_electrons) m_histVelocity_e->Fill(v.Z()); //Unit::cm/Unit::cm*Unit::eV/Unit::e*Unit::s);
497  if (m_histVelocity_h && !have_electrons) m_histVelocity_h->Fill(v.Z()); //Unit::cm/Unit::cm*Unit::eV/Unit::e*Unit::s);
498 
499  double driftTime = distanceToPlane / v.Z(); //ns
500  if (m_histDriftTime_e && have_electrons) m_histDriftTime_e->Fill(driftTime); //ns
501  if (m_histDriftTime_h && !have_electrons) m_histDriftTime_h->Fill(driftTime); //ns
502 
503  ROOT::Math::XYZVector center = position + driftTime * v; //cm
504  double mobility = (have_electrons) ?
505  info.getElectronMobility(info.getEField(mean_pos).R()) :
506  info.getHoleMobility(info.getEField(mean_pos).R());
507 
508  if (m_histMobility_e && have_electrons) m_histMobility_e->Fill(mobility); //cm2/V/ns
509  if (m_histMobility_h && !have_electrons) m_histMobility_h->Fill(mobility); //cm2/V/ns
510 
511  double D = Const::kBoltzmann * info.getTemperature() / Unit::e * mobility;
512  double sigma = std::max(1.0e-4, sqrt(2.0 * D * driftTime));
513  double tanLorentz = (!have_electrons) ? v.X() / v.Z() : v.Y() / v.Z();
514 
515  B2DEBUG(29, "velocity (" << v.X() / Unit::um << ", " << v.Y() / Unit::um << ", " << v.Z() / Unit::um << ") um/ns");
516  B2DEBUG(29, "D = " << D << ", driftTime = " << driftTime / Unit::ns << " ns");
517  B2DEBUG(29, "sigma = " << sigma / Unit::um << " um");
518  B2DEBUG(29, "tan Lorentz = " << tanLorentz);
519 
520  sigma *= sqrt(1.0 + tanLorentz * tanLorentz);
521  if (m_histLorentz_u && !have_electrons) m_histLorentz_u->Fill(tanLorentz);
522  if (m_histLorentz_v && have_electrons) m_histLorentz_v->Fill(tanLorentz);
523 
524  //Distribute carrier cloud on strips
525  int vID = info.getVCellID(center.Y(), true);
526  int uID = info.getUCellID(center.X(), center.Y(), true);
527  int seedStrip = (!have_electrons) ? uID : vID;
528  double seedPos = (!have_electrons) ?
529  info.getUCellPosition(seedStrip, vID) :
530  info.getVCellPosition(seedStrip);
531  double geomPitch = (!have_electrons) ? 0.5 * info.getUPitch(center.Y()) : 0.5 * info.getVPitch();
532  int nCells = (!have_electrons) ? info.getUCells() : info.getVCells();
533  std::deque<double> stripCharges;
534  std::deque<double> strips; // intermediate strips will be half-integers, like 2.5.
535 #define NORMAL_CDF(z) 0.5 * std::erfc( - (z) * 0.707107)
536  double current_pos = (!have_electrons) ? seedPos - center.X() : seedPos - center.Y();
537  double current_strip = seedStrip;
538  double cdf_low = NORMAL_CDF((current_pos - 0.5 * geomPitch) / sigma);
539  double cdf_high = NORMAL_CDF((current_pos + 0.5 * geomPitch) / sigma);
540  double charge = carriers * (cdf_high - cdf_low);
541 
542  B2DEBUG(29, "geomPitch = " << geomPitch / Unit::um << " um");
543  B2DEBUG(29, "charge = " << charge << " = " << carriers << "(carriers) * (" << cdf_high << "(cdf_high) - " << cdf_low <<
544  "(cdf_low));");
545 
546  stripCharges.push_back(charge);
547  strips.push_back(current_strip);
548  while (cdf_low > 1.0e-5) {
549  current_pos -= geomPitch;
550  current_strip -= 0.5;
551  double cdf_current = NORMAL_CDF((current_pos - 0.5 * geomPitch) / sigma);
552  charge = carriers * (cdf_low - cdf_current);
553  stripCharges.push_front(charge);
554  strips.push_front(current_strip);
555  cdf_low = cdf_current;
556  }
557  current_pos = (!have_electrons) ? seedPos - center.X() : seedPos - center.Y();
558  current_strip = seedStrip;
559  while (cdf_high < 1.0 - 1.0e-5) {
560  current_pos += geomPitch;
561  current_strip += 0.5;
562  double cdf_current = NORMAL_CDF((current_pos + 0.5 * geomPitch) / sigma);
563  charge = carriers * (cdf_current - cdf_high);
564  stripCharges.push_back(charge);
565  strips.push_back(current_strip);
566  cdf_high = cdf_current;
567  }
568 #undef NORMAL_CDF
569 
570  // Pad with zeros for smoothing
571  int npads = (strips.front() - floor(strips.front()) == 0) ? 5 : 4;
572  for (int i = 0; i < npads; ++i) {
573  strips.push_front(strips.front() - 0.5);
574  stripCharges.push_front(0);
575  }
576  npads = (strips.back() - floor(strips.back()) == 0) ? 5 : 4;
577  for (int i = 0; i < npads; ++i) {
578  strips.push_back(strips.back() + 0.5);
579  stripCharges.push_back(0);
580  }
581  // Charge sharing
582  B2DEBUG(29, " --> charge sharing simulation, # strips = " << strips.size());
583  std::deque<double> readoutCharges;
584  std::deque<int> readoutStrips;
585  VxdID currentSensorID = m_currentHit->getSensorID();
586  for (std::size_t index = 3; index < strips.size() - 3; index += 2) {
587  B2DEBUG(29, " index = " << index << ", strip = " << strips[index] << ", stripCharge = " << stripCharges[index]);
588  int currentStrip = static_cast<int>(strips[index]);
589 
590  double c0 = m_ChargeSimCal.getCouplingConstant(currentSensorID, !have_electrons, "C0");
591  double c1 = m_ChargeSimCal.getCouplingConstant(currentSensorID, !have_electrons, "C1");
592  double c2 = m_ChargeSimCal.getCouplingConstant(currentSensorID, !have_electrons, "C2");
593  double c3 = m_ChargeSimCal.getCouplingConstant(currentSensorID, !have_electrons, "C3");
594 
595  B2DEBUG(29, " current strip = " << currentStrip);
596  B2DEBUG(29, " index-3 = " << index - 3 << ", strip = " << strips[index - 3] << ", stripCharge = " << stripCharges[index - 3]);
597  B2DEBUG(29, " index-2 = " << index - 2 << ", strip = " << strips[index - 2] << ", stripCharge = " << stripCharges[index - 2]);
598  B2DEBUG(29, " index-1 = " << index - 1 << ", strip = " << strips[index - 1] << ", stripCharge = " << stripCharges[index - 1]);
599  B2DEBUG(29, " index = " << index << ", strip = " << strips[index] << ", stripCharge = " << stripCharges[index]);
600  B2DEBUG(29, " index+1 = " << index + 1 << ", strip = " << strips[index + 1] << ", stripCharge = " << stripCharges[index + 1]);
601  B2DEBUG(29, " index+2 = " << index + 2 << ", strip = " << strips[index + 2] << ", stripCharge = " << stripCharges[index + 2]);
602  B2DEBUG(29, " index+3 = " << index + 3 << ", strip = " << strips[index + 3] << ", stripCharge = " << stripCharges[index + 3]);
603 
604  readoutCharges.push_back(c3 * stripCharges[index - 3]
605  + c2 * stripCharges[index - 2]
606  + c1 * stripCharges[index - 1]
607  + c0 * stripCharges[index]
608  + c1 * stripCharges[index + 1]
609  + c2 * stripCharges[index + 2]
610  + c3 * stripCharges[index + 3]
611  );
612  readoutStrips.push_back(currentStrip);
613  B2DEBUG(29, " post simulation: " << index << ", strip = " << currentStrip << ", readoutCharge = " <<
614  readoutCharges[readoutCharges.size() - 1]);
615  }
616  // Trim at sensor edges
617  double tail = 0;
618  while (readoutStrips.size() > 0 && readoutStrips.front() < 0) {
619  readoutStrips.pop_front();
620  tail += readoutCharges.front();
621  readoutCharges.pop_front();
622  }
623  readoutCharges.front() += tail;
624  tail = 0;
625  while (readoutStrips.size() > 0 && readoutStrips.back() > nCells - 1) {
626  readoutStrips.pop_back();
627  tail += readoutCharges.back();
628  readoutCharges.pop_back();
629  }
630  readoutCharges.back() += tail;
631  // Poisson smearing - Gaussian approximation
632  if (m_applyPoisson)
633  for (auto& c : readoutCharges)
634  c = (c <= 0) ? 0 : std::max(0.0, gRandom->Gaus(c, std::sqrt(info.c_fanoFactorSi * c)));
635 
636  // Fill diagnostic charts
638  TH1D* histo = (!have_electrons) ? m_histChargeSharing_u : m_histChargeSharing_v;
639  double d = (!have_electrons) ? seedPos - center.X() : seedPos - center.Y();
640  for (std::size_t index = 0; index < readoutStrips.size(); ++ index) {
641  double dist = d + (readoutStrips[index] - seedStrip) * 2 * geomPitch;
642  histo->Fill(dist / Unit::um, readoutCharges[index]);
643  }
644  }
645  if (m_histHitTime) {
648  SVDModeByte modeByte = storeSVDEvtInfo->getModeByte();
649  m_histHitTimeTB->Fill(m_currentTime, modeByte.getTriggerBin());
650  }
651 
652  // Store
653  B2DEBUG(29, "currentTime = " << m_currentTime << " + 0.5 driftTime = " << 0.5 * driftTime << " = " << m_currentTime + 0.5 *
654  driftTime);
655 
656  // Specify beta prime decay time
657  double betaPrimeDecayTime = (!have_electrons) ? m_betaPrimeDecayTimeU : m_betaPrimeDecayTimeV;
658 
659  // Specify coupling and adjacent-channel waveform shape
660  double apvCoupling = m_ChargeSimCal.getCouplingConstant(currentSensorID, !have_electrons, "APVCoupling");
661  WaveformShape w_adjacent = (!have_electrons) ? w_adjacentU : w_adjacentV;
662 
663  double recoveredCharge = 0;
664  for (std::size_t index = 0; index < readoutStrips.size(); index ++) {
665  // NB> To first approximation, we assign to the signal 1/2*driftTime.
666  // This doesn't change the charge collection, only charge collection timing.
667  waveforms[readoutStrips[index]].add(m_currentTime + 0.5 * driftTime, readoutCharges[index],
668  betaPrimeDecayTime, m_currentParticle, m_currentTrueHit, w_betaprime);
669  // coupled signal left neighbour
670  if (index > 0)
671  waveforms[readoutStrips[index]].add(m_currentTime + 0.5 * driftTime, apvCoupling * readoutCharges[index - 1],
672  1, m_currentParticle, m_currentTrueHit, w_adjacent);
673  // coupled signal right neighbour
674  if (index < readoutStrips.size() - 1)
675  waveforms[readoutStrips[index]].add(m_currentTime + 0.5 * driftTime, apvCoupling * readoutCharges[index + 1],
676  1, m_currentParticle, m_currentTrueHit, w_adjacent);
677  recoveredCharge += readoutCharges[index];
678  B2DEBUG(29, "strip: " << readoutStrips[index] << " charge: " << readoutCharges[index]);
679  }
680  B2DEBUG(29, "Digitized " << recoveredCharge << " of " << carriers << " original carriers.");
681 }
682 
683 double SVDDigitizerModule::addNoise(double charge, double noise)
684 {
685  charge += gRandom->Gaus(0., noise);
686  return charge;
687 }
688 
690 {
691 
695  RelationArray relShaperDigitMCParticle(storeShaperDigits, storeMCParticles,
697  RelationArray relShaperDigitTrueHit(storeShaperDigits, storeTrueHits,
699 
700  //Get SVD config from SVDEventInfo
701  // int runType = (int) modeByte.getRunType();
702  // int eventType = (int) modeByte.getEventType();
703 
704 
705  // ... to store digit-digit relations
706  vector<pair<unsigned int, float> > digit_weights;
707 
708  // Take samples at the desired times, add noise, zero-suppress and save digits.
709  for (Waveforms::value_type& sensorWaveforms : m_waveforms) {
710  int sensorID = sensorWaveforms.first;
711  // u-side digits:
712 
713  // Cycle through signals and generate samples
714  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.first) {
715  short int iStrip = stripWaveform.first;
716  SVDWaveform& s = stripWaveform.second;
717  // Now generate samples in time and save as digits.
718  vector<double> samples;
719  // ... to store digit-digit relations
720  digit_weights.clear();
721  digit_weights.reserve(SVDShaperDigit::c_nAPVSamples);
722 
723  double elNoise = m_NoiseCal.getNoiseInElectrons(sensorID, true, iStrip);
724  double gain = 1 / m_PulseShapeCal.getChargeFromADC(sensorID, true, iStrip, 1);
725  double electronWeight = m_ChargeSimCal.getElectronWeight(sensorID, true);
726 
727  double t = m_initTime;
728  B2DEBUG(25, "start sampling at " << m_initTime);
729  for (int iSample = 0; iSample < (int) SVDShaperDigit::c_nAPVSamples; iSample ++) {
730  samples.push_back(addNoise(electronWeight * s(t), elNoise));
731  t += m_samplingTime;
732  }
733 
734  SVDWaveform::relations_map particles = s.getMCParticleRelations();
735  SVDWaveform::relations_map truehits = s.getTrueHitRelations();
736 
737  // Save SVDShaperDigits
738 
739  // 1. Convert to ADU
741  std::transform(samples.begin(), samples.end(), rawSamples.begin(),
742  [&](double x)->SVDShaperDigit::APVRawSampleType {
743  return SVDShaperDigit::trimToSampleRange(x * gain);
744  });
745 
746  // 2.a Check if over threshold
747  auto rawThreshold = m_SNAdjacent * elNoise * gain;
748  if (m_roundZS) rawThreshold = round(rawThreshold);
749  auto n_over = std::count_if(rawSamples.begin(), rawSamples.end(),
750  std::bind2nd(std::greater<double>(), rawThreshold)
751  );
752  if (n_over < m_nSamplesOverZS) continue;
753 
754  // 2.b check if the strip is masked
755  if (m_MaskedStr.isMasked(sensorID, true, iStrip)) continue;
756 
757  // 2.c check if the APV is disabled
758  if (!m_map->isAPVinMap(sensorID, true, iStrip)) continue;
759 
760  // 2.d.1 check if it's a 3-sample event
761  if (m_is3sampleEvent) {
762  rawSamples[0] = rawSamples[m_startingSample];
763  rawSamples[1] = rawSamples[m_startingSample + 1];
764  rawSamples[2] = rawSamples[m_startingSample + 2];
765  rawSamples[3] = 0.;
766  rawSamples[4] = 0.;
767  rawSamples[5] = 0.;
768  //2.d.2 check if still over threshold
769  n_over = std::count_if(rawSamples.begin(), rawSamples.end(),
770  std::bind2nd(std::greater<double>(), rawThreshold)
771  );
772  if (n_over < m_nSamplesOverZS) continue;
773 
774  }
775 
776  // 3. Save as a new digit
777  int digIndex = storeShaperDigits.getEntries();
778  storeShaperDigits.appendNew(sensorID, true, iStrip, rawSamples, 0);
779 
780  //If the digit has any relations to MCParticles, add the Relation
781  if (particles.size() > 0) {
782  relShaperDigitMCParticle.add(digIndex, particles.begin(), particles.end());
783  }
784  //If the digit has any relations to truehits, add the Relations.
785  if (truehits.size() > 0) {
786  relShaperDigitTrueHit.add(digIndex, truehits.begin(), truehits.end());
787  }
788  // generate SVDShaperDigits
789  } // for stripSignals
790 
791  // v-side digits:
792 
793  // Cycle through signals and generate samples
794  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.second) {
795  short int iStrip = stripWaveform.first;
796  SVDWaveform& s = stripWaveform.second;
797  // Now generate samples in time and save as digits.
798  vector<double> samples;
799  // ... to store digit-digit relations
800  digit_weights.clear();
801  digit_weights.reserve(SVDShaperDigit::c_nAPVSamples);
802 
803  double elNoise = m_NoiseCal.getNoiseInElectrons(sensorID, false, iStrip);
804  double gain = 1 / m_PulseShapeCal.getChargeFromADC(sensorID, false, iStrip, 1);
805  double electronWeight = m_ChargeSimCal.getElectronWeight(sensorID, false);
806 
807  double t = m_initTime;
808  for (int iSample = 0; iSample < (int)SVDShaperDigit::c_nAPVSamples; iSample ++) {
809  samples.push_back(addNoise(electronWeight * s(t), elNoise));
810  t += m_samplingTime;
811  }
812 
813  SVDWaveform::relations_map particles = s.getMCParticleRelations();
814  SVDWaveform::relations_map truehits = s.getTrueHitRelations();
815 
816  // Save SVDShaperDigits
817  // 1. Convert to ADU
819  std::transform(samples.begin(), samples.end(), rawSamples.begin(),
820  [&](double x)->SVDShaperDigit::APVRawSampleType {
821  return SVDShaperDigit::trimToSampleRange(x * gain);
822  });
823 
824  // 2.a Check if over threshold
825  auto rawThreshold = m_SNAdjacent * elNoise * gain;
826  if (m_roundZS) rawThreshold = round(rawThreshold);
827  auto n_over = std::count_if(rawSamples.begin(), rawSamples.end(),
828  std::bind2nd(std::greater<double>(), rawThreshold)
829  );
830  if (n_over < m_nSamplesOverZS) continue;
831 
832  // 2.b check if the strip is masked
833  if (m_MaskedStr.isMasked(sensorID, false, iStrip)) continue;
834 
835  // 2.c check if the APV is disabled
836  if (!m_map->isAPVinMap(sensorID, false, iStrip)) continue;
837 
838  // 2.d.1 check if it's a 3-sample event
839  if (m_is3sampleEvent) {
840  rawSamples[0] = rawSamples[m_startingSample];
841  rawSamples[1] = rawSamples[m_startingSample + 1];
842  rawSamples[2] = rawSamples[m_startingSample + 2];
843  rawSamples[3] = 0.;
844  rawSamples[4] = 0.;
845  rawSamples[5] = 0.;
846  //2.d.2 check if still over threshold
847  n_over = std::count_if(rawSamples.begin(), rawSamples.end(),
848  std::bind2nd(std::greater<double>(), rawThreshold)
849  );
850  if (n_over < m_nSamplesOverZS) continue;
851  }
852 
853  // 3. Save as a new digit
854  int digIndex = storeShaperDigits.getEntries();
855  storeShaperDigits.appendNew(sensorID, false, iStrip, rawSamples, 0);
856 
857  //If the digit has any relations to MCParticles, add the Relation
858  if (particles.size() > 0) {
859  relShaperDigitMCParticle.add(digIndex, particles.begin(), particles.end());
860  }
861  //If the digit has any relations to truehits, add the Relations.
862  if (truehits.size() > 0) {
863  relShaperDigitTrueHit.add(digIndex, truehits.begin(), truehits.end());
864  }
865  } // for stripSignals
866  } // FOREACH sensor
867 }
868 
870 {
871  for (Waveforms::value_type& sensorWaveforms : m_waveforms) {
872  tree_vxdID = sensorWaveforms.first;
873  const SensorInfo& info =
874  dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(sensorWaveforms.first));
875  // u-side digits:
876  tree_uv = 1;
877  double thresholdU = 3.0 * info.getElectronicNoiseU();
878  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.first) {
879  tree_strip = stripWaveform.first;
880  SVDWaveform& s = stripWaveform.second;
881  // Read the value only if the signal is large enough.
882  if (s.getCharge() < thresholdU)
883  continue;
884  for (int iTime = 0; iTime < 20; ++iTime) {
885  tree_signal[iTime] = s(10 * iTime);
886  }
887  m_waveTree->Fill();
888  } // FOREACH stripSignal
889  // v-side digits:
890  tree_uv = 0;
891  double thresholdV = 3.0 * info.getElectronicNoiseV();
892  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.second) {
893  tree_strip = stripWaveform.first;
894  SVDWaveform& s = stripWaveform.second;
895  // Read the values only if the signal is large enough
896  if (s.getCharge() < thresholdV)
897  continue;
898  for (int iTime = 0; iTime < 20; ++iTime) {
899  tree_signal[iTime] = s(10. * iTime);
900  }
901  m_waveTree->Fill();
902  } // FOREACH stripSignal
903  } // FOREACH sensor
904  m_rootFile->Flush();
905 }
906 
908 {
909  static size_t recordNo = 0;
910  static const string header("Event\tSensor\tSide\tStrip\tContrib\tTime\tCharge\tTau");
911  regex startLine("^|\n"); // for inserting event/sensor/etc info
912  ofstream outfile(m_signalsList, ios::out | ios::app);
913  if (recordNo == 0) outfile << header << endl;
914  for (Waveforms::value_type& sensorWaveforms : m_waveforms) {
915  VxdID sensorID(sensorWaveforms.first);
916  const SensorInfo& info =
917  dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(sensorWaveforms.first));
918  // u-side digits:
919  size_t isU = 1;
920  double thresholdU = 3.0 * info.getElectronicNoiseU();
921  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.first) {
922  size_t strip = stripWaveform.first;
923  SVDWaveform& s = stripWaveform.second;
924  // Read the value only if the signal is large enough.
925  if (s.getCharge() < thresholdU)
926  continue;
927  // Else print to a string
928  ostringstream preamble;
929  // We don't have eventNo, but we don't care about event boundaries.
930  preamble << "$&" << recordNo << '\t' << sensorID << '\t' << isU << '\t' << strip << '\t';
931  string signalString = s.toString();
932  signalString.pop_back(); // remove the last newline!!!
933  string tableString = regex_replace(signalString, startLine, preamble.str());
934  outfile << tableString << endl; // now we have to add the newline back.
935  } // FOREACH stripSignal
936  // x-side digits:
937  isU = 0;
938  double thresholdV = 3.0 * info.getElectronicNoiseV();
939  for (StripWaveforms::value_type& stripWaveform : sensorWaveforms.second.second) {
940  size_t strip = stripWaveform.first;
941  SVDWaveform& s = stripWaveform.second;
942  // Read the value only if the signal is large enough.
943  if (s.getCharge() < thresholdV)
944  continue;
945  // Else print to a string
946  ostringstream preamble;
947  // We don't have eventNo, but we don't care about event boundaries.
948  preamble << "$&" << recordNo << '\t' << sensorID << '\t' << isU << '\t' << strip << '\t';
949  string signalString = s.toString();
950  signalString.pop_back(); // remove the last newline!!!
951  string tableString = regex_replace(signalString, startLine, preamble.str());
952  outfile << tableString << endl; // now we have to add the newline back.
953  } // FOREACH stripSignal
954  } // for sensors
955  outfile.close();
956  recordNo++;
957 }
958 
960 {
961  if (m_rootFile) {
962  m_rootFile->Write();
963  m_rootFile->Close();
964  }
965 }
966 
967 int SVDDigitizerModule::getFirstSample(int triggerBin, int relativeShift)
968 {
969  int nTriggerClocks = triggerBin + relativeShift;
970  return floor(nTriggerClocks / 4);
971 }
int getPDGCode() const
PDG code.
Definition: Const.h:464
static const double kBoltzmann
Boltzmann constant in GeV/K.
Definition: Const.h:687
static const ParticleType photon
photon particle
Definition: Const.h:664
bool hasChanged()
Check whether the object has changed since the last call to hasChanged of the accessor).
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
@ 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
std::string getFileName() const
Get the name of the downloaded payload file.
Definition: PayloadFile.h:35
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.
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.
float getCouplingConstant(const VxdID &sensorID, const bool &isU, const std::string &couplingName) const
Return coupling constant.
float getElectronWeight(const VxdID &sensorID, const bool &isU) const
Return Geant4 electron weight.
float isMasked(const VxdID &sensorID, const bool &isU, const unsigned short &strip) const
This is the method for getting the comprehensive list of masked strips at FADC level.
bool isValid()
returns true if the m_aDBObtPtr is valid in the requested IoV
Class to store SVD mode information.
Definition: SVDModeByte.h:69
baseType getTriggerBin() const
Get the triggerBin id.
Definition: SVDModeByte.h:140
float getNoiseInElectrons(const VxdID &sensorID, const bool &isU, const unsigned short &strip) const
This method provides the correct noise conversion into electrons, taking into account that the noise ...
double getChargeFromADC(const Belle2::VxdID &sensorID, const bool &isU, const unsigned short &strip, const double &pulseADC) const
Return the charge (number of electrons/holes) collected on a specific strip, given the number of ADC ...
static void setAPVMode(size_t mode, size_t firstSample)
set APV mode for the event
static const std::size_t c_nAPVSamples
Number of APV samples stored.
std::array< APVRawSampleType, c_nAPVSamples > APVRawSamples
array of APVRawSamplesType objects
double m_startSampling
Time window start, excluding trigger bin effect.
TH1D * m_histHitTime
Histogram showing the hit time.
TH1D * m_histDistanceToPlane_e
Histogram showing the distance to plane for e.
TH1D * m_histChargeSharing_u
Histogram showing the charge sharing + diffusion in u (r-phi).
double m_sensorThickness
Thickness of current sensor (read from m_currentSensorInfo).
void processHit()
Process one SVDSimHit by dividing the step in smaller steps and drifting the charge.
TH1D * m_histVelocity_h
Histogram showing the velocity of h.
SVDFADCMaskedStrips m_MaskedStr
FADC masked strip payload.
TH1D * m_histVelocity_e
Histogram showing the velocity of e-.
Waveforms m_waveforms
Structure containing waveforms in all existing sensors.
double m_samplingTime
Interval between two waveform samples, by default taken from HardwareClockSettings.
std::string m_relTrueHitSimHitName
Name of the relation between SVDTrueHits and SVDSimHits.
TH1D * m_histLorentz_v
Histogram showing the Lorentz angles in v (z).
void saveDigits()
Save digits to the DataStore Saves samples of generated waveforms.
bool m_randomizeEventTimes
Randomize event times? If set to true, event times will be randomized uniformly from m_minTimeFrame t...
int getFirstSample(int triggerBin, int relativShift)
return the starting sample
int m_startingSample
Starting sample for the selection of 3 samples in 3-mixed-6.
int m_currentParticle
Index of the particle which caused the current hit.
std::string m_relShaperDigitMCParticleName
Name of the relation between SVDShaperDigits and MCParticles.
int m_nSamplesOverZS
Keep digit if at least m_nSamplesOverZS are over threshold.
TH1D * m_histChargeSharing_v
Histogram showing the charge sharing + diffusion in v (z).
TH1D * m_histMobility_h
Histogram showing the mobility of h.
virtual void initialize() override
Initialize the module and check module parameters.
bool m_roundZS
Round ZS cut to nearest ADU.
std::string m_storeShaperDigitsName
Name of the collection for the SVDShaperDigits.
virtual void event() override
Digitize one event.
bool m_is3sampleEvent
True if the event should be simulated with 3 sample.
double m_SNAdjacent
Zero-suppression cut.
double m_currentTime
Time of the current SimHit.
TFile * m_rootFile
Pointer to the ROOT filename for statistics.
SVDNoiseCalibrations m_NoiseCal
SVDNoise calibrations db object.
SensorWaveforms * m_currentSensorWaveforms
Pointer to the sensor in which the current hit occurred.
std::string m_storeTrueHitsName
Name of the collection for the SVDTrueHits.
TH1D * m_signalDist_u
Histogram showing the distribution of digit signals in u (r-phi).
DBObjPtr< PayloadFile > m_mapping
channel mapping payload
virtual void terminate() override
Terminate the module.
void saveSignals()
Save signals to a root-delimited file (to be analyzed in Python).
std::string m_storeMCParticlesName
Name of the collection for the MCParticles.
TH1D * m_signalDist_v
Histogram showing the distribution of digit signals in v (z).
double m_noiseFraction
(derived from SNAdjacent) Fraction of noisy strips per sensor.
static std::string m_xmlFileName
< channel mapping xml filename
double m_betaPrimeDecayTimeU
Decay time of betaprime waveform U-side.
SVDPulseShapeCalibrations m_PulseShapeCal
SVDPulseShapeCalibrations calibrations db object.
TH1D * m_histMobility_e
Histogram showing the mobility of e-.
std::string m_relShaperDigitTrueHitName
Name of the relation between SVDShaperDigits and SVDTrueHits.
SVDChargeSimulationCalibrations m_ChargeSimCal
SVDChargeSimulationCalibrations calibrations db object.
int m_nAPV25Samples
number of digitized samples read from SVDEventInfo
TTree * m_waveTree
Tree for waveform storage.
bool m_applyPoisson
Whether or not to apply poisson fluctuation of charge (Fano factor)
virtual void beginRun() override
Initialize the list of existing SVD Sensors.
TH1D * m_histDistanceToPlane_h
Histogram showing the distance to plane for h.
TH1D * m_histDriftTime_e
Histogram showing the drift time of e.
DBObjPtr< HardwareClockSettings > m_hwClock
Hardware Clocks.
std::string m_svdEventInfoName
Name of the SVDEventInfo object.
std::string m_signalsList
Name of the tab-delimited listing of waveforms.
double addNoise(double charge, double noise)
Calculate the noise contribution to one strip with given charge.
const SensorInfo * m_currentSensorInfo
Pointer to the SensorInfo of the current sensor.
TH1D * m_histLorentz_u
Histogram showing the Lorentz angles in u (r-phi).
int m_relativeShift
relative shift in SVDEventInfo obj
TH2F * m_histHitTimeTB
Histogram showing the hit time vs TB.
bool m_storeWaveforms
Store waveform data in the reporting file?
void driftCharge(const ROOT::Math::XYZVector &position, double carriers, SVD::SensorInfo::CarrierType carrierType)
Drift the charge inside the silicon.
void saveWaveforms()
Save waveforms to the statistics file.
std::unique_ptr< SVDOnlineToOfflineMap > m_map
channel mapping map
float m_maxTimeFrame
High edge of randomization time frame.
TH1D * m_histDriftTime_h
Histogram showing the drift time of h.
double m_initTime
Time window start, including the triggerBin effect.
int m_currentTrueHit
Index of the TrueHit the current hit belongs to.
float m_minTimeFrame
Low edge of randomization time frame.
const SVDSimHit * m_currentHit
Pointer to the SVDSimhit currently digitized.
std::string m_relMCParticleSimHitName
Name of the relation between MCParticles and SVDSimHits.
double m_betaPrimeDecayTimeV
Decay time of betaprime waveform V-side.
std::string m_rootFilename
Name of the ROOT filename to output statistics.
std::string m_storeSimHitsName
Name of the collection for the SVDSimhits.
float m_currentEventTime
Current event time.
The SVD waveform class.
Definition: SVDWaveform.h:38
std::map< RelationElement::index_type, RelationElement::weight_type > relations_map
Type to store contributions to strip signal by different particles on output of SVDWaveform.
Definition: SVDWaveform.h:80
Specific implementation of SensorInfo for SVD Sensors which provides additional sensor specific infor...
Definition: SensorInfo.h:25
CarrierType
Enum to flag charge carriers.
Definition: SensorInfo.h:38
double getBiasVoltage() const
Return the bias voltage on the sensor.
Definition: SensorInfo.h:163
double getDepletionVoltage() const
Return the depletion voltage of the sensor.
Definition: SensorInfo.h:161
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.
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
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
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
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
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 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
static const SensorInfoBase & get(Belle2::VxdID id)
Return a reference to the SensorInfo of a given SensorID.
Definition: GeoCache.h:139
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.
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
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 SVD.
Definition: GeoSVDCreator.h:23
std::pair< StripWaveforms, StripWaveforms > SensorWaveforms
Waveforms of u- and v- channels in one sensor.
std::function< double(double)> WaveformShape
WaveformShape type.
double w_adjacentU(double t)
Adjacent-channel waveform U-side.
double w_betaprime(double t)
Beta-prime waveform shape, x^alpha/(1+x)^beta.
double w_adjacentV(double t)
Adjacent-channel waveform V-side.
std::map< short int, SVDWaveform > StripWaveforms
Map of all channels' waveforms in one sensor side.
Abstract base class for different kinds of events.
RelationElement::index_type indexFrom
index of the element from which the relation points.
RelationElement::weight_type weight
weight of the relation.