Belle II Software release-09-00-00
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
31using namespace std;
32using namespace Belle2;
33using namespace Belle2::SVD;
34
35//-----------------------------------------------------------------
36// Register the Module
37//-----------------------------------------------------------------
38REG_MODULE(SVDClusterizerDirect);
39
40//-----------------------------------------------------------------
41// Implementation
42//-----------------------------------------------------------------
43
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
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
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 NNWaveFitTool & getFitTool() const
Get a handle to a NNWaveFit object.
Definition: NNWaveFitter.h:98
const nnFitterBinData & getBinCenters() const
Get bin times of the network output.
Definition: NNWaveFitter.h:104
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.
SVDClusterizerDirectModule()
Constructor defining the parameters.
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
const std::string & getName() const
Return name under which the object is saved in the DataStore.
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.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
void clear() override
Delete all entries in this array.
Definition: StoreArray.h:207
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
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
void zeroSuppress(T &a, double thr)
pass zero suppression
bool pass3Samples(const T &a, double thr)
pass 3-samples
Abstract base class for different kinds of events.
STL namespace.