Belle II Software release-09-00-00
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
31using namespace Belle2;
32
33//-----------------------------------------------------------------
34// Register the Modules
35//-----------------------------------------------------------------
36REG_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
60void 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
80void 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:143
virtual const char * eclShowerArrayName() const
ECLShowers array name.
Definition: ECLClusterPSD.h:68
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 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.
void initializeMVAweightFile(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile > > &weightFileRepresentation)
initialize MVA weight file from DB
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
virtual const char * eclCalDigitArrayName() const
ECLCalDigits array name.
Definition: ECLClusterPSD.h:64
double evaluateMVA(const ECLShower *cluster)
Evaluates mva.
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.
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 void initSupportedInterfaces()
Static function which initliazes all supported interfaces, has to be called once before getSupportedI...
Definition: Interface.cc:45
static std::map< std::string, AbstractInterface * > getSupportedInterfaces()
Returns interfaces supported by the MVA Interface.
Definition: Interface.h:53
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
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
#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.