Belle II Software  release-08-01-10
ECLClusterPSD.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/eclClusterPSD/ECLClusterPSD.h>
11 
12 /* ECL headers. */
13 #include <ecl/dataobjects/ECLCalDigit.h>
14 #include <ecl/dataobjects/ECLShower.h>
15 #include <ecl/geometry/ECLGeometryPar.h>
16 
17 /* Basf2 headers */
18 #include <framework/logging/Logger.h>
19 #include <framework/geometry/B2Vector3.h>
20 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
21 #include <mva/interface/Expert.h>
22 #include <mva/interface/Interface.h>
23 #include <mva/interface/Weightfile.h>
24 
25 /* Boost headers. */
26 #include <boost/algorithm/string/predicate.hpp>
27 
28 /* C++ headers. */
29 #include <cmath>
30 
31 using namespace Belle2;
32 
33 //-----------------------------------------------------------------
34 // Register the Modules
35 //-----------------------------------------------------------------
36 REG_MODULE(ECLClusterPSD);
37 //-----------------------------------------------------------------
38 // Implementation
39 //-----------------------------------------------------------------
40 
41 // constructor
43 {
44  // Set module properties
45  setDescription("Module uses offline two component fit results to compute pulse shape discrimation variables for particle identification.");
47  addParam("CrystalHadronEnergyThreshold", m_CrystalHadronEnergyThreshold,
48  "Hadron component energy threshold to identify as hadron digit.(GeV)", 0.003);
49  addParam("CrystalHadronIntensityThreshold", m_CrystalHadronIntensityThreshold,
50  "Hadron component intensity threshold to identify as hadron digit.", 0.005);
51  addParam("MVAidentifier", m_MVAidentifier, "MVA database identifier.", std::string{"eclClusterPSD_MVA"});
52 }
53 
54 // destructor
56 {
57 }
58 
59 // initialize MVA weightFile
60 void ECLClusterPSDModule::initializeMVAweightFile(const std::string& identifier,
61  std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>& weightFileRepresentation)
62 {
63  if (not(boost::ends_with(identifier, ".root") or boost::ends_with(identifier, ".xml"))) {
64  weightFileRepresentation = std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>(new
66  }
68 }
69 
70 // initialize
72 {
73  // ECL dataobjects
74  m_eclShowers.registerInDataStore(eclShowerArrayName());
75  m_eclCalDigits.registerInDataStore(eclCalDigitArrayName());
77 }
78 
79 // initialize MVA
80 void ECLClusterPSDModule::initializeMVA(const std::string& identifier,
81  std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>& weightFileRepresentation, std::unique_ptr<MVA::Expert>& expert)
82 {
83  MVA::Weightfile weightfile;
84  //Load MVA weight file
85  if (weightFileRepresentation) {
86 
87  if (weightFileRepresentation->hasChanged()) {
88  std::stringstream ss((*weightFileRepresentation)->m_data);
89  weightfile = MVA::Weightfile::loadFromStream(ss);
90  } else
91  return;
92  } else {
93  weightfile = MVA::Weightfile::loadFromFile(identifier);
94  }
95 
96 
97  auto supported_interfaces = MVA::AbstractInterface::getSupportedInterfaces();
98  MVA::GeneralOptions general_options;
99  weightfile.getOptions(general_options);
100 
101  //Check number of variables in weight file
102  if (m_numMVAvariables != general_options.m_variables.size())
103  B2FATAL("Expecting " << m_numMVAvariables << " variables, found " << general_options.m_variables.size());
104 
105  expert = supported_interfaces[general_options.m_method]->getExpert();
106  expert->load(weightfile);
107 
108  //create new dataset
109  if (weightFileRepresentation == m_weightfile_representation) {
110  std::vector<float> dummy(general_options.m_variables.size(), 0);
111  m_dataset = std::unique_ptr<MVA::SingleDataset>(new MVA::SingleDataset(general_options, dummy, 0));
112  }
113 }
114 
115 // begin run
117 {
119 }
120 
121 // evaluates mva
123 {
124 
125  //geometry for cell id position
127 
128  auto relatedDigits = cluster->getRelationsTo<ECLCalDigit>();
129 
130  //EnergyToSort vector is used for sorting digits by offline two component energy
131  std::vector<std::tuple<double, unsigned int>> EnergyToSort;
132 
133  for (unsigned int iRel = 0; iRel < relatedDigits.size(); iRel++) {
134 
135  const auto caldigit = relatedDigits.object(iRel);
136 
137  //exclude digits without waveforms
138  const double digitChi2 = caldigit->getTwoComponentChi2();
139  if (digitChi2 < 0) continue;
140 
141  ECLDsp::TwoComponentFitType digitFitType1 = caldigit->getTwoComponentFitType();
142 
143  //exclude digits digits with poor chi2
144  if (digitFitType1 == ECLDsp::poorChi2) continue;
145 
146  //exclude digits with diode-crossing fits
147  if (digitFitType1 == ECLDsp::photonDiodeCrossing) continue;
148 
149  EnergyToSort.emplace_back(caldigit->getTwoComponentTotalEnergy(), iRel);
150 
151  }
152 
153  //sorting by energy
154  std::sort(EnergyToSort.begin(), EnergyToSort.end(), std::greater<>());
155 
156  //get cluster position information
157  const double showerR = cluster->getR();
158  const double showerTheta = cluster->getTheta();
159  const double showerPhi = cluster->getPhi();
160 
161  B2Vector3D showerPosition;
162  showerPosition.SetMagThetaPhi(showerR, showerTheta, showerPhi);
163 
164  size_t input_index{0};
165  auto& input = m_dataset->m_input;
166 
167  for (unsigned int digit = 0; digit < maxdigits; ++digit) {
168 
169  if (digit >= EnergyToSort.size()) break;
170 
171  const auto [digitEnergy, next] = EnergyToSort[digit];
172 
173  const auto caldigit = relatedDigits.object(next);
174  const double digitHadronEnergy = caldigit->getTwoComponentHadronEnergy();
175  const double digitOnlineEnergy = caldigit->getEnergy();
176  const double digitWeight = relatedDigits.weight(next);
177  ECLDsp::TwoComponentFitType digitFitType1 = caldigit->getTwoComponentFitType();
178  const int digitFitType = digitFitType1;
179  const int cellId = caldigit->getCellId();
180  B2Vector3D calDigitPosition = geometry->GetCrystalPos(cellId - 1);
181  ROOT::Math::XYZVector tempP = showerPosition - calDigitPosition;
182  const double Rval = tempP.R();
183  const double theVal = tempP.Z() / tempP.R();
184  const double phiVal = cos(tempP.Phi());
185 
186  input[input_index++] = theVal;
187  input[input_index++] = phiVal;
188  input[input_index++] = Rval;
189  input[input_index++] = digitOnlineEnergy;
190  input[input_index++] = digitEnergy;
191  input[input_index++] = (digitHadronEnergy / digitEnergy);
192  input[input_index++] = digitFitType;
193  input[input_index++] = digitWeight;
194 
195  }
196 
197  //fill remainder with defaults
198  while (input_index < input.size()) {
199  if (((input_index - 6) % 8) != 0) {
200  input[input_index++] = 0.0;
201  } else {
202  input[input_index++] = -1.0; //Fit Type
203  }
204  }
205 
206  //compute mva from input variables
207  const double MVAout = m_expert->apply(*m_dataset)[0];
208 
209  return MVAout;
210 }
211 
212 
214 {
215 
216  for (auto& shower : m_eclShowers) {
217 
218 
219  auto relatedDigits = shower.getRelationsTo<ECLCalDigit>();
220 
221  double cluster2CTotalEnergy = 0;
222  double cluster2CHadronEnergy = 0;
223  double numberofHadronDigits = 0;
224  double nWaveforminCluster = 0;
225 
226  for (unsigned int iRel = 0; iRel < relatedDigits.size(); iRel++) {
227 
228  const auto weight = relatedDigits.weight(iRel);
229 
230  const auto caldigit = relatedDigits.object(iRel);
231  const double digit2CChi2 = caldigit->getTwoComponentChi2();
232 
233  if (digit2CChi2 < 0) continue; //only digits with waveforms
234 
235  ECLDsp::TwoComponentFitType digitFitType1 = caldigit->getTwoComponentFitType();
236 
237  //exclude digits digits with poor chi2
238  if (digitFitType1 == ECLDsp::poorChi2) continue;
239 
240  //exclude digits with diode-crossing fits
241  if (digitFitType1 == ECLDsp::photonDiodeCrossing) continue;
242 
243  const double digit2CTotalEnergy = caldigit->getTwoComponentTotalEnergy();
244  const double digit2CHadronComponentEnergy = caldigit->getTwoComponentHadronEnergy();
245 
246  cluster2CTotalEnergy += digit2CTotalEnergy;
247  cluster2CHadronEnergy += digit2CHadronComponentEnergy;
248 
249  if (digit2CTotalEnergy < 0.6) {
250  if (digit2CHadronComponentEnergy > m_CrystalHadronEnergyThreshold) numberofHadronDigits += weight;
251  } else {
252  const double digitHadronComponentIntensity = digit2CHadronComponentEnergy / digit2CTotalEnergy;
253  if (digitHadronComponentIntensity > m_CrystalHadronIntensityThreshold) numberofHadronDigits += weight;
254  }
255 
256  nWaveforminCluster += weight;
257 
258  }
259 
260  if (nWaveforminCluster > 0) {
261  if (cluster2CTotalEnergy != 0) shower.setShowerHadronIntensity(cluster2CHadronEnergy / cluster2CTotalEnergy);
262  //evaluates mva classifier only if waveforms are available in the cluster
263  const double mvaout = evaluateMVA(&shower);
264  shower.setPulseShapeDiscriminationMVA(mvaout);
265 
266  shower.setNumberOfHadronDigits(numberofHadronDigits);
268 
269  } else {
270  shower.setShowerHadronIntensity(0);
271  shower.setPulseShapeDiscriminationMVA(0.5);
272  shower.setNumberOfHadronDigits(0);
273  }
274  }
275 }
276 
277 // end run
279 {
280 }
281 
282 // terminate
284 {
285 }
DataType Z() const
access variable Z (= .at(2) without boundary check)
Definition: B2Vector3.h:435
void SetMagThetaPhi(DataType mag, DataType theta, DataType phi)
setter with mag, theta, phi
Definition: B2Vector3.h:259
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
Class to store calibrated ECLDigits: ECLCalDigits.
Definition: ECLCalDigit.h:23
double getTwoComponentChi2() const
Get two componnent chi2.
Definition: ECLCalDigit.h:139
ECLClusterPSDModule()
Constructor.
StoreArray< ECLShower > m_eclShowers
ECLShower's.
Definition: ECLClusterPSD.h:75
std::unique_ptr< MVA::SingleDataset > m_dataset
Pointer to the current dataset.
Definition: ECLClusterPSD.h:83
virtual void initialize() override
Initialize variables.
virtual void event() override
event per event.
virtual const char * eclShowerArrayName() const
ECLShowers array name.
Definition: ECLClusterPSD.h:68
virtual void endRun() override
end run.
virtual void terminate() override
terminate.
std::unique_ptr< MVA::Expert > m_expert
Pointer to the current MVA Expert.
Definition: ECLClusterPSD.h:82
const unsigned int maxdigits
Max number of digits mva can include.
Definition: ECLClusterPSD.h:77
const unsigned int m_numMVAvariables
number of variables expected in the MVA weightfile
Definition: ECLClusterPSD.h:78
std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile > > m_weightfile_representation
Database pointer to the Database representation of the MVA weightfile.
Definition: ECLClusterPSD.h:81
virtual void beginRun() override
begin run.
double m_CrystalHadronEnergyThreshold
hadron component energy threshold to classify as hadron.
Definition: ECLClusterPSD.h:72
std::string m_MVAidentifier
MVA - weight-file.
Definition: ECLClusterPSD.h:79
double evaluateMVA(const ECLShower *cluster)
Evaluates mva.
virtual const char * eclCalDigitArrayName() const
ECLCalDigits array name.
Definition: ECLClusterPSD.h:64
StoreArray< ECLCalDigit > m_eclCalDigits
ECLCalDigit's.
Definition: ECLClusterPSD.h:74
void initializeMVA(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation, std::unique_ptr< MVA::Expert > &expert)
Load MVA weight file and set pointer of expert.
void initializeMVAweightFile(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation)
initialize MVA weight file from DB
double m_CrystalHadronIntensityThreshold
hadron component intensity threshold to classify as hadron.
Definition: ECLClusterPSD.h:73
TwoComponentFitType
Offline two component fit type.
Definition: ECLDsp.h:29
@ poorChi2
All offline fit attempts were greater than chi2 threshold.
Definition: ECLDsp.h:30
@ photonDiodeCrossing
photon + diode template fit
Definition: ECLDsp.h:33
Class to store ECL Showers.
Definition: ECLShower.h:30
@ c_hasPulseShapeDiscrimination
bit 2: Shower has pulse shape discrimination variables.
Definition: ECLShower.h:61
The Class for ECL Geometry Parameters.
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
static std::map< std::string, AbstractInterface * > getSupportedInterfaces()
Returns interfaces supported by the MVA Interface.
Definition: Interface.h:53
static void initSupportedInterfaces()
Static function which initliazes all supported interfaces, has to be called once before getSupportedI...
Definition: Interface.cc:45
General options which are shared by all MVA trainings.
Definition: Options.h:62
Wraps the data of a single event into a Dataset.
Definition: Dataset.h:135
The Weightfile class serializes all information about a training into an xml tree.
Definition: Weightfile.h:38
static Weightfile loadFromStream(std::istream &stream)
Static function which deserializes a Weightfile from a stream.
Definition: Weightfile.cc:251
void getOptions(Options &options) const
Fills an Option object from the xml tree.
Definition: Weightfile.cc:67
static Weightfile loadFromFile(const std::string &filename)
Static function which loads a Weightfile from a file.
Definition: Weightfile.cc:206
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
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
Abstract base class for different kinds of events.