Belle II Software  release-06-02-00
SVDSimpleClusterizerModule.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/SVDSimpleClusterizerModule.h>
10 
11 #include <framework/datastore/DataStore.h>
12 #include <framework/datastore/RelationArray.h>
13 #include <framework/datastore/RelationIndex.h>
14 #include <framework/logging/Logger.h>
15 
16 #include <svd/geometry/SensorInfo.h>
17 #include <svd/dataobjects/SVDEventInfo.h>
18 
19 using namespace std;
20 using namespace Belle2;
21 using namespace Belle2::SVD;
22 
23 
24 //-----------------------------------------------------------------
25 // Register the Module
26 //-----------------------------------------------------------------
27 REG_MODULE(SVDSimpleClusterizer)
28 
29 //-----------------------------------------------------------------
30 // Implementation
31 //-----------------------------------------------------------------
32 
34  m_cutSeed(5.0), m_cutAdjacent(3.0), m_sizeHeadTail(3), m_cutCluster(0), m_useDB(true)
35 {
36  //Set module properties
37  setDescription("Clusterize SVDRecoDigits fitted by the Center of Gravity estimator");
38  setPropertyFlags(c_ParallelProcessingCertified);
39 
40  // 1. Collections.
41  addParam("RecoDigits", m_storeRecoDigitsName,
42  "SVDRecoDigits collection name", string(""));
43  addParam("Clusters", m_storeClustersName,
44  "SVDCluster collection name", string(""));
45  addParam("SVDTrueHits", m_storeTrueHitsName,
46  "TrueHit collection name", string(""));
47  addParam("MCParticles", m_storeMCParticlesName,
48  "MCParticles collection name", string(""));
49  addParam("ShaperDigits", m_storeShaperDigitsName,
50  "SVDShaperDigits collection name",
51  string(""));//NOTE: This collection is not directly accessed in this module, but indirectly accessed through SimpleClusterCandidate to get clustered samples.
52 
53  // 2. Clustering
54  addParam("AdjacentSN", m_cutAdjacent,
55  "SN for digits to be considered for clustering", m_cutAdjacent);
56  addParam("SeedSN", m_cutSeed,
57  "SN for digits to be considered as seed", m_cutSeed);
58  addParam("HeadTailSize", m_sizeHeadTail,
59  "Cluster size at which to switch to Analog head tail algorithm", m_sizeHeadTail);
60  addParam("ClusterSN", m_cutCluster,
61  "minimum value of the SNR of the cluster", m_cutCluster);
62  addParam("timeAlgorithm", m_timeAlgorithm,
63  " int to choose time algorithm: 0 = 6-sample CoG (default for 6-sample acquisition mode), 1 = 3-sample CoG (default for 3-sample acquisition mode), 2 = 3-sample ELS",
64  m_timeAlgorithm);
65  addParam("Calibrate3SampleWithEventT0", m_calibrate3SampleWithEventT0,
66  " if true returns the calibrated time instead of the raw time for 3-sample time algorithms",
67  m_calibrate3SampleWithEventT0);
68  addParam("useDB", m_useDB,
69  "if false use clustering module parameters", m_useDB);
70  addParam("SVDEventInfoName", m_svdEventInfoSet,
71  "Set the SVDEventInfo to use", string("SVDEventInfoSim"));
72 
73 }
74 
75 void SVDSimpleClusterizerModule::initialize()
76 {
77  //Register collections
78  m_storeClusters.registerInDataStore(m_storeClustersName, DataStore::c_ErrorIfAlreadyRegistered);
79  m_storeDigits.isRequired(m_storeRecoDigitsName);
80  m_storeTrueHits.isOptional(m_storeTrueHitsName);
81  m_storeMCParticles.isOptional(m_storeMCParticlesName);
82 
83  RelationArray relClusterDigits(m_storeClusters, m_storeDigits);
84  RelationArray relClusterTrueHits(m_storeClusters, m_storeTrueHits);
85  RelationArray relClusterMCParticles(m_storeClusters, m_storeMCParticles);
86  RelationArray relDigitTrueHits(m_storeDigits, m_storeTrueHits);
87  RelationArray relDigitMCParticles(m_storeDigits, m_storeMCParticles);
88 
89  relClusterDigits.registerInDataStore();
90  //Relations to simulation objects only if the ancestor relations exist
91  if (relDigitTrueHits.isOptional())
92  relClusterTrueHits.registerInDataStore();
93  if (relDigitMCParticles.isOptional())
94  relClusterMCParticles.registerInDataStore();
95 
96  //Store names to speed up creation later
97  m_storeClustersName = m_storeClusters.getName();
98  m_storeRecoDigitsName = m_storeDigits.getName();
99  m_storeTrueHitsName = m_storeTrueHits.getName();
100  m_storeMCParticlesName = m_storeMCParticles.getName();
101 
102  m_relClusterRecoDigitName = relClusterDigits.getName();
103  m_relClusterTrueHitName = relClusterTrueHits.getName();
104  m_relClusterMCParticleName = relClusterMCParticles.getName();
105  m_relRecoDigitTrueHitName = relDigitTrueHits.getName();
106  m_relRecoDigitMCParticleName = relDigitMCParticles.getName();
107 
108  // Report:
109  B2DEBUG(1, "SVDSimpleClusterizer Parameters (in default system unit, *=cannot be set directly):");
110 
111  B2DEBUG(1, " 1. COLLECTIONS:");
112  B2DEBUG(1, " --> MCParticles: " << DataStore::arrayName<MCParticle>(m_storeMCParticlesName));
113  B2DEBUG(1, " --> SVDRecoDigits: " << DataStore::arrayName<SVDRecoDigit>(m_storeRecoDigitsName));
114  B2DEBUG(1, " --> SVDClusters: " << DataStore::arrayName<SVDCluster>(m_storeClustersName));
115  B2DEBUG(1, " --> SVDTrueHits: " << DataStore::arrayName<SVDTrueHit>(m_storeTrueHitsName));
116  B2DEBUG(1, " --> DigitMCRel: " << m_relRecoDigitMCParticleName);
117  B2DEBUG(1, " --> ClusterMCRel: " << m_relClusterMCParticleName);
118  B2DEBUG(1, " --> ClusterDigitRel: " << m_relClusterRecoDigitName);
119  B2DEBUG(1, " --> DigitTrueRel: " << m_relRecoDigitTrueHitName);
120  B2DEBUG(1, " --> ClusterTrueRel: " << m_relClusterTrueHitName);
121  B2DEBUG(1, " 2. CLUSTERING:");
122  B2DEBUG(1, " --> Neighbour cut: " << m_cutAdjacent);
123  B2DEBUG(1, " --> Seed cut: " << m_cutSeed);
124  B2DEBUG(1, " --> Size HeadTail: " << m_sizeHeadTail);
125  B2DEBUG(1, " --> SVDEventInfoName: " << m_svdEventInfoSet);
126 }
127 
128 
129 
130 void SVDSimpleClusterizerModule::event()
131 {
132  int nDigits = m_storeDigits.getEntries();
133  if (nDigits == 0)
134  return;
135 
136  m_storeClusters.clear();
137 
138  RelationArray relClusterMCParticle(m_storeClusters, m_storeMCParticles,
139  m_relClusterMCParticleName);
140  if (relClusterMCParticle) relClusterMCParticle.clear();
141 
142  RelationArray relClusterDigit(m_storeClusters, m_storeDigits,
143  m_relClusterRecoDigitName);
144  if (relClusterDigit) relClusterDigit.clear();
145 
146  RelationArray relClusterTrueHit(m_storeClusters, m_storeTrueHits,
147  m_relClusterTrueHitName);
148  if (relClusterTrueHit) relClusterTrueHit.clear();
149 
150 
151  if (m_useDB) {
152  m_cutSeed = m_ClusterCal.getMinSeedSNR(m_storeDigits[0]->getSensorID(), m_storeDigits[0]->isUStrip());
153  m_cutAdjacent = m_ClusterCal.getMinAdjSNR(m_storeDigits[0]->getSensorID(), m_storeDigits[0]->isUStrip());
154  m_cutCluster = m_ClusterCal.getMinClusterSNR(m_storeDigits[0]->getSensorID(), m_storeDigits[0]->isUStrip());
155  }
156  //create a dummy cluster just to start
157  SimpleClusterCandidate clusterCandidate(m_storeDigits[0]->getSensorID(), m_storeDigits[0]->isUStrip(),
158  m_sizeHeadTail, m_cutSeed, m_cutAdjacent, m_cutCluster, m_timeAlgorithm, m_storeShaperDigitsName, m_storeRecoDigitsName);
159 
160  //loop over the SVDRecoDigits
161  int i = 0;
162  while (i < nDigits) {
163 
164  //retrieve the VxdID, sensor and cellID of the current RecoDigit
165  VxdID thisSensorID = m_storeDigits[i]->getSensorID();
166  bool thisSide = m_storeDigits[i]->isUStrip();
167  int thisCellID = m_storeDigits[i]->getCellID();
168 
169  if (m_useDB) {
170  m_cutSeed = m_ClusterCal.getMinSeedSNR(thisSensorID, thisSide);
171  m_cutAdjacent = m_ClusterCal.getMinAdjSNR(thisSensorID, thisSide);
172  m_cutCluster = m_ClusterCal.getMinClusterSNR(thisSensorID, thisSide);
173  }
174 
175  //Ignore digits with insufficient signal
176  float thisNoise = m_NoiseCal.getNoiseInElectrons(thisSensorID, thisSide, thisCellID);
177  float thisCharge = m_storeDigits[i]->getCharge();
178  B2DEBUG(10, "Noise = " << thisNoise << " e-, Charge = " << thisCharge);
179 
180  if ((float)thisCharge / thisNoise < m_cutAdjacent) {
181  i++;
182  continue;
183  }
184 
185  //this strip has a sufficient S/N
186  stripInCluster aStrip;
187  aStrip.recoDigitIndex = i;
188  aStrip.charge = thisCharge;
189  aStrip.cellID = thisCellID;
190  aStrip.noise = thisNoise;
191  //this is the 6-sample CoG time and will be used to compute the 6-sample CoG cluster time, it will not be used for in 3-sample time algorithms:
192  aStrip.time = m_storeDigits[i]->getTime();
193  aStrip.timeError = m_storeDigits[i]->getTimeError();
194 
195  //try to add the strip to the existing cluster
196  if (! clusterCandidate.add(thisSensorID, thisSide, aStrip)) {
197 
198  //if the strip is not added, write the cluster, if present and good:
199  if (clusterCandidate.size() > 0) {
200  clusterCandidate.finalizeCluster();
201  if (clusterCandidate.isGoodCluster()) {
202  writeClusters(clusterCandidate);
203  }
204  }
205 
206  //prepare for the next cluster:
207  clusterCandidate = SimpleClusterCandidate(thisSensorID, thisSide, m_sizeHeadTail, m_cutSeed, m_cutAdjacent, m_cutCluster,
208  m_timeAlgorithm,
209  m_storeShaperDigitsName, m_storeRecoDigitsName);
210 
211  //start another cluster:
212  if (! clusterCandidate.add(thisSensorID, thisSide, aStrip))
213  B2WARNING("this state is forbidden!!");
214 
215  }
216  i++;
217  } //exit loop on RecoDigits
218 
219  //write the last cluster, if good
220  if (clusterCandidate.size() > 0) {
221  clusterCandidate.finalizeCluster();
222  if (clusterCandidate.isGoodCluster())
223  writeClusters(clusterCandidate);
224  }
225 
226  B2DEBUG(1, "Number of clusters: " << m_storeClusters.getEntries());
227 }
228 
229 
230 void SVDSimpleClusterizerModule::writeClusters(SimpleClusterCandidate cluster)
231 {
232 
233  RelationArray relClusterDigit(m_storeClusters, m_storeDigits, m_relClusterRecoDigitName);
234 
235  RelationArray relClusterMCParticle(m_storeClusters, m_storeMCParticles, m_relClusterMCParticleName);
236  RelationArray relClusterTrueHit(m_storeClusters, m_storeTrueHits, m_relClusterTrueHitName);
237 
238  RelationIndex<SVDRecoDigit, MCParticle> relDigitMCParticle(m_storeDigits, m_storeMCParticles, m_relRecoDigitMCParticleName);
239  RelationIndex<SVDRecoDigit, SVDTrueHit> relDigitTrueHit(m_storeDigits, m_storeTrueHits, m_relRecoDigitTrueHitName);
240 
241 
242  VxdID sensorID = cluster.getSensorID();
243  bool isU = cluster.isUSide();
244  float seedCharge = cluster.getSeedCharge();
245  float charge = cluster.getCharge();
246  float size = cluster.size();
247  float SNR = cluster.getSNR();
248  float position = cluster.getPosition();
249  float positionError = m_OldDefaultSF.getCorrectedClusterPositionError(sensorID, isU, size, cluster.getPositionError());
250  //this is the 6-sample CoG time, it will not be used for in 3-sample time algorithms:
251  float time = cluster.getTime();
252  float timeError = cluster.getTimeError();
253  int firstFrame = cluster.getFirstFrame();
254 
255  //first check SVDEventInfo name
256  std::string m_svdEventInfoName = m_svdEventInfoSet;
257  if (m_svdEventInfoSet == "SVDEventInfoSim") {
258  StoreObjPtr<SVDEventInfo> temp_eventinfo("SVDEventInfo");
259  m_svdEventInfoName = "SVDEventInfo";
260  if (!temp_eventinfo.isValid())
261  m_svdEventInfoName = m_svdEventInfoSet;
262  }
263 
264  StoreObjPtr<SVDEventInfo> eventinfo(m_svdEventInfoName);
265  if (!eventinfo) B2ERROR("No SVDEventInfo!");
266 
267  //depending on the algorithm, time contains different information:
268  //6-sample CoG (0): this is the calibrated time already
269  //3-sample CoG (1) or ELS (2) this is the raw time, you need to calibrate:
270  //It is possile to get the uncalibrated 3-sample raw time here
271  //to get the 6-sample raw time there is an option in SVDCoGTimeEstimatorModule
272  float caltime = time;
273  if (m_timeAlgorithm == 1 and m_calibrate3SampleWithEventT0)
274  caltime = m_3CoGTimeCal.getCorrectedTime(sensorID, isU, -1, time, -1);
275  else if (m_timeAlgorithm == 2 and m_calibrate3SampleWithEventT0)
276  caltime = m_3ELSTimeCal.getCorrectedTime(sensorID, isU, -1, time, -1);
277 
278  // last step:
279  // shift cluster time by TB time AND by FirstFrame ( FF = 0 for the 6-sample CoG Time)
280  // the relative shift between 3- and 6-sample DAQ is also corrected
281  // NOTE: this shift is removed in the SVDTimeCalibrationCollector in the CAF
282  time = eventinfo->getTimeInFTSWReference(caltime, firstFrame);
283 
284  // Store Cluster into Datastore
285  m_storeClusters.appendNew(sensorID, isU, position, positionError, time, timeError, charge, seedCharge, size, SNR, -1, firstFrame);
286 
287  //register relation between RecoDigit and Cluster
288  int clsIndex = m_storeClusters.getEntries() - 1;
289 
290  map<int, float> mc_relations;
291  map<int, float> truehit_relations;
292 
293  vector<pair<int, float> > digit_weights;
294  digit_weights.reserve(size);
295 
296  std::vector<stripInCluster> strips = cluster.getStripsInCluster();
297 
298  for (auto strip : strips) {
299 
300  //Fill map with MCParticle relations
301  if (relDigitMCParticle) {
302  typedef const RelationIndex<SVDRecoDigit, MCParticle>::Element relMC_type;
303  for (relMC_type& mcRel : relDigitMCParticle.getElementsFrom(m_storeDigits[strip.recoDigitIndex])) {
304  //negative weights are from ignored particles, we don't like them and
305  //thus ignore them :D
306  if (mcRel.weight < 0) continue;
307  mc_relations[mcRel.indexTo] += mcRel.weight;
308  };
309  };
310  //Fill map with SVDTrueHit relations
311  if (relDigitTrueHit) {
312  typedef const RelationIndex<SVDRecoDigit, SVDTrueHit>::Element relTrueHit_type;
313  for (relTrueHit_type& trueRel : relDigitTrueHit.getElementsFrom(m_storeDigits[strip.recoDigitIndex])) {
314  //negative weights are from ignored particles, we don't like them and
315  //thus ignore them :D
316  if (trueRel.weight < 0) continue;
317  truehit_relations[trueRel.indexTo] += trueRel.weight;
318  };
319  };
320 
321  digit_weights.push_back(make_pair(strip.recoDigitIndex, strip.charge));
322  }
323 
324 
325  //Create Relations to this Digit
326  if (!mc_relations.empty()) {
327  relClusterMCParticle.add(clsIndex, mc_relations.begin(), mc_relations.end());
328  }
329  if (!truehit_relations.empty()) {
330  relClusterTrueHit.add(clsIndex, truehit_relations.begin(), truehit_relations.end());
331  }
332 
333  relClusterDigit.add(clsIndex, digit_weights.begin(), digit_weights.end());
334 }
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.
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:76
range_from getElementsFrom(const FROM *from) const
Return a range of all elements pointing from the given object.
SVDSimpleClusterizerModule: The SVD SimpleClusterizer.
Class representing a cluster candidate during simple clustering of the SVD.
bool add(VxdID vxdID, bool isUside, struct stripInCluster &aStrip)
Add a Strip to the current cluster.
void finalizeCluster()
compute the position, time and their error of the cluster
bool isGoodCluster()
return true if the cluster candidate can be promoted to cluster
int size() const
return the cluster size (number of strips of the cluster
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.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:110
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Namespace to encapsulate code needed for simulation and reconstrucion of the SVD.
Definition: GeoSVDCreator.h:23
Abstract base class for different kinds of events.
RelationElement::weight_type weight
weight of the relation.
structure containing the relevant informations of eachstrip of the cluster
float timeError
6-sample CoG strip time error
int recoDigitIndex
index of the reco digit
float time
6-sample CoG strip time