Belle II Software  release-06-01-15
SVDCoGTimeEstimatorModule.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/SVDCoGTimeEstimatorModule.h>
10 
11 using namespace Belle2;
12 using namespace std;
13 
14 //-----------------------------------------------------------------
15 // Register the Module
16 //-----------------------------------------------------------------
17 REG_MODULE(SVDCoGTimeEstimator)
18 
19 //-----------------------------------------------------------------
20 // Implementation
21 //-----------------------------------------------------------------
22 
24 {
25  setDescription("From SVDShaperDigit to SVDRecoDigit. Strip charge is evaluated as the max of the 6 samples; hit time is evaluated as a corrected Centre of Gravity (CoG) time.");
26  setPropertyFlags(c_ParallelProcessingCertified);
27 
28  addParam("SVDEventInfo", m_svdEventInfoName,
29  "SVDEventInfo name", string(""));
30  addParam("ShaperDigits", m_storeShaperDigitsName,
31  "ShaperDigits collection name", string(""));
32  addParam("RecoDigits", m_storeRecoDigitsName,
33  "RecoDigits collection name", string(""));
34  addParam("StripPeakTimeCorrection", m_corrPeakTime,
35  "Correct for the different peaking times of the strips, obtained from local run calibration", true);
36  addParam("CalibrationWithEventT0", m_calEventT0,
37  "Use the timing informations of the EventT0 in order to calibrate the CoG.",
38  true);
39 
40 }
41 
42 
44 {
45 }
46 
47 
49 {
50  m_storeTrueHits.isOptional();
51  m_storeMCParticles.isOptional();
52 
53  //Inizialization of needed store array
54  m_storeShaper.isRequired(m_storeShaperDigitsName);
55 
56  if (!m_storeSVDEvtInfo.isOptional(m_svdEventInfoName)) m_svdEventInfoName = "SVDEventInfoSim";
57  m_storeSVDEvtInfo.isRequired(m_svdEventInfoName);
58 
59  //Initialize the new RecoDigit
60  m_storeReco.registerInDataStore(m_storeRecoDigitsName, DataStore::c_ErrorIfAlreadyRegistered);
61 
62  RelationArray relRecoDigitShaperDigits(m_storeReco, m_storeShaper);
63  relRecoDigitShaperDigits.registerInDataStore();
64  RelationArray relRecoDigitTrueHits(m_storeReco, m_storeTrueHits);
65  RelationArray relRecoDigitMCParticles(m_storeReco, m_storeMCParticles);
66  RelationArray relShaperDigitTrueHits(m_storeShaper, m_storeTrueHits);
67  RelationArray relShaperDigitMCParticles(m_storeShaper, m_storeMCParticles);
68 
69  //Relations to simulation objects only if the ancestor relations exist
70  if (relShaperDigitTrueHits.isOptional())
71  relRecoDigitTrueHits.registerInDataStore();
72  if (relShaperDigitMCParticles.isOptional())
73  relRecoDigitMCParticles.registerInDataStore();
74 
75  //Store names to speed up creation later
76  m_storeTrueHitsName = m_storeTrueHits.getName();
77  m_storeMCParticlesName = m_storeMCParticles.getName();
78 
79  m_relRecoDigitShaperDigitName = relRecoDigitShaperDigits.getName();
80  m_relRecoDigitTrueHitName = relRecoDigitTrueHits.getName();
81  m_relRecoDigitMCParticleName = relRecoDigitMCParticles.getName();
82  m_relShaperDigitTrueHitName = relShaperDigitTrueHits.getName();
83  m_relShaperDigitMCParticleName = relShaperDigitMCParticles.getName();
84 
85  B2DEBUG(25, " 1. COLLECTIONS:");
86  B2DEBUG(25, " --> MCParticles: " << m_storeMCParticlesName);
87  B2DEBUG(25, " --> Digits: " << m_storeShaperDigitsName);
88  B2DEBUG(25, " --> RecoDigits: " << m_storeRecoDigitsName);
89  B2DEBUG(25, " --> TrueHits: " << m_storeTrueHitsName);
90  B2DEBUG(25, " --> DigitMCRel: " << m_relShaperDigitMCParticleName);
91  B2DEBUG(25, " --> RecoDigitMCRel: " << m_relRecoDigitMCParticleName);
92  B2DEBUG(25, " --> RecoDigitDigitRel: " << m_relRecoDigitShaperDigitName);
93  B2DEBUG(25, " --> DigitTrueRel: " << m_relShaperDigitTrueHitName);
94  B2DEBUG(25, " --> RecoDigitTrueRel: " << m_relRecoDigitTrueHitName);
95 
96 }
98 {
99 }
100 
101 
103 {
104 
106  std::vector<float> probabilities = {0.5};
107 
108  // If no digits or no SVDEventInfo, nothing to do
109  if (!m_storeShaper || !m_storeShaper.getEntries() || !m_storeSVDEvtInfo.isValid()) return;
110 
111  SVDModeByte modeByte = m_storeSVDEvtInfo->getModeByte();
112  size_t nDigits = m_storeShaper.getEntries();
113 
114  RelationArray relRecoDigitShaperDigit(m_storeReco, m_storeShaper,
115  m_relRecoDigitShaperDigitName);
116  if (relRecoDigitShaperDigit) relRecoDigitShaperDigit.clear();
117 
118 
119  RelationArray relShaperDigitMCParticle(m_storeShaper, m_storeMCParticles, m_relShaperDigitMCParticleName);
120  RelationArray relShaperDigitTrueHit(m_storeShaper, m_storeTrueHits, m_relShaperDigitTrueHitName);
121 
122  RelationArray relRecoDigitMCParticle(m_storeReco, m_storeMCParticles,
123  m_relRecoDigitMCParticleName);
124  if (relRecoDigitMCParticle) relRecoDigitMCParticle.clear();
125 
126 
127  RelationArray relRecoDigitTrueHit(m_storeReco, m_storeTrueHits,
128  m_relRecoDigitTrueHitName);
129  if (relRecoDigitTrueHit) relRecoDigitTrueHit.clear();
130 
131  //Build lookup tables for relations
132  createRelationLookup(relShaperDigitMCParticle, m_mcRelation, nDigits);
133  createRelationLookup(relShaperDigitTrueHit, m_trueRelation, nDigits);
134 
135  //start loop on SVDSHaperDigits
137 
138  m_NumberOfAPVSamples = m_storeSVDEvtInfo->getNSamples();
139 
140  B2DEBUG(25, "number of APV samples = " << m_NumberOfAPVSamples);
141 
142  for (const SVDShaperDigit& shaper : m_storeShaper) {
143 
144  m_StopCreationReco = false;
145 
146 
147  if (m_StopCreationReco)
148  continue;
149 
150  samples_vec = shaper.getSamples();
151 
152  //retrieve the VxdID, sensor and cellID of the current RecoDigit
153  VxdID thisSensorID = shaper.getSensorID();
154  bool thisSide = shaper.isUStrip();
155  int thisCellID = shaper.getCellID();
156 
157  //call of the functions doomed to calculate the required quantities
158  m_weightedMeanTime = CalculateWeightedMeanPeakTime(samples_vec);
159  if (m_StopCreationReco)
160  continue;
161  m_amplitude = CalculateAmplitude(samples_vec);
162  m_amplitudeError = CalculateAmplitudeError(thisSensorID, thisSide, thisCellID);
163 
164  //need the amplitudeError in ADC as the noise of the strip to computer the error on time
165  m_weightedMeanTimeError = CalculateWeightedMeanPeakTimeError(samples_vec);
166 
167  m_chi2 = CalculateChi2();
168 
169  //check too high ADC
170  if (m_amplitude > 255)
171  B2DEBUG(25, "ERROR: m_amplitude = " << m_amplitude << ", should be <= 255");
172 
173  //CALIBRATION
174  //convert ADC into #e- and apply offset to shift estimated peak time to hit time (to be completed)
175  m_amplitude = m_PulseShapeCal.getChargeFromADC(thisSensorID, thisSide, thisCellID, m_amplitude);
176  m_amplitudeError = m_PulseShapeCal.getChargeFromADC(thisSensorID, thisSide, thisCellID, m_amplitudeError);
177 
178  if (m_corrPeakTime)
179  m_weightedMeanTime -= m_PulseShapeCal.getPeakTime(thisSensorID, thisSide, thisCellID);
180  SVDModeByte::baseType triggerBin = modeByte.getTriggerBin();
181 
182  if (m_calEventT0) {
183  m_weightedMeanTime = m_TimeCal.getCorrectedTime(thisSensorID, thisSide, thisCellID, m_weightedMeanTime, triggerBin);
184  m_weightedMeanTimeError = m_TimeCal.getCorrectedTimeError(thisSensorID, thisSide, thisCellID, m_weightedMeanTime,
185  m_weightedMeanTimeError, triggerBin);
186  }
187 
188  //check high charges and too high ADC
189  if (m_amplitude > 100000) {
190  B2DEBUG(25, "Charge = " << m_amplitude);
191  B2DEBUG(25, "corresponding ADC = " << m_PulseShapeCal.getADCFromCharge(thisSensorID, thisSide, thisCellID, m_amplitude));
192  B2DEBUG(25, "thisLayerNumber = " << thisSensorID.getLayerNumber());
193  B2DEBUG(25, "thisLadderNumber = " << thisSensorID.getLadderNumber());
194  B2DEBUG(25, "thisSensorNumber = " << thisSensorID.getSensorNumber());
195  B2DEBUG(25, "thisSide = " << thisSide);
196  B2DEBUG(25, "thisCellID = " << thisCellID);
197  B2DEBUG(25, "-----");
198  }
199 
200  //recording of the RecoDigit
201  m_storeReco.appendNew(shaper.getSensorID(), shaper.isUStrip(), shaper.getCellID(), m_amplitude, m_amplitudeError,
202  m_weightedMeanTime, m_weightedMeanTimeError, probabilities, m_chi2);
203 
204  //Add digit to the RecoDigit->ShaperDigit relation list
205  int recoDigitIndex = m_storeReco.getEntries() - 1;
206  vector<pair<unsigned int, float> > digit_weights;
207  digit_weights.reserve(1);
208  digit_weights.emplace_back(shaper.getArrayIndex(), 1.0);
209  relRecoDigitShaperDigit.add(recoDigitIndex, digit_weights.begin(), digit_weights.end());
210 
211  // Finally, we save the RecoDigit and its relations.
212  map<unsigned int, float> mc_relations;
213  map<unsigned int, float> truehit_relations;
214 
215  // Store relations to MCParticles and SVDTrueHits
216  fillRelationMap(m_mcRelation, mc_relations, shaper.getArrayIndex());
217  fillRelationMap(m_trueRelation, truehit_relations, shaper.getArrayIndex());
218 
219  //Create relations to the cluster
220  if (!mc_relations.empty()) {
221  relRecoDigitMCParticle.add(recoDigitIndex, mc_relations.begin(), mc_relations.end());
222  }
223  if (!truehit_relations.empty()) {
224  relRecoDigitTrueHit.add(recoDigitIndex, truehit_relations.begin(), truehit_relations.end());
225  }
226 
227  }
228 }
229 
230 
232 {
233 }
234 
235 
237 {
238 }
239 
240 
242 {
243  float averagetime = 0;
244  float sumAmplitudes = 0;
245  //calculate weighted average time
246  for (int k = 0; k < m_NumberOfAPVSamples; k ++) {
247  averagetime += k * samples[k];
248  sumAmplitudes += samples[k];
249  }
250  if (sumAmplitudes != 0) {
251  averagetime /= (sumAmplitudes);
252  averagetime *= m_DeltaT;
253  } else {
254  averagetime = -1;
255  m_StopCreationReco = true;
256  B2WARNING("Trying to divide by 0 (ZERO)! Sum of amplitudes is nullptr! Skipping this SVDShaperDigit!");
257  }
258 
259  return averagetime;
260 }
261 
263 {
264  float amplitude = 0;
265  //calculate amplitude
266  for (int k = 0; k < m_NumberOfAPVSamples; k ++) {
267  if (samples[k] > amplitude)
268  amplitude = samples[k];
269  }
270 
271  return amplitude;
272 }
273 
275 {
276 
277  //assuming that noise of the samples are totally UNcorrelated
278  //in MC this hypothesis is correct
279 
280  //sum of samples amplitudes
281  float Atot = 0;
282  //sum of time residuals squared
283  float tmpResSq = 0;
284 
285  for (int k = 0; k < m_NumberOfAPVSamples; k ++) {
286  Atot += samples[k];
287  tmpResSq += TMath::Power(k * m_DeltaT - m_weightedMeanTime, 2);
288  }
289 
290  return m_amplitudeError / Atot * TMath::Sqrt(tmpResSq);
291 
292 }
293 
294 float SVDCoGTimeEstimatorModule::CalculateAmplitudeError(VxdID ThisSensorID, bool ThisSide, int ThisCellID)
295 {
296  float stripnoise;
297  stripnoise = m_NoiseCal.getNoise(ThisSensorID, ThisSide, ThisCellID);
298 
299  return stripnoise;
300 }
301 
303 {
304  return 0.01;
305 }
306 
307 
308 
310  RelationLookup& lookup, size_t digits)
311 {
312  lookup.clear();
313  //If we don't have a relation we don't build a lookuptable
314  if (!relation) return;
315  //Resize to number of digits and set all values
316  lookup.resize(digits);
317  for (const auto& element : relation) {
318  lookup[element.getFromIndex()] = &element;
319  }
320 }
321 
323  std::map<unsigned int, float>& relation, unsigned int index)
324 {
325  //If the lookup table is not empty and the element is set
326  if (!lookup.empty() && lookup[index]) {
327  const RelationElement& element = *lookup[index];
328  const unsigned int size = element.getSize();
329  //Add all Relations to the map
330  for (unsigned int i = 0; i < size; ++i) {
331  //negative weights are from ignored particles, we don't like them and
332  //thus ignore them :D
333  if (element.getWeight(i) < 0) continue;
334  relation[element.getToIndex(i)] += element.getWeight(i);
335  }
336  }
337 }
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
352 
353 
354 
355 
356 
357 
358 
359 
360 
361 
362 
363 
364 
365 
366 
367 
368 
369 
@ c_ErrorIfAlreadyRegistered
If the object/array was already registered, produce an error (aborting initialisation).
Definition: DataStore.h:72
Base class for Modules.
Definition: Module.h:72
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.
This module builds the SVDRecoDigits (calibrated and fitted strips) from the SVDShaperDigits.
float CalculateAmplitudeError(VxdID ThisSensorID, bool ThisSide, int ThisCellID)
Function to calculate the amplitude error as the noise of the strip.
virtual void initialize() override
Initialize the SVDCoGTimeEstimator.
virtual void event() override
This method is the core of the SVDCoGTimeEstimator.
std::vector< const RelationElement * > RelationLookup
Container for a RelationArray Lookup table.
float CalculateAmplitude(Belle2::SVDShaperDigit::APVFloatSamples samples)
Function to calculate the amplitude of the shaper, obtained as the largest of the 6 samples.
virtual void endRun() override
This method is called if the current run ends.
virtual ~SVDCoGTimeEstimatorModule()
default destructor
virtual void terminate() override
This method is called at the end of the event processing.
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.
float CalculateWeightedMeanPeakTimeError(Belle2::SVDShaperDigit::APVFloatSamples samples)
Function to calculate the peak time error.
float CalculateChi2()
Function to calculate chi2, that is not used here, so just set at 0.01.
virtual void beginRun() override
Called when entering a new run.
void createRelationLookup(const RelationArray &relation, RelationLookup &lookup, size_t digits)
Create lookup maps for relations FIXME: This has to be significantly simplified here,...
float CalculateWeightedMeanPeakTime(Belle2::SVDShaperDigit::APVFloatSamples samples)
Function to calculate the peak time, obtained as the weighted mean of the time of the samples,...
Class to store SVD mode information.
Definition: SVDModeByte.h:69
baseType getTriggerBin() const
Get the triggerBin id.
Definition: SVDModeByte.h:140
uint8_t baseType
The base integer type for SVDModeByte.
Definition: SVDModeByte.h:72
The SVD ShaperDigit class.
std::array< APVFloatSampleType, c_nAPVSamples > APVFloatSamples
array of APVFloatSampleType objects
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.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
baseType getSensorNumber() const
Get the sensor id.
Definition: VxdID.h:100
baseType getLadderNumber() const
Get the ladder id.
Definition: VxdID.h:98
baseType getLayerNumber() const
Get the layer id.
Definition: VxdID.h:96
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.