Belle II Software  release-08-01-10
SVDNNClusterizerModule.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/svdReconstruction/SVDNNClusterizerModule.h>
10 
11 #include <framework/datastore/StoreArray.h>
12 #include <framework/logging/Logger.h>
13 
14 #include <vxd/geometry/GeoCache.h>
15 #include <svd/geometry/SensorInfo.h>
16 
17 #include <mdst/dataobjects/MCParticle.h>
18 #include <svd/dataobjects/SVDTrueHit.h>
19 #include <svd/dataobjects/SVDShaperDigit.h>
20 #include <svd/dataobjects/SVDRecoDigit.h>
21 #include <svd/dataobjects/SVDCluster.h>
22 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
23 
24 #include <svd/reconstruction/NNWaveFitTool.h>
25 
26 #include <algorithm>
27 #include <numeric>
28 #include <functional>
29 #include <cassert>
30 
31 using namespace std;
32 using namespace Belle2;
33 using namespace Belle2::SVD;
34 
35 //-----------------------------------------------------------------
36 // Register the Module
37 //-----------------------------------------------------------------
38 REG_MODULE(SVDNNClusterizer);
39 
40 //-----------------------------------------------------------------
41 // Implementation
42 //-----------------------------------------------------------------
43 
44 SVDNNClusterizerModule::SVDNNClusterizerModule() : Module()
45 {
46  B2DEBUG(200, "SVDNNClusterizerModule ctor");
47  //Set module properties
48  setDescription("Clusterize SVDRecoDigits and reconstruct hits");
50 
51  // 1. Collections.
53  "RecoDigits collection name", string(""));
54  addParam("Clusters", m_storeClustersName,
55  "Cluster collection name", string(""));
56  addParam("TrueHits", m_storeTrueHitsName,
57  "TrueHit collection name", string(""));
58  addParam("MCParticles", m_storeMCParticlesName,
59  "MCParticles collection name", string(""));
60 
61  // 2. Calibration and time fitter sources
62  addParam("TimeFitterName", m_timeFitterName,
63  "Name of time fitter data file", string("SVDTimeNet_6samples"));
64  addParam("CalibratePeak", m_calibratePeak, "Use calibrattion (vs. default) for peak widths and positions", bool(false));
65 
66  // 3. Clustering
67  // FIXME: Idiotic names of parameters kept for compatibility with the old clusterizer.
68  addParam("NoiseSN", m_cutAdjacent,
69  "SN for digits to be considered for clustering", m_cutAdjacent);
70  addParam("SeedSN", m_cutSeed,
71  "SN for digits to be considered as seed", m_cutSeed);
72  addParam("ClusterSN", m_cutCluster,
73  "Minimum SN for clusters", m_cutCluster);
74  addParam("HeadTailSize", m_sizeHeadTail,
75  "Cluster size at which to switch to Analog head tail algorithm", m_sizeHeadTail);
76 
77 }
78 
80 {
81  //Register collections
86 
87  storeClusters.registerInDataStore();
88  storeRecoDigits.isRequired();
89  storeTrueHits.isOptional();
90  storeMCParticles.isOptional();
91 
92  RelationArray relClusterRecoDigits(storeClusters, storeRecoDigits);
93  RelationArray relClusterTrueHits(storeClusters, storeTrueHits);
94  RelationArray relClusterMCParticles(storeClusters, storeMCParticles);
95  RelationArray relRecoDigitTrueHits(storeRecoDigits, storeTrueHits);
96  RelationArray relRecoDigitMCParticles(storeRecoDigits, storeMCParticles);
97 
98  relClusterRecoDigits.registerInDataStore();
99  //Relations to simulation objects only if the ancestor relations exist
100  if (relRecoDigitTrueHits.isOptional())
101  relClusterTrueHits.registerInDataStore();
102  if (relRecoDigitMCParticles.isOptional())
103  relClusterMCParticles.registerInDataStore();
104 
105  //Store names to speed up creation later
106  m_storeClustersName = storeClusters.getName();
107  m_storeRecoDigitsName = storeRecoDigits.getName();
108  m_storeTrueHitsName = storeTrueHits.getName();
109  m_storeMCParticlesName = storeMCParticles.getName();
110 
111  m_relClusterRecoDigitName = relClusterRecoDigits.getName();
112  m_relClusterTrueHitName = relClusterTrueHits.getName();
113  m_relClusterMCParticleName = relClusterMCParticles.getName();
114  m_relRecoDigitTrueHitName = relRecoDigitTrueHits.getName();
115  m_relRecoDigitMCParticleName = relRecoDigitMCParticles.getName();
116 
117  B2INFO(" 1. COLLECTIONS:");
118  B2INFO(" --> MCParticles: " << m_storeMCParticlesName);
119  B2INFO(" --> Digits: " << m_storeRecoDigitsName);
120  B2INFO(" --> Clusters: " << m_storeClustersName);
121  B2INFO(" --> TrueHits: " << m_storeTrueHitsName);
122  B2INFO(" --> DigitMCRel: " << m_relRecoDigitMCParticleName);
123  B2INFO(" --> ClusterMCRel: " << m_relClusterMCParticleName);
124  B2INFO(" --> ClusterDigitRel: " << m_relClusterRecoDigitName);
125  B2INFO(" --> DigitTrueRel: " << m_relRecoDigitTrueHitName);
126  B2INFO(" --> ClusterTrueRel: " << m_relClusterTrueHitName);
127  B2INFO(" 2. CALIBRATION DATA:");
128  B2INFO(" --> Time NN: " << m_timeFitterName);
129  B2INFO(" 4. CLUSTERING:");
130  B2INFO(" --> Neighbour cut: " << m_cutAdjacent);
131  B2INFO(" --> Seed cut: " << m_cutSeed);
132  B2INFO(" --> Cluster charge cut: " << m_cutCluster);
133  B2INFO(" --> HT for clusters >: " << m_sizeHeadTail);
134 
135  // Properly initialize the NN time fitter
136  // FIXME: Should be moved to beginRun
137  // FIXME: No support for 3/6 sample switching within a run/event
139  m_fitter.setNetwrok(dbXml->m_data);
140 }
141 
143  RelationLookup& lookup, size_t digits)
144 {
145  lookup.clear();
146  //If we don't have a relation we don't build a lookuptable
147  if (!relation) return;
148  //Resize to number of digits and set all values
149  lookup.resize(digits);
150  for (const auto& element : relation) {
151  lookup[element.getFromIndex()] = &element;
152  }
153 }
154 
156  std::map<unsigned int, float>& relation, unsigned int index)
157 {
158  //If the lookup table is not empty and the element is set
159  if (!lookup.empty() && lookup[index]) {
160  const RelationElement& element = *lookup[index];
161  const unsigned int size = element.getSize();
162  //Add all Relations to the map
163  for (unsigned int i = 0; i < size; ++i) {
164  //negative weights are from ignored particles, we don't like them and
165  //thus ignore them :D
166  if (element.getWeight(i) < 0) continue;
167  relation[element.getToIndex(i)] += element.getWeight(i);
168  }
169  }
170 }
171 
173 {
174  const StoreArray<SVDRecoDigit> storeRecoDigits(m_storeRecoDigitsName);
175  // If no recodigits, nothing to do
176  if (!storeRecoDigits || !storeRecoDigits.getEntries()) return;
177 
178  size_t nDigits = storeRecoDigits.getEntries();
179  B2DEBUG(90, "Initial size of RecoDigits array: " << nDigits);
180 
181  const StoreArray<MCParticle> storeMCParticles(m_storeMCParticlesName);
182  const StoreArray<SVDTrueHit> storeTrueHits(m_storeTrueHitsName);
183 
184  RelationArray relRecoDigitMCParticle(storeRecoDigits, storeMCParticles, m_relRecoDigitMCParticleName);
185  RelationArray relRecoDigitTrueHit(storeRecoDigits, storeTrueHits, m_relRecoDigitTrueHitName);
186 
188  storeClusters.clear();
189 
190  RelationArray relClusterMCParticle(storeClusters, storeMCParticles,
192  if (relClusterMCParticle) relClusterMCParticle.clear();
193 
194  RelationArray relClusterRecoDigit(storeClusters, storeRecoDigits,
196  if (relClusterRecoDigit) relClusterRecoDigit.clear();
197 
198  RelationArray relClusterTrueHit(storeClusters, storeTrueHits,
200  if (relClusterTrueHit) relClusterTrueHit.clear();
201 
202  //Build lookup tables for relations
203  createRelationLookup(relRecoDigitMCParticle, m_mcRelation, nDigits);
204  createRelationLookup(relRecoDigitTrueHit, m_trueRelation, nDigits);
205 
206  // Create fit tool object
207  NNWaveFitTool fitTool = m_fitter.getFitTool();
208 
209  // I. Group digits by sensor/side.
210  vector<pair<unsigned short, unsigned short> > sensorDigits;
211  VxdID lastSensorID(0);
212  size_t firstSensorDigit = 0;
213  for (size_t iDigit = 0; iDigit < nDigits; ++iDigit) {
214  const SVDRecoDigit& adigit = *storeRecoDigits[iDigit];
215  VxdID sensorID = adigit.getSensorID();
216  sensorID.setSegmentNumber(adigit.isUStrip() ? 1 : 0);
217  if (sensorID != lastSensorID) { // we have a new sensor side
218  sensorDigits.push_back(make_pair(firstSensorDigit, iDigit));
219  firstSensorDigit = iDigit;
220  lastSensorID = sensorID;
221  }
222  }
223  // save last VxdID
224  sensorDigits.push_back(make_pair(firstSensorDigit, nDigits));
225 
226  // ICYCLE OVER SENSORS
227  for (auto id_indices : sensorDigits) {
228  // Retrieve parameters from sensorDigits
229  unsigned int firstDigit = id_indices.first;
230  unsigned int lastDigit = id_indices.second;
231  // Get VXDID from the first digit
232  const SVDRecoDigit& sampleRecoDigit = *storeRecoDigits[firstDigit];
233  VxdID sensorID = sampleRecoDigit.getSensorID();
234  bool isU = sampleRecoDigit.isUStrip();
235 
236  // Retrieve sensor parameters from GeoCache
237  const SensorInfo& sensorInfo = dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(sensorID));
238 
239  // 4. Cycle through digits and form clusters on the way.
240 
241  // Identify contiguous groups of strips
242  // We maintain two pointers: firstDigit and lastDigit. We also keep track of last seen
243  // strip number.
244  // We start with firstDigit = lastDigit = 0
245  // If there is a gap in strip numbers or the current digit/strip is invalid, we save the
246  // current group (fd, cd), unless empty, and set fd = cd.
247  // If current strip is valid, we include it: ld = cd+1.
248 
249  vector<pair<size_t, size_t> > stripGroups;
250  size_t firstClusterDigit = firstDigit;
251  size_t lastClusterDigit = firstDigit;
252  short lastStrip = -2;
253 
254  B2DEBUG(300, "Clustering digits " << firstDigit << " to " << lastDigit);
255  for (size_t iDigit = firstDigit; iDigit < lastDigit; ++iDigit) {
256 
257  const SVDRecoDigit& recoDigit = *storeRecoDigits[iDigit];
258  unsigned short currentStrip = recoDigit.getCellID();
259  B2DEBUG(300, "Digit " << iDigit << ", strip: " << currentStrip << ", lastStrip: " << lastStrip);
260  B2DEBUG(300, "First CD: " << firstClusterDigit << " Last CD: " << lastClusterDigit);
261 
262  // See if we have a gap in strip numbers.
263  bool consecutive = ((currentStrip - lastStrip) == 1);
264  lastStrip = currentStrip;
265 
266  B2DEBUG(300, (consecutive ? "consecutive" : "gap"));
267 
268  // If we have a gap, we save if there is something to save
269  if (!consecutive && (firstClusterDigit < lastClusterDigit)) {
270  B2DEBUG(300, "Saving (" << firstClusterDigit << ", " << lastClusterDigit << ")");
271  stripGroups.emplace_back(firstClusterDigit, lastClusterDigit);
272  }
273 
274  // Update counters
275  if (consecutive) {// consecutive : include in cluster
276  lastClusterDigit = iDigit + 1;
277  } else { // valid after a gap = new cluster
278  firstClusterDigit = iDigit;
279  lastClusterDigit = iDigit + 1;
280  }
281  } // for digits
282  // save last if any
283  if (firstClusterDigit < lastClusterDigit) {
284  B2DEBUG(300, "Saving (" << firstClusterDigit << ", " << lastDigit << ")");
285  stripGroups.emplace_back(firstClusterDigit, lastDigit);
286  }
287 
288  ostringstream os;
289  os << "StripGroups: " << endl;
290  for (auto item : stripGroups) {
291  os << "(" << item.first << ", " << item.second << "), ";
292  }
293  B2DEBUG(300, os.str());
294 
295  // 5. Now we loop through stripGroups and form clusters.
296  // We are still keeping digit indices, so we are keeping hold on the relations as wwell.
297  double pitch = isU ? sensorInfo.getUPitch() : sensorInfo.getVPitch();
298 
299  // FIXME: Pretty stupid. There should be ClusterCandidate type to hold all this, as
300  // well as normed samples. It could calculate a lot of things by itself and make the
301  // code cleaner.
302  vector<unsigned short> stripNumbers;
303  vector<float> stripPositions;
304  vector<float> stripNoises;
305  vector<float> stripGains;
306  vector<float> timeShifts;
307  vector<float> waveWidths;
308  vector<apvSamples> storedNormedSamples;
309  vector<SVDRecoDigit::OutputProbArray> storedPDFs;
310 
311  // Now reconstruct clusters
312  for (auto clusterBounds : stripGroups) {
313 
314  unsigned short clusterSize = clusterBounds.second - clusterBounds.first;
315  assert(clusterSize > 0);
316 
317  stripNumbers.clear();
318  stripPositions.clear();
319  stripNoises.clear();
320  stripGains.clear();
321  timeShifts.clear();
322  waveWidths.clear();
323 
324  for (size_t iDigit = clusterBounds.first; iDigit < clusterBounds.second; ++iDigit) {
325  // Now we take the normed samples and calculate the common
326  // cluster probability distribution and, from it, the time and its error, and
327  // the probability of the hit being from beam background.
328  const SVDRecoDigit& recoDigit = *storeRecoDigits[iDigit];
329 
330  unsigned short stripNo = recoDigit.getCellID();
331  stripNumbers.push_back(stripNo);
332  // Is the calibrations interface sensible?
333  double stripNoiseADU = m_noiseCal.getNoise(sensorID, isU, stripNo);
334  stripNoises.push_back(
335  m_pulseShapeCal.getChargeFromADC(sensorID, isU, stripNo, stripNoiseADU)
336  );
337  // Some calibrations magic.
338  // FIXME: Only use calibration on real data. Until simulations correspond to
339  // default calibrtion, we cannot use it.
340  double peakWidth = 270;
341  double timeShift = isU ? 4.0 : 0.0;
342  if (m_calibratePeak) {
343  peakWidth = 1.988 * m_pulseShapeCal.getWidth(sensorID, isU, stripNo);
344  timeShift = m_pulseShapeCal.getPeakTime(sensorID, isU, stripNo)
345  - 0.25 * peakWidth;
346  }
347  waveWidths.push_back(peakWidth);
348  timeShifts.push_back(timeShift);
349  stripPositions.push_back(
350  isU ? sensorInfo.getUCellPosition(stripNo) : sensorInfo.getVCellPosition(stripNo)
351  );
352  // Recover samples from ShaperDigits and store them.
353  apvSamples normedSamples;
354  const SVDShaperDigit* shaperDigit = recoDigit.getRelatedTo<SVDShaperDigit>();
355  if (!shaperDigit) // PANIC, this should not happen.
356  B2FATAL("Missing SVDRecoDigits->SVDShaperDigits relation. This should not happen.");
357  auto samples = shaperDigit->getSamples();
358  transform(samples.begin(), samples.end(), normedSamples.begin(),
359  bind2nd(divides<float>(), stripNoiseADU));
360 
361  // These are from ShaperDigit, we need to zeroSuppress again,
362  // just in case.
363  zeroSuppress(normedSamples, m_cutAdjacent);
364  storedNormedSamples.emplace_back(normedSamples);
365  storedPDFs.emplace_back(recoDigit.getProbabilities());
366  }
367  // The formulas don't take into account differences in strip noises. So we take RMS
368  // strip noise as cluster noise.
369  // clusterNoise is noise in electrons.
370  float clusterNoise = sqrt(
371  1.0 / clusterSize
372  * inner_product(stripNoises.begin(), stripNoises.end(), stripNoises.begin(), 0.0)
373  );
374  B2DEBUG(200, "RMS cluster noise: " << clusterNoise);
375 
376  // This will hold component pdfs. We may want to rememeber them to study
377  // homogeneity of cluster times.
378  shared_ptr<nnFitterBinData> pStrip;
379  // This will aggregate the components pdfs to get cluster time pdf
380  nnFitterBinData pCluster(m_fitter.getBinCenters().size());
381  fill(pCluster.begin(), pCluster.end(), double(1.0));
382 
383  for (size_t iClusterStrip = 0; iClusterStrip < clusterSize; ++iClusterStrip) {
384  size_t iDigit = clusterBounds.first + iClusterStrip;
385  ostringstream os1;
386  os1 << "Input to NNFitter: iDigit = " << iDigit << endl << "Samples: ";
387  copy(storedNormedSamples[iClusterStrip].begin(), storedNormedSamples[iClusterStrip].end(),
388  ostream_iterator<double>(os1, " "));
389  os1 << endl;
390  os1 << "PDF from RecoDigit: " << endl;
391  copy(storedPDFs[iClusterStrip].begin(), storedPDFs[iClusterStrip].end(), ostream_iterator<double>(os1, " "));
392  os1 << endl;
393  fitTool.multiply(pCluster, storedPDFs[iClusterStrip]);
394  os1 << "Accummulated: " << endl;
395  copy(pCluster.begin(), pCluster.end(), ostream_iterator<double>(os1, " "));
396  B2DEBUG(200, os1.str());
397  }
398  // We can now calculate clsuter time and its error.
399  double clusterTime, clusterTimeErr;
400  tie(clusterTime, clusterTimeErr) = fitTool.getTimeShift(pCluster);
401  B2DEBUG(200, "Time: " << clusterTime << " +/- " << clusterTimeErr);
402  // Now we have the cluster time pdf, so we can calculate amplitudes.
403  // In the next cycle thrugh cluster's digits, we calculate ampltidues and their
404  // errors.
405  vector<double> stripAmplitudes(stripNoises.size());
406  vector<double> stripAmplitudeErrors(stripNoises.size());
407  double clusterChi2 = 0.0;
408  for (size_t iClusterStrip = 0; iClusterStrip < clusterSize; ++iClusterStrip) {
409  size_t iDigit = clusterBounds.first + iClusterStrip;
410  double snAmp, snAmpError, chi2;
411  tie(snAmp, snAmpError, chi2) =
412  fitTool.getAmplitudeChi2(storedNormedSamples[iClusterStrip], clusterTime, waveWidths[iClusterStrip]);
413  // We have to de-normalize: Multiply amplitudes in SN units by noises in electrons.
414  stripAmplitudes[iClusterStrip] = stripNoises[iClusterStrip] * snAmp;
415  stripAmplitudeErrors[iClusterStrip] = stripNoises[iClusterStrip] * snAmpError;
416  clusterChi2 += chi2;
417  B2DEBUG(200, "Digit " << iDigit << " Noise: " << stripNoises[iClusterStrip]
418  << " Amplitude: " << stripAmplitudes[iClusterStrip]
419  << " +/- " << stripAmplitudeErrors[iClusterStrip]
420  << " Chi2: " << chi2
421  );
422  }
423  // Cluster charge, S/N, chi2
424  float clusterCharge = accumulate(stripAmplitudes.begin(), stripAmplitudes.end(), 0.0);
425  float clusterChargeError = sqrt(
426  inner_product(stripAmplitudeErrors.begin(), stripAmplitudeErrors.end(),
427  stripAmplitudeErrors.begin(), 0.0)
428  );
429  float clusterSN = (clusterChargeError > 0) ? clusterCharge / clusterChargeError : clusterCharge;
430  // FIXME: Return chi2 and ndf from GetApmplitude, this is ugly.
431  clusterChi2 /= clusterSize;
432  // Cluster seed
433  size_t seedIndex = distance(stripAmplitudes.begin(), max_element(
434  stripAmplitudes.begin(), stripAmplitudes.end()));
435  float clusterSeedCharge = stripAmplitudes[seedIndex];
436  B2DEBUG(200, "Cluster parameters:");
437  B2DEBUG(200, "Charge: " << clusterCharge << " +/- " << clusterChargeError);
438  B2DEBUG(200, "Seed: " << clusterSeedCharge << " +/- " << stripAmplitudeErrors[seedIndex]);
439  B2DEBUG(200, "S/N: " << clusterSN);
440  B2DEBUG(200, "chi2: " << clusterChi2);
441 
442  // Hit position
443  float clusterPosition, clusterPositionError;
444 
445  // Now censoring:
446  // NB: We don't censor strip charges again. The requirement of 3 consecutive samples
447  // above threshold is a good enough safeguard.
448  if ((clusterCharge < clusterNoise * m_cutCluster) || (clusterSeedCharge < clusterNoise * m_cutSeed))
449  continue;
450 
451  if (clusterSize < m_sizeHeadTail) { // centre of gravity
452  clusterPosition = 1.0 / clusterCharge * inner_product(
453  stripAmplitudes.begin(), stripAmplitudes.end(), stripPositions.begin(), 0.0
454  );
455  // Strip charge equal to zero-suppression threshold
456  float phantomCharge = m_cutAdjacent * clusterNoise;
457  if (clusterSize == 1) {
458  clusterPositionError = pitch * phantomCharge / (clusterCharge + phantomCharge);
459  } else {
460  clusterPositionError = pitch * phantomCharge / clusterCharge;
461  }
462  } else { // Head-tail
463  float leftStripCharge = stripAmplitudes.front();
464  float leftPos = stripPositions.front();
465  float rightStripCharge = stripAmplitudes.back();
466  float rightPos = stripPositions.back();
467  float centreCharge = (clusterCharge - leftStripCharge - rightStripCharge) / (clusterSize - 2);
468  leftStripCharge = (leftStripCharge < centreCharge) ? leftStripCharge : centreCharge;
469  rightStripCharge = (rightStripCharge < centreCharge) ? rightStripCharge : centreCharge;
470  clusterPosition = 0.5 * (leftPos + rightPos)
471  + 0.5 * (rightStripCharge - leftStripCharge) / centreCharge * pitch;
472  float sn = centreCharge / m_cutAdjacent / clusterNoise;
473  // Rough estimates of Landau noise
474  float landauHead = leftStripCharge / centreCharge;
475  double landauTail = rightStripCharge / centreCharge;
476  clusterPositionError = 0.5 * pitch * sqrt(1.0 / sn / sn
477  + 0.5 * landauHead * landauHead + 0.5 * landauTail * landauTail);
478  }
479  //Lorentz shift correction
480  clusterPosition -= sensorInfo.getLorentzShift(isU, clusterPosition);
481 
482  // Finally, we save the cluster and its relations.
483  map<unsigned int, float> mc_relations;
484  map<unsigned int, float> truehit_relations;
485  vector<pair<unsigned int, float> > digit_weights;
486  digit_weights.reserve(clusterSize);
487 
488  for (size_t iDigit = clusterBounds.first; iDigit < clusterBounds.second; ++iDigit) {
489  // Store relations to MCParticles and SVDTrueHits
490  fillRelationMap(m_mcRelation, mc_relations, iDigit);
491  fillRelationMap(m_trueRelation, truehit_relations, iDigit);
492  //Add digit to the Cluster->Digit relation list
493  digit_weights.emplace_back(iDigit, stripAmplitudes[iDigit - clusterBounds.first]);
494  }
495 
496  //Store the cluster into Datastore ...
497  int clsIndex = storeClusters.getEntries();
498  VxdID clusterSensorID = sensorID;
499  clusterSensorID.setSegmentNumber(0);
500  storeClusters.appendNew(
501  SVDCluster(sensorID, isU, clusterPosition, clusterPositionError, clusterTime,
502  clusterTimeErr, clusterCharge, clusterSeedCharge, clusterSize, clusterSN, clusterChi2)
503  );
504 
505  //Create relations to the cluster
506  if (!mc_relations.empty()) {
507  relClusterMCParticle.add(clsIndex, mc_relations.begin(), mc_relations.end());
508  }
509  if (!truehit_relations.empty()) {
510  relClusterTrueHit.add(clsIndex, truehit_relations.begin(), truehit_relations.end());
511  }
512  relClusterRecoDigit.add(clsIndex, digit_weights.begin(), digit_weights.end());
513  } // CYCLE OVER CLUSTERS for stripGroups
514 
515  } // CYCLE OVER SENSORS for items in sensorDigits
516 
517  B2DEBUG(100, "Number of clusters: " << storeClusters.getEntries());
518 
519 } // event()
520 
521 
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
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
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.
Class to store a single element of a relation.
TO * getRelatedTo(const std::string &name="", const std::string &namedRelation="") const
Get the object to which this object has a relation.
The SVD Cluster class This class stores all information about reconstructed SVD clusters.
Definition: SVDCluster.h:29
float getNoise(const VxdID &sensorID, const bool &isU, const unsigned short &strip) const
This is the method for getting 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 ...
float getPeakTime(const VxdID &sensorID, const bool &isU, const unsigned short &strip) const
Return the peaking time of the strip.
float getWidth(const VxdID &sensorID, const bool &isU, const unsigned short &strip) const
Return the width of the pulse shape for a given strip.
The SVD RecoDigit class.
Definition: SVDRecoDigit.h:43
OutputProbArray getProbabilities() const
Get signal time pdf.
Definition: SVDRecoDigit.h:144
VxdID getSensorID() const
Get the sensor ID.
Definition: SVDRecoDigit.h:98
short int getCellID() const
Get strip ID.
Definition: SVDRecoDigit.h:114
bool isUStrip() const
Get strip direction.
Definition: SVDRecoDigit.h:109
The SVD ShaperDigit class.
APVFloatSamples getSamples() const
Get array of samples.
The class holds arrays of bins and bin centers, and a wave generator object containing information on...
Definition: NNWaveFitTool.h:91
std::tuple< double, double, double > getAmplitudeChi2(const apvSamples &samples, double timeShift, double tau)
Return std::tuple with signal amplitude, its error, and chi2 of the fit.
std::tuple< double, double > getTimeShift(const nnFitterBinData &p)
Return std::tuple containing time shift and its error.
void multiply(nnFitterBinData &p, const nnFitterBinData &p1)
Multiply probabilities.
void setNetwrok(const std::string &xmlData)
Set proper network definition file.
const nnFitterBinData & getBinCenters() const
Get bin times of the network output.
Definition: NNWaveFitter.h:104
const NNWaveFitTool & getFitTool() const
Get a handle to a NNWaveFit object.
Definition: NNWaveFitter.h:98
std::string m_storeRecoDigitsName
Name of the collection to use for the SVDRecoDigits.
virtual void initialize() override
Initialize the module.
virtual void event() override
do the clustering
std::vector< const RelationElement * > RelationLookup
Container for a RelationArray Lookup table.
std::string m_relRecoDigitTrueHitName
Name of the relation between SVDRecoDigits and SVDTrueHits.
double m_cutCluster
Cluster cut in units of m_elNoise.
std::string m_storeTrueHitsName
Name of the collection to use for the SVDTrueHits.
std::string m_relRecoDigitMCParticleName
Name of the relation between SVDRecoDigits and MCParticles.
std::string m_timeFitterName
Name of the time fitter (db label)
void fillRelationMap(const RelationLookup &lookup, std::map< unsigned int, float > &relation, unsigned int index)
Add the relation from a given SVDRecoDigit index to a map.
std::string m_storeMCParticlesName
Name of the collection to use for the MCParticles.
RelationLookup m_trueRelation
Lookup table for SVDRecoDigit->SVDTrueHit relation.
SVDPulseShapeCalibrations m_pulseShapeCal
Calibrations: pusle shape and gain.
SVDNoiseCalibrations m_noiseCal
Calibrations: noise.
int m_sizeHeadTail
Size of the cluster at which we switch from Center of Gravity to Analog Head Tail.
void createRelationLookup(const RelationArray &relation, RelationLookup &lookup, size_t digits)
Create lookup maps for relations We do not use the RelationIndex as we know much more about the relat...
std::string m_storeClustersName
Name of the collection to use for the SVDClusters.
double m_cutSeed
Seed cut in units of m_elNoise.
std::string m_relClusterMCParticleName
Name of the relation between SVDClusters and MCParticles.
RelationLookup m_mcRelation
Lookup table for SVDRecoDigit->MCParticle relation.
std::string m_relClusterRecoDigitName
Name of the relation between SVDClusters and SVDRecoDigits.
bool m_calibratePeak
Use peak widths and peak time calibrations? Unitl this is also simulated, set to true only for testbe...
double m_cutAdjacent
Noise (cluster member) cut in units of m_elNoise.
std::string m_relClusterTrueHitName
Name of the relation between SVDClusters and SVDTrueHits.
Specific implementation of SensorInfo for SVD Sensors which provides additional sensor specific infor...
Definition: SensorInfo.h:25
const ROOT::Math::XYZVector & getLorentzShift(double uCoord, double vCoord) const
Calculate Lorentz shift along a given coordinate in a magnetic field at a given position.
Definition: SensorInfo.cc:104
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
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
void clear() override
Delete all entries in this array.
Definition: StoreArray.h:207
static const SensorInfoBase & get(Belle2::VxdID id)
Return a reference to the SensorInfo of a given SensorID.
Definition: GeoCache.h:139
double getVCellPosition(int vID) const
Return the position of a specific strip/pixel in v direction.
double getUPitch(double v=0) const
Return the pitch of the sensor.
double getUCellPosition(int uID, int vID=-1) const
Return the position of a specific strip/pixel in u direction.
double getVPitch(double v=0) const
Return the pitch of the sensor.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
void setSegmentNumber(baseType segment)
Set the sensor segment.
Definition: VxdID.h:113
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
void zeroSuppress(T &a, double thr)
pass zero suppression
std::array< apvSampleBaseType, nAPVSamples > apvSamples
vector od apvSample BaseType objects
std::vector< double > nnFitterBinData
Vector of values defined for bins, such as bin times or bin probabilities.
Definition: NNWaveFitTool.h:30
Abstract base class for different kinds of events.