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