Belle II Software  release-06-01-15
ECLCRFinderModule.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 // THIS MODULE
10 #include <ecl/modules/eclCRFinder/ECLCRFinderModule.h>
11 
12 // FRAMEWORK
13 #include <framework/core/Environment.h>
14 #include <framework/gearbox/Unit.h>
15 #include <framework/logging/LogConfig.h>
16 #include <framework/logging/Logger.h>
17 
18 //ECL
19 #include <ecl/geometry/ECLNeighbours.h>
20 #include <ecl/dataobjects/ECLCalDigit.h>
21 #include <ecl/dataobjects/ECLConnectedRegion.h>
22 
23 // MDST
24 #include <mdst/dataobjects/EventLevelClusteringInfo.h>
25 
26 // C++
27 #include <algorithm>
28 
29 // NAMESPACE(S)
30 using namespace Belle2;
31 
32 //-----------------------------------------------------------------
33 // Register the Module
34 //-----------------------------------------------------------------
35 REG_MODULE(ECLCRFinder)
36 REG_MODULE(ECLCRFinderPureCsI)
37 
38 //-----------------------------------------------------------------
39 // Implementation
40 //-----------------------------------------------------------------
41 ECLCRFinderModule::ECLCRFinderModule() : Module(), m_eclCalDigits(eclCalDigitArrayName()),
42  m_eclConnectedRegions(eclConnectedRegionArrayName()), m_eventLevelClusteringInfo(eventLevelClusteringInfoName())
43 {
44  // Set description
45  setDescription("ECLCRFinderModule");
46 
47  // Parallel processing certification.
48  setPropertyFlags(c_ParallelProcessingCertified);
49 
50  // Add module parameters.
51  addParam("energyCut0", m_energyCut[0], "Seed energy cut.", 10.0 * Belle2::Unit::MeV);
52  addParam("energyCut1", m_energyCut[1], "Growth energy cut.", 10.0 * Belle2::Unit::MeV);
53  addParam("energyCut2", m_energyCut[2], "Digit energy cut.", 0.5 * Belle2::Unit::MeV);
54  addParam("energyCutBkgd0", m_energyCutBkgd[0], "Seed energy cut (for high background).", 10.0 * Belle2::Unit::MeV);
55  addParam("energyCutBkgd1", m_energyCutBkgd[1], "Growth energy cut (for high background).", 10.0 * Belle2::Unit::MeV);
56  addParam("energyCutBkgd2", m_energyCutBkgd[2], "Digit energy cut (for high background).", 0.5 * Belle2::Unit::MeV);
57  addParam("timeCut0", m_timeCut[0], "Seed time cut (negative values for residual cut).", 99999.);
58  addParam("timeCut1", m_timeCut[1], "Growth time cut (negative values for residual cut).", 99999.);
59  addParam("timeCut2", m_timeCut[2], "Digit time cut (negative values for residual cut).", 99999.);
60  addParam("mapType0", m_mapType[0], "Map type for seed crystals.", std::string("N"));
61  addParam("mapType1", m_mapType[1], "Map type for growth crystals.", std::string("N"));
62  addParam("mapPar0", m_mapPar[0],
63  "Map parameter for seed crystals (radius (type=R), integer (for type=N) or fraction (for type=MC)).", 1.0);
64  addParam("mapPar1", m_mapPar[1],
65  "Map parameter for growth crystals (radius (type=R), integer (for type=N) or fraction (for type=MC)).", 1.0);
66  addParam("useBackgroundLevel", m_useBackgroundLevel, "Use background dependent time and energy cuts.", 0);
67  addParam("skipFailedTimeFitDigits", m_skipFailedTimeFitDigits, "Digits with failed fits are skipped when checking timing cuts.", 0);
68  addParam("fullBkgdCount", m_fullBkgdCount, "Full background count (via eventLevelClusteringInfo).", 182);
69 
70 }
71 
73 {
74  ;
75 }
76 
78 {
79  B2DEBUG(200, "ECLCRFinderModule::initialize()");
80 
81  // Register dataobjects.
82  m_eclCalDigits.registerInDataStore(eclCalDigitArrayName());
85 
86  // Register relations.
87  m_eclConnectedRegions.registerRelationTo(m_eclCalDigits);
88 
89  // Check user inputs.
90  if (m_energyCut[0] < m_energyCut[1]) B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[0] must be larger than m_energyCut[1].");
91  if (m_energyCut[1] < m_energyCut[2]) B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[1] must be larger than m_energyCut[2].");
92  if (m_energyCut[0] < m_energyCut[2]) B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[0] must be larger than m_energyCut[2].");
93  if (m_useBackgroundLevel > 0
94  and m_energyCutBkgd[0] < m_energyCutBkgd[1])
95  B2FATAL("ECLCRFinderModule::initialize(): m_energyCutBkgd[0] must be larger than m_energyCutBkgd[1].");
96  if (m_useBackgroundLevel > 0
97  and m_energyCutBkgd[1] < m_energyCutBkgd[2])
98  B2FATAL("ECLCRFinderModule::initialize(): m_energyCutBkgd[1] must be larger than m_energyCutBkgd[2].");
99  if (m_useBackgroundLevel > 0
100  and m_energyCutBkgd[0] < m_energyCutBkgd[2])
101  B2FATAL("ECLCRFinderModule::initialize(): m_energyCutBkgd[0] must be larger than m_energyCutBkgd[2].");
102  if (m_useBackgroundLevel > 0
103  and m_energyCut[0] > m_energyCutBkgd[0])
104  B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[0] must be smaller than m_energyCutBkgd[0].");
105  if (m_useBackgroundLevel > 0
106  and m_energyCut[1] > m_energyCutBkgd[1])
107  B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[1] must be smaller than m_energyCutBkgd[1].");
108  if (m_useBackgroundLevel > 0
109  and m_energyCut[2] > m_energyCutBkgd[2])
110  B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[2] must be smaller than m_energyCutBkgd[2].");
111 
112  // Initialize neighbour maps.
113  m_neighbourMaps.resize(2);
116 
117  // Initialize the modified energy cuts (that could depend on event-by-event backgrounds later).
118  for (int i = 0; i < 3; i++) {
119  m_energyCutMod[i] = m_energyCut[i];
120  }
121 
122  // Resize the vectors
123  m_cellIdToCheckVec.resize(8737);
124  m_cellIdToSeedVec.resize(8737);
125  m_cellIdToGrowthVec.resize(8737);
126  m_cellIdToDigitVec.resize(8737);
127  m_cellIdToTempCRIdVec.resize(8737);
128  m_calDigitStoreArrPosition.resize(8737);
129 
130  // Check if we are running this module online
132  if (m_isOnlineProcessing) {
133  m_energyCut[1] = 1.5 * Belle2::Unit::MeV;
135  }
136 }
137 
139 {
140 
141 }
142 
144 {
145  B2DEBUG(200, "ECLCRFinderModule::event()");
146 
147  // Reset the vector(s).
148  std::fill(m_cellIdToCheckVec.begin(), m_cellIdToCheckVec.end(), 0);
149  std::fill(m_cellIdToSeedVec.begin(), m_cellIdToSeedVec.end(), 0);
150  std::fill(m_cellIdToGrowthVec.begin(), m_cellIdToGrowthVec.end(), 0);
151  std::fill(m_cellIdToDigitVec.begin(), m_cellIdToDigitVec.end(), 0);
152  std::fill(m_cellIdToTempCRIdVec.begin(), m_cellIdToTempCRIdVec.end(), 0);
153 
154  // Fill a vector that can be used to map cellid -> store array position
155  std::fill(m_calDigitStoreArrPosition.begin(), m_calDigitStoreArrPosition.end(), -1);
156  for (int i = 0; i < m_eclCalDigits.getEntries(); i++) {
157  m_calDigitStoreArrPosition[m_eclCalDigits[i]->getCellId()] = i;
158  }
159 
160  // Clear the map(s).
161  m_cellIdToTempCRIdMap.clear();
162 
163  // Init variables.
164  m_tempCRId = 1;
165 
166  //-------------------------------------------------------
167  // Get background level for this events and adjust cuts.
168  if (m_useBackgroundLevel > 0) {
169  const int bkgdcount = m_eventLevelClusteringInfo->getNECLCalDigitsOutOfTime();
170 
171  // This scaling can probably be more clever to be really efficienct.
172  // So far just scale linearly between 0 and 280 (release-07).
173  double frac = 1.0;
174  if (m_fullBkgdCount > 0) frac = static_cast<double>(bkgdcount) / static_cast<double>(m_fullBkgdCount);
175 
176  B2DEBUG(175, "ECLCRFinderModule::event(), Background count for this event: " << bkgdcount << " (expected for full bkgd: " <<
177  m_fullBkgdCount << ", scaling factor is " << frac << ".");
178 
179  // Scale cut values.
180  for (int i = 0; i < 3; i++) {
181  m_energyCutMod[i] = m_energyCut[i] + (m_energyCutBkgd[i] - m_energyCut[i]) * frac;
182  B2DEBUG(200, "ECLCRFinderModule::event(), Energy cut value m_energyCutMod[" << i << "] = " << m_energyCutMod[i] <<
183  ", without bkgd scale m_energyCut[" << i << "] = " << m_energyCut[i]);
184  }
185  }
186 
187  //-------------------------------------------------------
188  // fill digits into maps
189  for (const auto& eclCalDigit : m_eclCalDigits) {
190  const double energy = eclCalDigit.getEnergy();
191  const double time = eclCalDigit.getTime();
192  const double timeresolution = eclCalDigit.getTimeResolution();
193  const int cellid = eclCalDigit.getCellId();
194  const bool fitfailed = eclCalDigit.isFailedFit();
195 
196  double timeresidual = 999.;
197  if (!fitfailed and fabs(timeresolution) > 1e-9) {
198  timeresidual = time / timeresolution;
199  }
200 
201  // Negative timecut is interpreted as cut on time residual, positive cut as cut on the timeresolution!
202  // Fill seed crystals to a map.
203  unsigned isSeed = 0;
204  if (energy >= m_energyCutMod[0]) {
205  if (fitfailed > 0 and m_skipFailedTimeFitDigits > 0) continue;
206  if (!fitfailed) {
207  if (m_timeCut[0] > 1e-9 and fabs(timeresolution) > m_timeCut[0]) continue;
208  if (m_timeCut[0] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[0])) continue;
209  }
210 
211  m_cellIdToSeedVec[cellid] = 1;
212  isSeed = 1;
213  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'seed digit' with cellid = " << cellid);
214  }
215 
216  // Fill growth crystals to a map.
217  unsigned isGrowth = 0;
218  if (energy >= m_energyCutMod[1]) {
219  if (isSeed == 0) { // if a cell is a seed, it is also a growth cell (e.g. for different timing cuts)
220  if (fitfailed > 0 and m_skipFailedTimeFitDigits > 0) continue;
221  if (!fitfailed) {
222  if (m_timeCut[1] > 1e-9 and fabs(timeresolution) > m_timeCut[1]) continue;
223  if (m_timeCut[1] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[1])) continue;
224  }
225  }
226 
227  m_cellIdToGrowthVec[cellid] = 1;
228  isGrowth = 1;
229  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'growth digit' with cellid = " << cellid);
230  }
231 
232  // Fill all crystals above threshold to a map (this must include growth and seed crystals!).
233  if (energy >= m_energyCutMod[2]) {
234  if (isGrowth == 0) { // if a cell is a growth (incl. seed), it is also a growth cell (e.g. for different timing cuts)
235  if (fitfailed > 0 and m_skipFailedTimeFitDigits > 0) continue;
236  if (!fitfailed) {
237  if (m_timeCut[2] > 1e-9 and fabs(timeresolution) > m_timeCut[2]) continue;
238  if (m_timeCut[2] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[2])) continue;
239  }
240  }
241 
242  m_cellIdToDigitVec[cellid] = 1;
243  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'digit' with cellid = " << cellid);
244  }
245 
246  } // done filling digit map
247 
248  //-------------------------------------------------------
249  // 'find" in a map is faster if the number of seeds is not too large, can be replaced easily once we know what seed cuts we want.
250  // This is weird: if we are running online, we use behaviour that was in place until release-05,
251  // otherwise we use the one implemented since release-06
252  // This is fundamental for avoiding a segfault error caused by veeery noisy ECL events,
253  // but note it is a temporary fix.
254  for (unsigned int pos = 1; pos < m_cellIdToSeedVec.size(); ++pos) {
255  // check for m_isOnlineProcessing is for release-05 behaviour
256  if (m_cellIdToSeedVec[pos] > 0 and (m_cellIdToCheckVec[pos] == 0 or m_isOnlineProcessing)) {
257  if (!m_isOnlineProcessing) m_cellIdToCheckVec[pos] = 1; // release-06 and newer versions
258  checkNeighbours(pos, m_tempCRId, 0);
259  ++m_tempCRId; // This is just a number, will be replaced by a consecutive number later in this module
260  }
261  }
262 
263  //-------------------------------------------------------
264  // Make CR Ids consecutive.
265  std::map< int, int > tempCRIdToCRIdMap;
266  std::map< int, int>::iterator tempCRIdToCRIdMapIterator;
267 
268  int CRId = 1;
269  for (unsigned int i = 1; i < m_cellIdToTempCRIdVec.size(); ++i) {
270 
271  if (m_cellIdToTempCRIdVec[i] > 0) { // digit belongs to a temporary CR
272  tempCRIdToCRIdMapIterator = tempCRIdToCRIdMap.find(m_cellIdToTempCRIdVec[i]);
273 
274  if (tempCRIdToCRIdMapIterator == tempCRIdToCRIdMap.end()) { // not found
275  tempCRIdToCRIdMap[m_cellIdToTempCRIdVec[i]] = CRId;
276  ++CRId;
277  }
278  }
279  }
280 
281  // Create CRs and add relations to digits.
282  for (const auto& entry : tempCRIdToCRIdMap) {
283  int connectedRegionID = entry.second;
284 
285  // create CR
286 
287  // Append to store array.
288  const auto aCR = m_eclConnectedRegions.appendNew();
289 
290  // Fill variable(s).
291  aCR->setCRId(connectedRegionID);
292 
293  // Add relations to all digits in this CR.
294  for (unsigned int i = 1; i < m_cellIdToTempCRIdVec.size(); ++i) {
295  if (tempCRIdToCRIdMap[m_cellIdToTempCRIdVec[i]] == connectedRegionID) {
296 
297  const int pos = m_calDigitStoreArrPosition[i];
298  aCR->addRelationTo(m_eclCalDigits[pos], 1.0);
299  }
300  }
301  } // end m_cellIdToTempCRIdVec loop
302 }
303 
304 
306 {
307  B2DEBUG(200, "ECLCRFinderModule::endRun()");
308 }
309 
310 
312 {
313  B2DEBUG(200, "ECLCRFinderModule::terminate()");
314  for (unsigned int i = 0; i < m_neighbourMaps.size(); i++) {
315  if (m_neighbourMaps[i]) delete m_neighbourMaps[i];
316  }
317 
318 }
319 
320 
321 void ECLCRFinderModule::checkNeighbours(const int cellid, const int tempcrid, const int type)
322 {
323  B2DEBUG(200, "ECLCRFinderModule::checkNeighbours() type=" << type);
324 
325  for (const auto& neighbour : m_neighbourMaps[type]->getNeighbours(cellid)) {
326  B2DEBUG(200, "ECLCRFinderModule::checkNeighbours(): neighbour=" << neighbour);
327 
328  // Check if this digit is above the lowest threshold (i.e. included in m_cellIdToDigitPointerVec) to be added.
329  int isAdded = 0;
330  if (m_cellIdToDigitVec[neighbour] > 0) {
331  updateCRs(neighbour, tempcrid);
332  isAdded = 1;
333  }
334 
335  B2DEBUG(300, " --> ECLCRFinderModule::checkNeighbours(): tempcrid=" << tempcrid);
336  // Check if we have to grow further.
337  if (m_cellIdToGrowthVec[neighbour] > 0) {
338  B2DEBUG(300, " --> ECLCRFinderModule::checkNeighbours(): " << neighbour);
339  if (isAdded < 1) {
340  B2DEBUG(300, " --> ECLCRFinderModule::checkNeighbours(): isAdded=" << isAdded);
341 
342  updateCRs(neighbour, tempcrid); // it could be that this digit is not in the all digit list (eg. tight timing cuts for "all digits".
343  isAdded = 1;
344  }
345 
346  B2DEBUG(300, " --> ECLCRFinderModule::checkNeighbours(): m_cellIdToTempCRIdVec[" << neighbour << "] " <<
347  m_cellIdToTempCRIdVec[neighbour]);
348  // This is weird: if we are running online, we use behaviour that was in place until release-05,
349  // otherwise we use the one implemented since release-06
350  // This is fundamental for avoiding a segfault error caused by veeery noisy ECL events,
351  // but note it is a temporary fix.
352  if (m_isOnlineProcessing) { // release-05
353  if (m_cellIdToTempCRIdVec[neighbour] == 0) { // found
354  checkNeighbours(neighbour, tempcrid, 1);
355  }
356  } else { // release-06 and newer versions
357  if (m_cellIdToCheckVec[neighbour] == 0) { // only check again if we have not looked at that digit before
358  m_cellIdToCheckVec[neighbour] = 1;
359  checkNeighbours(neighbour, tempcrid, 1);
360  }
361  }
362  }
363  }
364 }
365 
366 
367 void ECLCRFinderModule::updateCRs(int cellid, int tempcr)
368 {
369  B2DEBUG(200, "ECLCRFinderModule::updateCRs()");
370 
371  // Check if this cellid already belongs to a connected region.
372  int thiscr = m_cellIdToTempCRIdVec[cellid];
373 
374  if (thiscr != 0) {
375 
376  // This cellid is already in another connected region, update all cells of this other connected region
377  for (unsigned int i = 1; i < m_cellIdToTempCRIdVec.size(); ++i) {
378  if (m_cellIdToTempCRIdVec[i] == thiscr) {
379  m_cellIdToTempCRIdVec[i] = tempcr;
380  }
381  }
382 
383  } else { //not in a CR yet, add it!
384  m_cellIdToTempCRIdVec[cellid] = tempcr;
385  }
386 }
Class to find connected regions.
double m_mapPar[2]
Parameters for neighbour maps.
double m_energyCutMod[3]
modified energy cut taking into account bkgd per event for seed, neighbours, ...
std::vector< int > m_cellIdToDigitVec
cellid -> above threshold digits.
virtual ~ECLCRFinderModule()
Destructor.
StoreArray< ECLConnectedRegion > m_eclConnectedRegions
Store array: ECLConnectedRegion.
double m_timeCut[3]
Time cut for seed, neighbours, ...
bool m_isOnlineProcessing
Other variables.
std::vector< int > m_cellIdToGrowthVec
cellid -> growth digits.
virtual void initialize() override
Initialize.
int m_useBackgroundLevel
Background dependend energy and timing cuts.
std::map< int, int > m_cellIdToTempCRIdMap
cellid -> temporary CR.
double m_energyCut[3]
Energy cut for seed, neighbours, ...
std::vector< int > m_cellIdToCheckVec
Digit vectors.
virtual void event() override
Event.
std::vector< int > m_cellIdToSeedVec
cellid -> seed digit.
int m_tempCRId
Temporary CR ID.
void updateCRs(int cellid, int tempcr)
Update CRs.
virtual void endRun() override
End run.
virtual void terminate() override
Terminate (close ROOT files here if you have opened any).
std::vector< int > m_cellIdToTempCRIdVec
Connected Region map.
int m_skipFailedTimeFitDigits
Handling of digits with failed time fits.
std::vector< int > m_calDigitStoreArrPosition
vector (8736+1 entries) with cell id to store array positions
virtual void beginRun() override
Begin.
int m_fullBkgdCount
Number of expected background digits at full background.
virtual const char * eventLevelClusteringInfoName() const
Name to be used for default option: EventLevelClusteringInfo.
std::vector< ECL::ECLNeighbours * > m_neighbourMaps
Neighbour maps.
std::string m_mapType[2]
Neighbour map types.
double m_energyCutBkgd[3]
Energy cut (for high background) for seed, neighbours, ...
virtual const char * eclCalDigitArrayName() const
Name to be used for default or PureCsI option: ECLCalDigits.
void checkNeighbours(const int cellid, const int tempcrid, const int type)
Neighbour finder.
StoreObjPtr< EventLevelClusteringInfo > m_eventLevelClusteringInfo
Store object pointer: EventLevelClusteringInfo.
StoreArray< ECLCalDigit > m_eclCalDigits
Store array: ECLCalDigit.
virtual const char * eclConnectedRegionArrayName() const
Name to be used for default option: ECLConnectedRegions.
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:23
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:29
LogConfig::ELogRealm getRealm() const
Get the basf2 execution realm.
Definition: Environment.h:193
@ c_Online
Online data taking.
Definition: LogConfig.h:49
Base class for Modules.
Definition: Module.h:72
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
#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.