Belle II Software  release-08-01-10
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 /* Own header. */
10 #include <ecl/modules/eclCRFinder/ECLCRFinderModule.h>
11 
12 /* ECL headeers. */
13 #include <ecl/dataobjects/ECLCalDigit.h>
14 #include <ecl/dataobjects/ECLConnectedRegion.h>
15 #include <ecl/geometry/ECLNeighbours.h>
16 
17 /* Basf2 headers. */
18 #include <framework/gearbox/Unit.h>
19 #include <framework/logging/Logger.h>
20 #include <mdst/dataobjects/EventLevelClusteringInfo.h>
21 
22 /* C++ headers. */
23 #include <algorithm>
24 #include <iostream>
25 
26 // NAMESPACE(S)
27 using namespace Belle2;
28 
29 //-----------------------------------------------------------------
30 // Register the Module
31 //-----------------------------------------------------------------
32 REG_MODULE(ECLCRFinder);
33 REG_MODULE(ECLCRFinderPureCsI);
34 
35 //-----------------------------------------------------------------
36 // Implementation
37 //-----------------------------------------------------------------
38 ECLCRFinderModule::ECLCRFinderModule() : Module(), m_eclCalDigits(eclCalDigitArrayName()),
39  m_eclConnectedRegions(eclConnectedRegionArrayName()), m_eventLevelClusteringInfo(eventLevelClusteringInfoName())
40 {
41  // Set description
42  setDescription("ECLCRFinderModule");
43 
44  // Parallel processing certification.
46 
47  // Add module parameters.
48  addParam("energyCut0", m_energyCut[0], "Seed energy cut.", 10.0 * Belle2::Unit::MeV);
49  addParam("energyCut1", m_energyCut[1], "Growth energy cut.", 10.0 * Belle2::Unit::MeV);
50  addParam("energyCut2", m_energyCut[2], "Digit energy cut.", 0.5 * Belle2::Unit::MeV);
51  addParam("timeCut0", m_timeCut[0], "Seed time cut (negative values for residual cut).", 99999.);
52  addParam("timeCut1", m_timeCut[1], "Growth time cut (negative values for residual cut).", 99999.);
53  addParam("timeCut2", m_timeCut[2], "Digit time cut (negative values for residual cut).", 99999.);
54  addParam("timeCut0maxEnergy", m_timeCut_maxEnergy[0], "Time cut is only applied below this energy for seed crystals.",
55  0.0 * Belle2::Unit::MeV);
56  addParam("timeCut1maxEnergy", m_timeCut_maxEnergy[1], "Time cut is only applied below this energy for growth crystals.",
57  0.0 * Belle2::Unit::MeV);
58  addParam("timeCut2maxEnergy", m_timeCut_maxEnergy[2], "Time cut is only applied below this energy for digits.",
59  0.0 * Belle2::Unit::MeV);
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("skipFailedTimeFitDigits", m_skipFailedTimeFitDigits, "Digits with failed fits are skipped when checking timing cuts.", 0);
67 
68 }
69 
71 {
72  ;
73 }
74 
76 {
77  B2DEBUG(200, "ECLCRFinderModule::initialize()");
78 
79  // Register dataobjects.
80  m_eclCalDigits.registerInDataStore(eclCalDigitArrayName());
83 
84  // Register relations.
85  m_eclConnectedRegions.registerRelationTo(m_eclCalDigits);
86 
87  // Check user inputs: [2]: digit, [1]: growth, [0]: seed
88  // overall energy thresholds
89  if (std::isless(m_energyCut[0], m_energyCut[1])) B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[0]=" << m_energyCut[0] <<
90  " must be larger or equal than m_energyCut[1]=" << m_energyCut[1]);
91  if (std::isless(m_energyCut[1], m_energyCut[2])) B2FATAL("ECLCRFinderModule::initialize(): m_energyCut[1]=" << m_energyCut[1] <<
92  " must be larger or equal than m_energyCut[2]=" << m_energyCut[2]);
93 
94  // timing threshold (can depend on energy, but we make the check here even stronger by checking that the timing is looser without checking the timing energy range)
95  if (std::isgreater(m_timeCut[0], m_timeCut[1]))
96  B2FATAL("ECLCRFinderModule::initialize(): m_timeCut[0] must be less or equal than m_timeCut[1].");
97  if (std::isgreater(m_timeCut[1], m_timeCut[2]))
98  B2FATAL("ECLCRFinderModule::initialize(): m_timeCut[1] must be less or equal than m_timeCut[2].");
99 
100  // Initialize neighbour maps.
101  m_neighbourMaps.resize(2);
104 
105  // Resize the vectors
106  m_cellIdToCheckVec.resize(8737);
107  m_cellIdToSeedVec.resize(8737);
108  m_cellIdToGrowthVec.resize(8737);
109  m_cellIdToDigitVec.resize(8737);
110  m_cellIdToTempCRIdVec.resize(8737);
111  m_calDigitStoreArrPosition.resize(8737);
112 
113 }
114 
116 {
117 
118 }
119 
121 {
122  B2DEBUG(200, "ECLCRFinderModule::event()");
123 
124  // Reset the vector(s).
125  std::fill(m_cellIdToCheckVec.begin(), m_cellIdToCheckVec.end(), 0);
126  std::fill(m_cellIdToSeedVec.begin(), m_cellIdToSeedVec.end(), 0);
127  std::fill(m_cellIdToGrowthVec.begin(), m_cellIdToGrowthVec.end(), 0);
128  std::fill(m_cellIdToDigitVec.begin(), m_cellIdToDigitVec.end(), 0);
129  std::fill(m_cellIdToTempCRIdVec.begin(), m_cellIdToTempCRIdVec.end(), 0);
130 
131  // Fill a vector that can be used to map cellid -> store array position
132  std::fill(m_calDigitStoreArrPosition.begin(), m_calDigitStoreArrPosition.end(), -1);
133  for (int i = 0; i < m_eclCalDigits.getEntries(); i++) {
134  m_calDigitStoreArrPosition[m_eclCalDigits[i]->getCellId()] = i;
135  }
136 
137  // Clear the map(s).
138  m_cellIdToTempCRIdMap.clear();
139 
140  //-------------------------------------------------------
141  // fill digits into maps
142  for (const auto& eclCalDigit : m_eclCalDigits) {
143  const double energy = eclCalDigit.getEnergy();
144  const double time = eclCalDigit.getTime();
145  const double timeresolution = eclCalDigit.getTimeResolution();
146  const int cellid = eclCalDigit.getCellId();
147  const bool fitfailed = eclCalDigit.isFailedFit();
148 
149  double timeresidual = 999.;
150  if (!fitfailed and fabs(timeresolution) > 1e-9) {
151  timeresidual = time / timeresolution;
152  }
153 
154  // Negative timecut is interpreted as cut on time residual, positive cut as cut on the time!
155  // Start filling all crystals to a map. Growth and seed crystals are strict subsets.
156  if (std::isgreaterequal(energy, m_energyCut[2])) {
157  if (fitfailed > 0 and m_skipFailedTimeFitDigits > 0) continue;
158  if (!fitfailed
159  and energy < m_timeCut_maxEnergy[2]) { //check timing cuts only if we have a good fit and if the energy is below threshold
160  if (m_timeCut[2] > 1e-9 and fabs(time) > m_timeCut[2]) continue;
161  if (m_timeCut[2] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[2])) continue;
162  }
163  m_cellIdToDigitVec[cellid] = 1;
164  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'all digit' cellid = " << cellid << " " << energy << " " << time << " " <<
165  timeresidual);
166 
167  // check growth only if they already passed the digit check
168  if (std::isgreaterequal(energy, m_energyCut[1])) {
169  if (!fitfailed
170  and energy < m_timeCut_maxEnergy[1]) { //check timing cuts only if we have a good fit and if the energy is below threshold
171  if (m_timeCut[1] > 1e-9 and fabs(time) > m_timeCut[1]) continue;
172  if (m_timeCut[1] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[1])) continue;
173  }
174  m_cellIdToGrowthVec[cellid] = 1;
175  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'growth digit' cellid = " << cellid << " " << energy << " " << time << " " <<
176  timeresidual);
177 
178 
179  // check seed only if they already passed the growth check
180  if (std::isgreaterequal(energy, m_energyCut[0])) {
181  if (!fitfailed
182  and energy < m_timeCut_maxEnergy[0]) { //check timing cuts only if we have a good fit and if the energy is below threshold
183  if (m_timeCut[0] > 1e-9 and fabs(time) > m_timeCut[0]) continue;
184  if (m_timeCut[0] < -1e-9 and fabs(timeresidual) > fabs(m_timeCut[0])) continue;
185  }
186  m_cellIdToSeedVec[cellid] = 1;
187  B2DEBUG(250, "ECLCRFinderModule::event(), adding 'seed digit' cellid = " << cellid << " " << energy << " " << time << " " <<
188  timeresidual);
189  } // end seed
190  } //end growth
191  }// end digit
192  }//end filling maps
193 
194  // we start with seed crystals A and attach all growth crystals B
195  std::vector<std::vector<int>> connectedRegions_AB = getConnectedRegions(m_cellIdToSeedVec, m_cellIdToGrowthVec, 0);
196  std::vector<int> connectedRegions_AB_flattened = flattenVector(connectedRegions_AB);
197  std::vector<int> AB = oneHotVector(connectedRegions_AB_flattened, m_cellIdToSeedVec.size());
198 
199  // Check if any of the growth crystals could grow to other growth crystals
200  std::vector<std::vector<int>> connectedRegions_ABB = getConnectedRegions(AB, m_cellIdToGrowthVec, 0);
201  std::vector<int> connectedRegions_ABB_flattened = flattenVector(connectedRegions_ABB);
202  std::vector<int> ABB = oneHotVector(connectedRegions_ABB_flattened, AB.size());
203 
204  // and finally: attach all normal digits
205  std::vector<std::vector<int>> connectedRegions_ABBC = getConnectedRegions(ABB, m_cellIdToDigitVec, 0);
206 
207  //final step: merge all CRs that share at least one crystal
208  std::vector<std::set<int>> connectedRegionsMerged_ABBC_sets = mergeVectorsUsingSets(connectedRegions_ABBC);
209 
210  // Create CRs and add relations to digits.
211  unsigned int connectedRegionID = 0;
212  for (const auto& xcr : connectedRegionsMerged_ABBC_sets) {
213 
214  // Append to store array
215  const auto aCR = m_eclConnectedRegions.appendNew();
216 
217  // Set CR ID
218  aCR->setCRId(connectedRegionID);
219  connectedRegionID++;
220 
221  // Add all digits
222  for (int x : xcr) {
223  const int pos = m_calDigitStoreArrPosition[x];
224  aCR->addRelationTo(m_eclCalDigits[pos], 1.0);
225  }
226  }
227 
228 }
229 
231 {
232  B2DEBUG(200, "ECLCRFinderModule::endRun()");
233 }
234 
235 
237 {
238  B2DEBUG(200, "ECLCRFinderModule::terminate()");
239  for (unsigned int i = 0; i < m_neighbourMaps.size(); i++) {
240  if (m_neighbourMaps[i]) delete m_neighbourMaps[i];
241  }
242 
243 }
244 
245 bool ECLCRFinderModule::areNeighbours(const int cellid1, const int cellid2, const int maptype)
246 {
247  for (const auto& neighbour : m_neighbourMaps[maptype]->getNeighbours(cellid1)) {
248  if (neighbour == cellid2) return true;
249  }
250  return false;
251 }
252 
253 std::vector<int> ECLCRFinderModule::flattenVector(std::vector<std::vector<int>>& A)
254 {
255  std::vector<int> C;
256  for (const auto& B : A) {
257  C.insert(C.end(), B.begin(), B.end());
258  }
259  std::sort(C.begin(), C.end());
260  C.erase(std::unique(C.begin(), C.end()), C.end());
261  return C;
262 }
263 
264 std::vector<int> ECLCRFinderModule::oneHotVector(std::vector<int>& A, const int n)
265 {
266  std::vector<int> C(n, 0);
267  for (int x : A) {
268  if (x >= 0 && x < n) {
269  C[x] = 1;
270  }
271  }
272  return C;
273 }
274 
275 std::vector<std::set<int>> ECLCRFinderModule::mergeVectorsUsingSets(std::vector<std::vector<int>>& A)
276 {
277 
278  // Make empty list of sets "output"
279  std::vector< std::set<int> > output;
280 
281  for (auto& vec : A) {
282  std::set<int> s(vec.begin(), vec.end());
283 
284  //Check whether element intersects with any in output
285  for (auto it = output.begin(); it != output.end();) {
286  std::set<int> intersect;
287  std::set_intersection(it->begin(), it->end(), s.begin(), s.end(),
288  std::inserter(intersect, intersect.begin()));
289 
290  if (!intersect.empty()) {
291  s.insert(it->begin(), it->end());
292  it = output.erase(it);
293  } else ++it;
294  }
295  output.push_back(s);
296  }
297 
298  return output;
299 }
300 
301 std::vector<std::vector<int>> ECLCRFinderModule::getConnectedRegions(const std::vector<int>& A, const std::vector<int>& B,
302  const int maptype)
303 {
304  std::vector<std::vector<int>> connectedRegions;
305 
306  for (unsigned int i = 0; i < A.size(); ++i) {
307  if (A[i] > 0) {
308  std::vector<int> region;
309  region.push_back(i);
310 
311  for (unsigned int j = 0; j < B.size(); ++j) {
312  if (B[j] > 0 && areNeighbours(i, j, maptype)) {
313  region.push_back(j);
314  }
315  }
316 
317  std::sort(region.begin(), region.end());
318  region.erase(unique(region.begin(), region.end()), region.end());
319  connectedRegions.push_back(region);
320  }
321  }
322 
323  return connectedRegions;
324 }
double m_mapPar[2]
Parameters for neighbour maps.
bool areNeighbours(const int cellid1, const int cellid2, const int maptype)
Check if two crystals are 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, ...
std::vector< int > oneHotVector(std::vector< int > &A, const int n)
Convert vector of cell ids to 0/1 vectors from 1-8737.
std::vector< int > m_cellIdToGrowthVec
cellid -> growth digits.
virtual void initialize() override
Initialize.
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.
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 (ECLElementNumbers::c_NCrystals + 1 entries) with cell id to store array positions
virtual void beginRun() override
Begin.
std::vector< std::vector< int > > getConnectedRegions(const std::vector< int > &A, const std::vector< int > &B, const int maptype)
Get all connected regions.
std::vector< int > flattenVector(std::vector< std::vector< int >> &A)
Convert vector of vectors to one long vector.
virtual const char * eventLevelClusteringInfoName() const
Name to be used for default option: EventLevelClusteringInfo.
std::vector< std::set< int > > mergeVectorsUsingSets(std::vector< std::vector< int >> &A)
Find all lists of cell-ids that share at least one cell.
std::vector< ECL::ECLNeighbours * > m_neighbourMaps
Neighbour maps.
std::string m_mapType[2]
Neighbour map types.
double m_timeCut_maxEnergy[3]
Time cut is only applied below this energy, ...
virtual const char * eclCalDigitArrayName() const
Name to be used for default or PureCsI option: ECLCalDigits.
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:25
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
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
REG_MODULE(arichBtest)
Register the Module.
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
int intersect(const TRGCDCLpar &lp1, const TRGCDCLpar &lp2, CLHEP::HepVector &v1, CLHEP::HepVector &v2)
intersection
Definition: Lpar.cc:249
Abstract base class for different kinds of events.