Belle II Software  release-05-02-19
ECLFinalizerModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2016 - Belle II Collaboration *
4  * *
5  * This module converts the ecl dataobject(s) in the mdst dataobect(s) *
6  * *
7  * Author: The Belle II Collaboration *
8  * Contributors: Torben Ferber (ferber@physics.ubc.ca) *
9  * Guglielmo De Nardo (denardo@na.infn.it) *
10  * Ewan Hill (ehill@mail.ubc.ca) *
11  * *
12  * This software is provided "as is" without any warranty. *
13  **************************************************************************/
14 
15 // THIS MODULE
16 #include <ecl/modules/eclFinalize/ECLFinalizerModule.h>
17 
18 // FRAMEWORK
19 #include <framework/gearbox/Unit.h>
20 #include <framework/logging/Logger.h>
21 #include <framework/dataobjects/EventT0.h>
22 
23 //ECL
24 #include <ecl/dataobjects/ECLShower.h>
25 #include <ecl/dataobjects/ECLCalDigit.h>
26 #include <ecl/utility/utilityFunctions.h>
27 
28 //MDST
29 #include <mdst/dataobjects/ECLCluster.h>
30 #include <mdst/dataobjects/EventLevelClusteringInfo.h>
31 
32 // NAMESPACES
33 using namespace Belle2;
34 using namespace ECL;
35 
36 //-----------------------------------------------------------------
37 // Register the Module
38 //-----------------------------------------------------------------
39 REG_MODULE(ECLFinalizer)
40 REG_MODULE(ECLFinalizerPureCsI)
41 
42 //-----------------------------------------------------------------
43 // Implementation
44 //-----------------------------------------------------------------
46 {
47  // Set description
48  setDescription("ECLFinalizerModule: Converts ecl shower dataobjects to mdst eclcluster dataobjects");
49 
50  addParam("clusterEnergyCutMin", m_clusterEnergyCutMin, "Min value for the cluster energy cut.",
51  20.0 * Belle2::Unit::MeV);
52  addParam("clusterTimeCutMaxEnergy", m_clusterTimeCutMaxEnergy, "All clusters above this energy are kept.",
53  50.0 * Belle2::Unit::MeV);
54  addParam("clusterLossyFraction", m_clusterLossyFraction,
55  "Keep neutral hadron hypothesis clusters only if the number of crystals is different from that of the n photons hypothesis cluster by this fraction: abs(n(neutral hadron)-n(photon))/n(photon)",
56  1e-4);
57 
58  setPropertyFlags(c_ParallelProcessingCertified);
59 }
60 
62 {
63 }
64 
66 {
67  // Register in datastore.
68  m_eclShowers.isRequired(eclShowerArrayName());
69  m_eclClusters.registerInDataStore(eclClusterArrayName());
70  m_eclCalDigits.isRequired(eclCalDigitArrayName());
71  m_eventLevelClusteringInfo.registerInDataStore();
72  m_eventT0.isRequired();
73 
74  // Register relations.
75  m_eclClusters.registerRelationTo(m_eclShowers);
76  m_eclClusters.registerRelationTo(m_eclCalDigits);
77 
78 }
79 
81 {
82  // Do not use this blindly for database updates, they will probably not follow the concept of a "run"
83  ;
84 }
85 
87 {
88  //EventLevelClusteringInfo counters
89  uint rejectedShowersFwd = 0;
90  uint rejectedShowersBrl = 0;
91  uint rejectedShowersBwd = 0;
92 
93  // event T0
94  double eventT0 = 0.;
95  if (m_eventT0->hasEventT0()) {
96  eventT0 = m_eventT0->getEventT0();
97  }
98 
99  // map connected regions to different cluster hypothesis: key (CRId, HypothesisID) -> list arrayindex of shower
100  std::map<std::pair<int, int>, std::vector<int>> hypoShowerMap;
101  for (const auto& eclShower : m_eclShowers) {
102  // if they pass cuts, put them in this map
103  // get shower time, energy and highest energy for cuts
104  const double showerTime = eclShower.getTime() - eventT0;
105  const double showerdt99 = eclShower.getDeltaTime99();
106  const double showerEnergy = eclShower.getEnergy();
107 
108  if (showerEnergy > m_clusterEnergyCutMin and ((fabs(showerTime) < showerdt99) or (showerEnergy > m_clusterTimeCutMaxEnergy))) {
109  hypoShowerMap[std::make_pair(eclShower.getConnectedRegionId(), eclShower.getHypothesisId())].push_back(eclShower.getArrayIndex());
110  } else {
111  if (eclShower.getHypothesisId() == Belle2::ECLShower::c_nPhotons) {
112 
113  // Get detector region
114  const auto detectorRegion = eclShower.getDetectorRegion();
115 
116  B2DEBUG(39, "ECLFinalizerModule::event: Rejected shower with energy " << showerEnergy << ", time = " << showerTime << ", theta = "
117  << eclShower.getTheta()
118  << ", region " << detectorRegion);
119  // Increment counters
120  if (detectorRegion == static_cast<int>(ECL::DetectorRegion::FWD)) {
121  ++rejectedShowersFwd;
122  } else if (detectorRegion == ECL::DetectorRegion::BRL) {
123  ++rejectedShowersBrl;
124  } else if (detectorRegion == ECL::DetectorRegion::BWD) {
125  ++rejectedShowersBwd;
126  }
127  }
128  }
129  }
130 
131  // map connected regions to different cluster hypothesis: key (CRId, HypothesisID) -> list arrayindex of cluster
132  std::map<std::pair<int, int>, std::vector<int>> hypoClusterMap;
133 
134  // now loop over all photon showers from the map and make clusters for those and put them in the map
135  for (const auto & [keypair, indexlist] : hypoShowerMap) {
136  if (keypair.second == Belle2::ECLShower::c_nPhotons) {
137  for (const auto& index : indexlist) {
138  hypoClusterMap[keypair].push_back(makeCluster(index, eventT0));
139  }
140  }
141  }
142 
143  // now loop over all other showers
144  for (const auto & [keypair, indexlist] : hypoShowerMap) {
145  if (keypair.second != Belle2::ECLShower::c_nPhotons) {
146  for (const auto& index : indexlist) {
147  // no photon entry exists (maybe we did not run the splitter or selection cuts failed)
148  if (hypoShowerMap.count(std::make_pair(keypair.first, Belle2::ECLShower::c_nPhotons)) < 1) {
149  hypoClusterMap[keypair].push_back(makeCluster(index, eventT0));
150  }
151  // there is more than one photon cluster, i.e. CR is split into multiple clusters
152  else if (hypoShowerMap[std::make_pair(keypair.first, Belle2::ECLShower::c_nPhotons)].size() > 1) {
153  hypoClusterMap[keypair].push_back(makeCluster(index, eventT0));
154  } else {
155  // get the already existing nPhotons cluster index
156  const int indexOfCorrespondingNPhotonsCluster = hypoClusterMap[std::make_pair(keypair.first, Belle2::ECLShower::c_nPhotons)][0];
157  double lossfraction = fabs(m_eclClusters[indexOfCorrespondingNPhotonsCluster]->getNumberOfCrystals() -
158  m_eclShowers[index]->getNumberOfCrystals()) / m_eclClusters[indexOfCorrespondingNPhotonsCluster]->getNumberOfCrystals();
159 
160  B2DEBUG(35, "ECLFinalizerModule::event n(photon shower) = " <<
161  m_eclClusters[indexOfCorrespondingNPhotonsCluster]->getNumberOfCrystals() << ", n(hadron shower): " <<
162  m_eclShowers[index]->getNumberOfCrystals());
163  B2DEBUG(35, "ECLFinalizerModule::event lossfraction = " << lossfraction);
164 
165  if (lossfraction > m_clusterLossyFraction) {
166  hypoClusterMap[keypair].push_back(makeCluster(index, eventT0));
167  } else {
168  if (keypair.second == ECLShower::c_neutralHadron) m_eclClusters[indexOfCorrespondingNPhotonsCluster]->addHypothesis(
170  else {
171  B2ERROR("This ECLShower hypothesis is not supported yet: " << keypair.second);
172  }
173  }
174  }
175  }
176  }
177  }
178 
179  // Save EventLevelClusteringInfo
180  if (!m_eventLevelClusteringInfo) {
181  m_eventLevelClusteringInfo.create();
182  }
183  m_eventLevelClusteringInfo->setNECLShowersRejectedFWD(rejectedShowersFwd);
184  m_eventLevelClusteringInfo->setNECLShowersRejectedBarrel(rejectedShowersBrl);
185  m_eventLevelClusteringInfo->setNECLShowersRejectedBWD(rejectedShowersBwd);
186 
187  B2DEBUG(35, "ECLFinalizerModule::event found " << rejectedShowersFwd << ", " << rejectedShowersBrl << ", " << rejectedShowersBwd
188  << " rejected showers in FWD, BRL, BWD");
189 }
190 
192 
194 
195 
196 int ECLFinalizerModule::makeCluster(int index, double evtt0)
197 {
198 
199  const auto eclShower = m_eclShowers[index];
200 
201  // create an mdst cluster for each ecl shower
202  const auto eclCluster = m_eclClusters.appendNew();
203 
204  // status between showers and clusters may be different:
205  if (eclShower->hasPulseShapeDiscrimination()) {
207  }
208 
209  eclCluster->setConnectedRegionId(eclShower->getConnectedRegionId());
210 
211  // ECLShowers have *one* hypothesisID...
212  const int hyp = eclShower->getHypothesisId();
213 
214  // ECLClusters can have *multiple*, but not at the creation of an ECLCluster: use "set" and not "add"
215  if (hyp == ECLShower::c_nPhotons) {
216  eclCluster->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
217  } else if (hyp == ECLShower::c_neutralHadron) {
218  eclCluster->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
219  } else {
220  B2ERROR("This ECLShower hypothesis is not supported yet: " << hyp);
221  }
222 
223  eclCluster->setClusterId(eclShower->getShowerId());
224 
225  eclCluster->setEnergy(eclShower->getEnergy());
226  eclCluster->setEnergyRaw(eclShower->getEnergyRaw());
227  eclCluster->setEnergyHighestCrystal(eclShower->getEnergyHighestCrystal());
228  eclCluster->setMaxECellId(static_cast<unsigned short>(eclShower->getCentralCellId()));
229 
230  double covmat[6] = {
231  eclShower->getUncertaintyEnergy()* eclShower->getUncertaintyEnergy(),
232  0.0,
233  eclShower->getUncertaintyPhi()* eclShower->getUncertaintyPhi(),
234  0.0,
235  0.0,
236  eclShower->getUncertaintyTheta()* eclShower->getUncertaintyTheta()
237  };
238  eclCluster->setCovarianceMatrix(covmat);
239 
240  eclCluster->setAbsZernike40(eclShower->getAbsZernike40());
241  eclCluster->setAbsZernike51(eclShower->getAbsZernike51());
242  eclCluster->setZernikeMVA(eclShower->getZernikeMVA());
243  eclCluster->setE1oE9(eclShower->getE1oE9());
244  eclCluster->setE9oE21(eclShower->getE9oE21());
245  eclCluster->setSecondMoment(eclShower->getSecondMoment());
246  eclCluster->setLAT(eclShower->getLateralEnergy());
247  eclCluster->setNumberOfCrystals(eclShower->getNumberOfCrystals());
248  eclCluster->setTime(eclShower->getTime() - evtt0); // If bad timing fit, this value is changed later in the code
249  eclCluster->setDeltaTime99(eclShower->getDeltaTime99());
250  eclCluster->setTheta(eclShower->getTheta());
251  eclCluster->setPhi(eclShower->getPhi());
252  eclCluster->setR(eclShower->getR());
253  eclCluster->setPulseShapeDiscriminationMVA(eclShower->getPulseShapeDiscriminationMVA());
254 #ifdef __INTEL_COMPILER
255 #pragma warning push
256 #pragma warning (disable:1786) //[[deprecated("message")]]
257 #else
258 #pragma GCC diagnostic push
259 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
260 #endif
261  eclCluster->setClusterHadronIntensity(eclShower->getShowerHadronIntensity());
262 #ifdef __INTEL_COMPILER
263 #pragma warning pop
264 #else
265 #pragma GCC diagnostic pop
266 #endif
267  eclCluster->setNumberOfHadronDigits(eclShower->getNumberOfHadronDigits());
268 
269  // set relation to ECLShower
270  eclCluster->addRelationTo(eclShower);
271 
272  // set relation to ECLCalDigits and set failed timing flags
273  auto cellIDOfMaxEnergyCrystal = eclShower->getCentralCellId() ;
274  auto showerDigitRelations = eclShower->getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
275  for (unsigned int iRel = 0; iRel < showerDigitRelations.size(); ++iRel) {
276  const auto calDigit = showerDigitRelations.object(iRel);
277  const auto weight = showerDigitRelations.weight(iRel);
278 
279  eclCluster->addRelationTo(calDigit, weight);
280 
281 
282  // Set the failed timing flag for the crystal that defines the cluster time
283  if (calDigit->getCellId() == cellIDOfMaxEnergyCrystal) {
284  if (calDigit->isFailedFit()) {
285  eclCluster->addStatus(ECLCluster::EStatusBit::c_fitTimeFailed);
286  eclCluster->setTime(eclShower->getTime());
287  }
288  if (calDigit->isTimeResolutionFailed()) {
289  eclCluster->addStatus(ECLCluster::EStatusBit::c_timeResolutionFailed);
290  }
291  }
292  }
293 
294  return eclCluster->getArrayIndex();
295 
296 }
Belle2::ECLFinalizerModule::beginRun
virtual void beginRun() override
Begin run.
Definition: ECLFinalizerModule.cc:80
Belle2::ECLFinalizerModule::endRun
virtual void endRun() override
End run.
Definition: ECLFinalizerModule.cc:191
Belle2::ECLCluster::EStatusBit::c_PulseShapeDiscrimination
@ c_PulseShapeDiscrimination
bit 2: ECLCluster has pulse shape discrimination variables.
Belle2::ECLCluster::EStatusBit::c_fitTimeFailed
@ c_fitTimeFailed
bit 3: ECLCluster has fit time that failed.
Belle2::ECLCalDigit
Class to store calibrated ECLDigits: ECLCalDigits.
Definition: ECLCalDigit.h:38
Belle2::ECLCluster::EStatusBit::c_timeResolutionFailed
@ c_timeResolutionFailed
bit 4: ECLCluster has time resolution calculation that failed.
Belle2::ECLFinalizerModule::makeCluster
int makeCluster(int, double)
Make a cluster from a given shower array index.
Definition: ECLFinalizerModule.cc:196
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::ECLFinalizerModule
Class to perform the shower correction.
Definition: ECLFinalizerModule.h:45
Belle2::ECLFinalizerModule::~ECLFinalizerModule
~ECLFinalizerModule()
Destructor.
Definition: ECLFinalizerModule.cc:61
Belle2::ECLCluster::EHypothesisBit::c_nPhotons
@ c_nPhotons
CR is split into n photons (N1)
Belle2::ECLShower::c_neutralHadron
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
Definition: ECLShower.h:56
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::Unit::MeV
static const double MeV
[megaelectronvolt]
Definition: Unit.h:124
Belle2::ECLFinalizerModule::initialize
virtual void initialize() override
Initialize.
Definition: ECLFinalizerModule.cc:65
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ECLFinalizerModule::event
virtual void event() override
Event.
Definition: ECLFinalizerModule.cc:86
Belle2::ECLCluster::EHypothesisBit::c_neutralHadron
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
Belle2::ECLShower::c_nPhotons
@ c_nPhotons
CR is split into n photons (N1)
Definition: ECLShower.h:54
Belle2::ECLFinalizerModule::terminate
virtual void terminate() override
Terminate.
Definition: ECLFinalizerModule.cc:193