Belle II Software  release-08-01-10
SVDClusterizerDirectModule.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/SVDClusterizerDirectModule.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/SVDCluster.h>
21 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
22 
23 #include <svd/reconstruction/NNWaveFitTool.h>
24 
25 #include <unordered_map>
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(SVDClusterizerDirect);
39 
40 //-----------------------------------------------------------------
41 // Implementation
42 //-----------------------------------------------------------------
43 
44 SVDClusterizerDirectModule::SVDClusterizerDirectModule() : Module()
45 {
46  B2DEBUG(200, "SVDClusterizerDirectModule ctor");
47  //Set module properties
48  setDescription("Clusterize SVDShaperDigits and reconstruct hits");
50 
51  // 1. Collections.
53  "6-digits 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  addParam("SVDEventInfo", m_svdEventInfoName,
61  "SVDEventInfo 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 
82 {
83  //Register collections
88 
89  storeClusters.registerInDataStore();
90  storeShaperDigits.isRequired();
91  storeTrueHits.isOptional();
92  storeMCParticles.isOptional();
93  m_storeSVDEvtInfo.isRequired();
94 
95  if (!m_storeSVDEvtInfo.isOptional(m_svdEventInfoName)) m_svdEventInfoName = "SVDEventInfoSim";
97 
98  RelationArray relClusterShaperDigits(storeClusters, storeShaperDigits);
99  RelationArray relClusterTrueHits(storeClusters, storeTrueHits);
100  RelationArray relClusterMCParticles(storeClusters, storeMCParticles);
101  RelationArray relShaperDigitTrueHits(storeShaperDigits, storeTrueHits);
102  RelationArray relShaperDigitMCParticles(storeShaperDigits, storeMCParticles);
103 
104  relClusterShaperDigits.registerInDataStore();
105  //Relations to simulation objects only if the ancestor relations exist
106  if (relShaperDigitTrueHits.isOptional())
107  relClusterTrueHits.registerInDataStore();
108  if (relShaperDigitMCParticles.isOptional())
109  relClusterMCParticles.registerInDataStore();
110 
111  //Store names to speed up creation later
112  m_storeClustersName = storeClusters.getName();
113  m_storeShaperDigitsName = storeShaperDigits.getName();
114  m_storeTrueHitsName = storeTrueHits.getName();
115  m_storeMCParticlesName = storeMCParticles.getName();
116 
117  m_relClusterShaperDigitName = relClusterShaperDigits.getName();
118  m_relClusterTrueHitName = relClusterTrueHits.getName();
119  m_relClusterMCParticleName = relClusterMCParticles.getName();
120  m_relShaperDigitTrueHitName = relShaperDigitTrueHits.getName();
121  m_relShaperDigitMCParticleName = relShaperDigitMCParticles.getName();
122 
123  B2INFO(" 1. COLLECTIONS:");
124  B2INFO(" --> MCParticles: " << m_storeMCParticlesName);
125  B2INFO(" --> Digits: " << m_storeShaperDigitsName);
126  B2INFO(" --> Clusters: " << m_storeClustersName);
127  B2INFO(" --> TrueHits: " << m_storeTrueHitsName);
128  B2INFO(" --> DigitMCRel: " << m_relShaperDigitMCParticleName);
129  B2INFO(" --> ClusterMCRel: " << m_relClusterMCParticleName);
130  B2INFO(" --> ClusterDigitRel: " << m_relClusterShaperDigitName);
131  B2INFO(" --> DigitTrueRel: " << m_relShaperDigitTrueHitName);
132  B2INFO(" --> ClusterTrueRel: " << m_relClusterTrueHitName);
133  B2INFO(" 2. CALIBRATION DATA:");
134  B2INFO(" --> Time NN: " << m_timeFitterName);
135  B2INFO(" 4. CLUSTERING:");
136  B2INFO(" --> Neighbour cut: " << m_cutAdjacent);
137  B2INFO(" --> Seed cut: " << m_cutSeed);
138  B2INFO(" --> Cluster charge cut: " << m_cutCluster);
139  B2INFO(" --> HT for clusters >: " << m_sizeHeadTail);
140 
141  // Properly initialize the NN time fitter
142  // FIXME: Should be moved to beginRun
143  // FIXME: No support for 3/6 sample switching within a run/event
145  m_fitter.setNetwrok(dbXml->m_data);
146 }
147 
149  RelationLookup& lookup, size_t digits)
150 {
151  lookup.clear();
152  //If we don't have a relation we don't build a lookuptable
153  if (!relation) return;
154  //Resize to number of digits and set all values
155  lookup.resize(digits);
156  for (const auto& element : relation) {
157  lookup[element.getFromIndex()] = &element;
158  }
159 }
160 
162  std::map<unsigned int, float>& relation, unsigned int index)
163 {
164  //If the lookup table is not empty and the element is set
165  if (!lookup.empty() && lookup[index]) {
166  const RelationElement& element = *lookup[index];
167  const unsigned int size = element.getSize();
168  //Add all Relations to the map
169  for (unsigned int i = 0; i < size; ++i) {
170  //negative weights are from ignored particles, we don't like them and
171  //thus ignore them :D
172  if (element.getWeight(i) < 0) continue;
173  relation[element.getToIndex(i)] += element.getWeight(i);
174  }
175  }
176 }
177 
179 {
180 
181  const StoreArray<SVDShaperDigit> storeShaperDigits(m_storeShaperDigitsName);
182  // If no digits or no SVDEventInfo, nothing to do
183  if (!storeShaperDigits || !storeShaperDigits.getEntries() || !m_storeSVDEvtInfo.isValid()) return;
184 
185  SVDModeByte modeByte = m_storeSVDEvtInfo->getModeByte();
186 
187  size_t nDigits = storeShaperDigits.getEntries();
188  B2DEBUG(90, "Initial size of StoreDigits array: " << nDigits);
189 
190  const StoreArray<MCParticle> storeMCParticles(m_storeMCParticlesName);
191  const StoreArray<SVDTrueHit> storeTrueHits(m_storeTrueHitsName);
192 
193  RelationArray relShaperDigitMCParticle(storeShaperDigits, storeMCParticles, m_relShaperDigitMCParticleName);
194  RelationArray relShaperDigitTrueHit(storeShaperDigits, storeTrueHits, m_relShaperDigitTrueHitName);
195 
197  storeClusters.clear();
198 
199  RelationArray relClusterMCParticle(storeClusters, storeMCParticles,
201  if (relClusterMCParticle) relClusterMCParticle.clear();
202 
203  RelationArray relClusterShaperDigit(storeClusters, storeShaperDigits,
205  if (relClusterShaperDigit) relClusterShaperDigit.clear();
206 
207  RelationArray relClusterTrueHit(storeClusters, storeTrueHits,
209  if (relClusterTrueHit) relClusterTrueHit.clear();
210 
211  //Build lookup tables for relations
212  createRelationLookup(relShaperDigitMCParticle, m_mcRelation, nDigits);
213  createRelationLookup(relShaperDigitTrueHit, m_trueRelation, nDigits);
214 
215  // Create fit tool object
216  NNWaveFitTool fitTool = m_fitter.getFitTool();
217 
218  // I. Group digits by sensor/side.
219  vector<pair<unsigned short, unsigned short> > sensorDigits;
220  VxdID lastSensorID(0);
221  size_t firstSensorDigit = 0;
222  for (size_t iDigit = 0; iDigit < nDigits; ++iDigit) {
223  const SVDShaperDigit& adigit = *storeShaperDigits[iDigit];
224  VxdID sensorID = adigit.getSensorID();
225  sensorID.setSegmentNumber(adigit.isUStrip() ? 1 : 0);
226  if (sensorID != lastSensorID) { // we have a new sensor side
227  sensorDigits.push_back(make_pair(firstSensorDigit, iDigit));
228  firstSensorDigit = iDigit;
229  lastSensorID = sensorID;
230  }
231  }
232  // save last VxdID
233  sensorDigits.push_back(make_pair(firstSensorDigit, nDigits));
234 
235  // ICYCLE OVER SENSORS
236  for (auto id_indices : sensorDigits) {
237  // Retrieve parameters from sensorDigits
238  unsigned int firstDigit = id_indices.first;
239  unsigned int lastDigit = id_indices.second;
240  // Get VXDID from the first digit
241  const SVDShaperDigit& sampleDigit = *storeShaperDigits[firstDigit];
242  VxdID sensorID = sampleDigit.getSensorID();
243  bool isU = sampleDigit.isUStrip();
244 
245  // Retrieve sensor parameters from GeoCache
246  const SensorInfo& info = dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(sensorID));
247  double pitch = isU ? info.getUPitch() : info.getVPitch();
248 
249  // 4. Cycle through digits and form clusters on the way.
250 
251  // Identify contiguous groups of strips
252  // We maintain two pointers: firstDigit and lastDigit. We also keep track of last seen
253  // strip number.
254  // We start with firstDigit = lastDigit = 0
255  // If there is a gap in strip numbers or the current digit/strip is invalid, we save the
256  // current group (fd, cd), unless empty, and set fd = cd.
257  // If current strip is valid, we include it: ld = cd+1.
258 
259  vector<pair<size_t, size_t> > stripGroups;
260  unordered_map<size_t, apvSamples> storedNormedSamples;
261  size_t firstClusterDigit = firstDigit;
262  size_t lastClusterDigit = firstDigit;
263  short lastStrip = -2;
264 
265  B2DEBUG(300, "Clustering digits " << firstDigit << " to " << lastDigit);
266  for (size_t iDigit = firstDigit; iDigit < lastDigit; ++iDigit) {
267 
268  const SVDShaperDigit& digit = *storeShaperDigits[iDigit];
269  unsigned short currentStrip = digit.getCellID();
270  B2DEBUG(300, "Digit " << iDigit << ", strip: " << currentStrip << ", lastStrip: " << lastStrip);
271  B2DEBUG(300, "First CD: " << firstClusterDigit << " Last CD: " << lastClusterDigit);
272  // Get calibration
273  float stripNoiseADU = m_noiseCal.getNoise(sensorID, isU, currentStrip);
274 
275  // If the strip is not masked away, save normalized samples (sample/stripNoise)
276  apvSamples normedSamples;
277 
278  auto samples = digit.getSamples();
279  transform(samples.begin(), samples.end(), normedSamples.begin(),
280  bind2nd(divides<float>(), stripNoiseADU));
281  bool validDigit = pass3Samples(normedSamples, m_cutAdjacent);
282 
283  // If this is a valid digit, store normed samples.
284  // It's not just that we don't have to normalize again - we don't need other data than strip
285  // number and normed samples from the digits!
286  zeroSuppress(normedSamples, m_cutAdjacent);
287  storedNormedSamples.insert(make_pair(iDigit, normedSamples));
288 
289 
290  // See if we have a gap in strip numbers.
291  bool consecutive = ((currentStrip - lastStrip) == 1);
292  lastStrip = currentStrip;
293 
294  B2DEBUG(300, (validDigit ? "Valid " : "Invalid ") << (consecutive ? "consecutive" : "gap"));
295 
296  // If this is not a valid digit or we have a gap, we save if there is something to save
297  if ((!validDigit || !consecutive) && (firstClusterDigit < lastClusterDigit)) {
298  B2DEBUG(300, "Saving (" << firstClusterDigit << ", " << lastClusterDigit << ")");
299  stripGroups.emplace_back(firstClusterDigit, lastClusterDigit);
300  }
301 
302  // Update counters
303  if (validDigit) {
304  if (consecutive) {// consecutive and valid : include in cluster
305  lastClusterDigit = iDigit + 1;
306  } else { // valid after a gap = new cluster
307  firstClusterDigit = iDigit;
308  lastClusterDigit = iDigit + 1;
309  }
310  } else { // invalid digit : skip
311  firstClusterDigit = iDigit + 1;
312  lastClusterDigit = iDigit + 1;
313  }
314  } // for digits
315  // save last if any
316  if (firstClusterDigit < lastClusterDigit) {
317  B2DEBUG(300, "Saving (" << firstClusterDigit << ", " << lastDigit << ")");
318  stripGroups.emplace_back(firstClusterDigit, lastDigit);
319  }
320 
321  ostringstream os;
322  os << sensorID << "NormedSamples: " << endl;
323  for (auto item : storedNormedSamples) {
324  os << item.first << ": ";
325  copy(item.second.begin(), item.second.end(), ostream_iterator<double>(os, " "));
326  os << endl;
327  }
328  os << "StripGroups: " << endl;
329  for (auto item : stripGroups) {
330  os << "(" << item.first << ", " << item.second << "), ";
331  }
332  B2DEBUG(300, os.str());
333 
334  // 5. Now we loop through stripGroups and form clusters.
335  // We are still keeping digit indices, so we are keeping hold on the relations as wwell.
336 
337  // FIXME: Pretty stupid. There should be ClusterCandidate type to hold all this, as
338  // well as normed samples. It could calculate a lot of things by itself and make the
339  // code cleaner.
340  vector<unsigned short> stripNumbers;
341  vector<float> stripPositions;
342  vector<float> stripNoises;
343  vector<float> timeShifts;
344  vector<float> waveWidths;
345 
346  for (auto clusterBounds : stripGroups) {
347 
348  unsigned short clusterSize = clusterBounds.second - clusterBounds.first;
349  assert(clusterSize > 0);
350 
351  stripNumbers.clear();
352  stripPositions.clear();
353  stripNoises.clear();
354  timeShifts.clear();
355  waveWidths.clear();
356 
357  for (size_t iDigit = clusterBounds.first; iDigit < clusterBounds.second; ++iDigit) {
358  // Now we take the normed samples and calculate the common
359  // cluster probability distribution and, from it, the time and its error, and
360  // the probability of the hit being from beam background.
361  const SVDShaperDigit& digit = *storeShaperDigits[iDigit];
362 
363  unsigned short stripNo = digit.getCellID();
364  stripNumbers.push_back(stripNo);
365  // Is the calibrations interface sensible?
366  double stripNoiseADU = m_noiseCal.getNoise(sensorID, isU, stripNo);
367  stripNoises.push_back(
368  m_pulseShapeCal.getChargeFromADC(sensorID, isU, stripNo, stripNoiseADU)
369  );
370  // Some calibrations magic.
371  // FIXME: Only use calibration on real data. Until simulations correspond to
372  // default calibrtion, we cannot use it.
373  double peakWidth = 270;
374  double timeShift = isU ? 2.5 : -2.2;
375  if (m_calibratePeak) {
376  peakWidth = 1.988 * m_pulseShapeCal.getWidth(sensorID, isU, stripNo);
377  timeShift = m_pulseShapeCal.getPeakTime(sensorID, isU, stripNo)
378  - 0.25 * peakWidth;
379  }
380  // Correct with trigger bin information
381  const double triggerBinSep = 4 * 1.96516; //in ns
382  double apvPhase = triggerBinSep * (0.5 + static_cast<int>(modeByte.getTriggerBin()));
383  timeShift = timeShift + apvPhase;
384  waveWidths.push_back(peakWidth);
385  timeShifts.push_back(timeShift);
386  stripPositions.push_back(
387  isU ? info.getUCellPosition(stripNo) : info.getVCellPosition(stripNo)
388  );
389  stripPositions.push_back(
390  isU ? info.getUCellPosition(stripNo) : info.getVCellPosition(stripNo)
391  );
392  }
393  // The formulas don't take into account differences in strip noises. So we take RMS
394  // strip noise as cluster noise.
395  // cluster noise is in e-!
396  float clusterNoise = sqrt(
397  1.0 / clusterSize
398  * inner_product(stripNoises.begin(), stripNoises.end(), stripNoises.begin(), 0.0)
399  );
400  B2DEBUG(200, "RMS cluster noise: " << clusterNoise);
401 
402  // This will hold component pdfs. We may want to rememeber them to study
403  // homogeneity of cluster times.
404  shared_ptr<nnFitterBinData> pStrip;
405  // This will aggregate the components pdfs to get cluster time pdf
406  nnFitterBinData pCluster(m_fitter.getBinCenters().size());
407  fill(pCluster.begin(), pCluster.end(), double(1.0));
408  for (size_t iClusterStrip = 0; iClusterStrip < clusterSize; ++iClusterStrip) {
409  size_t iDigit = clusterBounds.first + iClusterStrip;
410  ostringstream os1;
411  os1 << "Input to NNFitter: iDigit = " << iDigit << endl << "Samples: ";
412  copy(storedNormedSamples[iDigit].begin(), storedNormedSamples[iDigit].end(),
413  ostream_iterator<double>(os1, " "));
414  os1 << endl;
415  pStrip = m_fitter.getFit(storedNormedSamples[iDigit], waveWidths[iClusterStrip]);
416  os1 << "Output from NNWaveFitter: " << endl;
417  copy(pStrip->begin(), pStrip->end(), ostream_iterator<double>(os1, " "));
418  os1 << endl;
419  // Apply strip time shift to pdf
420  fitTool.shiftInTime(*pStrip, -timeShifts[iClusterStrip]);
421  fitTool.multiply(pCluster, *pStrip);
422  os1 << "Accummulated: " << endl;
423  copy(pCluster.begin(), pCluster.end(), ostream_iterator<double>(os1, " "));
424  B2DEBUG(200, os1.str());
425  }
426  // We can now calculate clsuter time and its error.
427  double clusterTime, clusterTimeErr;
428  tie(clusterTime, clusterTimeErr) = fitTool.getTimeShift(pCluster);
429  B2DEBUG(200, "Time: " << clusterTime << " +/- " << clusterTimeErr);
430  // Now we have the cluster time pdf, so we can calculate amplitudes.
431  // In the next cycle thrugh cluster's digits, we calculate ampltidues and their
432  // errors.
433  vector<double> stripAmplitudes(stripNoises.size());
434  vector<double> stripAmplitudeErrors(stripNoises.size());
435  double clusterChi2 = 0.0;
436  for (size_t iClusterStrip = 0; iClusterStrip < clusterSize; ++iClusterStrip) {
437  size_t iDigit = clusterBounds.first + iClusterStrip;
438  double snAmp, snAmpError, chi2;
439  tie(snAmp, snAmpError, chi2) =
440  fitTool.getAmplitudeChi2(storedNormedSamples[iDigit], clusterTime, waveWidths[iClusterStrip]);
441  // We have to re-normalize: Multiply amplitudes in SN units by noises in electrons.
442  stripAmplitudes[iClusterStrip] =
443  stripNoises[iClusterStrip] * snAmp;
444  stripAmplitudeErrors[iClusterStrip] =
445  stripNoises[iClusterStrip] * snAmpError;
446  clusterChi2 += chi2;
447  B2DEBUG(200, "Digit " << iDigit << " Noise: " << stripNoises[iClusterStrip]
448  << " Amplitude: " << stripAmplitudes[iClusterStrip]
449  << " +/- " << stripAmplitudeErrors[iClusterStrip]
450  << " Chi2: " << chi2
451  );
452  }
453  // Cluster charge and S/N
454  float clusterCharge = accumulate(stripAmplitudes.begin(), stripAmplitudes.end(), 0.0);
455  float clusterChargeError = sqrt(
456  inner_product(stripAmplitudeErrors.begin(), stripAmplitudeErrors.end(),
457  stripAmplitudeErrors.begin(), 0.0)
458  );
459  float clusterSN = (clusterChargeError > 0) ? clusterCharge / clusterChargeError : clusterCharge;
460  clusterChi2 /= clusterSize;
461  // Cluster seed
462  size_t seedIndex = distance(stripAmplitudes.begin(), max_element(
463  stripAmplitudes.begin(), stripAmplitudes.end()));
464  //unsigned short clusterSeedStrip = stripNumbers[seedIndex];
465  float clusterSeedCharge = stripAmplitudes[seedIndex];
466  B2DEBUG(200, "Cluster parameters:");
467  B2DEBUG(200, "Charge: " << clusterCharge << " +/- " << clusterChargeError);
468  B2DEBUG(200, "Seed: " << clusterSeedCharge << " +/- " << stripAmplitudeErrors[seedIndex]);
469  B2DEBUG(200, "S/N: " << clusterSN);
470 
471 
472  // Hit position
473  float clusterPosition, clusterPositionError;
474 
475  // Now censoring:
476  // NB: We don't censor strip charges again. The requirement of 3 consecutive samples
477  // above threshold is a good enough safeguard.
478  if ((clusterCharge < clusterNoise * m_cutCluster) || (clusterSeedCharge < clusterNoise * m_cutSeed))
479  continue;
480 
481  if (clusterSize < m_sizeHeadTail) { // centre of gravity
482  clusterPosition = 1.0 / clusterCharge * inner_product(
483  stripAmplitudes.begin(), stripAmplitudes.end(), stripPositions.begin(), 0.0
484  );
485  // Strip charge equal to zero-suppression threshold
486  float phantomCharge = m_cutAdjacent * clusterNoise;
487  if (clusterSize == 1) {
488  clusterPositionError = pitch * phantomCharge / (clusterCharge + phantomCharge);
489  } else {
490  clusterPositionError = pitch * phantomCharge / clusterCharge;
491  }
492  } else { // Head-tail
493  float leftStripCharge = stripAmplitudes.front();
494  float leftPos = stripPositions.front();
495  float rightStripCharge = stripAmplitudes.back();
496  float rightPos = stripPositions.back();
497  float centreCharge = (clusterCharge - leftStripCharge - rightStripCharge) / (clusterSize - 2);
498  leftStripCharge = (leftStripCharge < centreCharge) ? leftStripCharge : centreCharge;
499  rightStripCharge = (rightStripCharge < centreCharge) ? rightStripCharge : centreCharge;
500  clusterPosition = 0.5 * (leftPos + rightPos)
501  + 0.5 * (rightStripCharge - leftStripCharge) / centreCharge * pitch;
502  float sn = centreCharge / m_cutAdjacent / clusterNoise;
503  // Rough estimates of Landau noise
504  float landauHead = leftStripCharge / centreCharge;
505  double landauTail = rightStripCharge / centreCharge;
506  clusterPositionError = 0.5 * pitch * sqrt(1.0 / sn / sn
507  + 0.5 * landauHead * landauHead + 0.5 * landauTail * landauTail);
508  }
509  //Lorentz shift correction
510  clusterPosition -= info.getLorentzShift(isU, clusterPosition);
511 
512  // Finally, we save the cluster and its relations.
513  map<unsigned int, float> mc_relations;
514  map<unsigned int, float> truehit_relations;
515  vector<pair<unsigned int, float> > digit_weights;
516  digit_weights.reserve(clusterSize);
517 
518  for (size_t iDigit = clusterBounds.first; iDigit < clusterBounds.second; ++iDigit) {
519  // Store relations to MCParticles and SVDTrueHits
520  fillRelationMap(m_mcRelation, mc_relations, iDigit);
521  fillRelationMap(m_trueRelation, truehit_relations, iDigit);
522  //Add digit to the Cluster->Digit relation list
523  digit_weights.emplace_back(iDigit, stripAmplitudes[iDigit - clusterBounds.first]);
524  }
525 
526  //Store the cluster into Datastore ...
527  int clsIndex = storeClusters.getEntries();
528  VxdID clusterSensorID = sensorID;
529  clusterSensorID.setSegmentNumber(0);
530  storeClusters.appendNew(
531  SVDCluster(sensorID, isU, clusterPosition, clusterPositionError, clusterTime,
532  clusterTimeErr, clusterCharge, clusterSeedCharge, clusterSize, clusterSN, clusterChi2)
533  );
534 
535  //Create relations to the cluster
536  if (!mc_relations.empty()) {
537  relClusterMCParticle.add(clsIndex, mc_relations.begin(), mc_relations.end());
538  }
539  if (!truehit_relations.empty()) {
540  relClusterTrueHit.add(clsIndex, truehit_relations.begin(), truehit_relations.end());
541  }
542  relClusterShaperDigit.add(clsIndex, digit_weights.begin(), digit_weights.end());
543  } // CYCLE OVER CLUSTERS for stripGroups
544 
545  } // CYCLE OVER SENSORS for items in sensorDigits
546 
547  B2DEBUG(100, "Number of clusters: " << storeClusters.getEntries());
548 
549 } // event()
550 
551 
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.
The SVD Cluster class This class stores all information about reconstructed SVD clusters.
Definition: SVDCluster.h:29
Class to store SVD mode information.
Definition: SVDModeByte.h:69
baseType getTriggerBin() const
Get the triggerBin id.
Definition: SVDModeByte.h:140
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 ShaperDigit class.
VxdID getSensorID() const
Get the sensor ID.
APVFloatSamples getSamples() const
Get array of samples.
short int getCellID() const
Get strip ID.
bool isUStrip() const
Get strip direction.
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 shiftInTime(nnFitterBinData &p, double timeShift)
Shift the probability array in time.
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::shared_ptr< nnFitterBinData > getFit(const apvSamples &samples, double tau)
Fitting method Send data and get rseult structure.
std::string m_relShaperDigitMCParticleName
Name of the relation between SVDShaperDigits and MCParticles.
virtual void initialize() override
Initialize the module.
std::string m_storeShaperDigitsName
Name of the collection to use for the SVDShaperDigits.
virtual void event() override
do the clustering
std::vector< const RelationElement * > RelationLookup
Container for a RelationArray Lookup table.
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_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 SVDShaperDigit index to a map.
std::string m_storeMCParticlesName
Name of the collection to use for the MCParticles.
std::string m_relShaperDigitTrueHitName
Name of the relation between SVDShaperDigits and SVDTrueHits.
RelationLookup m_trueRelation
Lookup table for SVDShaperDigit->SVDTrueHit relation.
SVDPulseShapeCalibrations m_pulseShapeCal
Calibrations: pusle shape and gain.
std::string m_svdEventInfoName
Name of the SVDEventInfo object.
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_relClusterShaperDigitName
Name of the relation between SVDClusters and SVDShaperDigits.
std::string m_relClusterMCParticleName
Name of the relation between SVDClusters and MCParticles.
RelationLookup m_mcRelation
Lookup table for SVDShaperDigit->MCParticle relation.
StoreObjPtr< SVDEventInfo > m_storeSVDEvtInfo
Storage for SVDEventInfo object.
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
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
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
bool pass3Samples(const T &a, double thr)
pass 3-samples
Abstract base class for different kinds of events.