Belle II Software development
KLMMuonIDDNNExpertModule.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#include <iostream>
10#include <fstream>
11#include <sstream>
12
13#include <reconstruction/modules/KLMMuonIDDNNExpert/KLMMuonIDDNNExpertModule.h>
14
15#include <klm/bklm/geometry/GeometryPar.h>
16#include <klm/bklm/geometry/Module.h>
17#include <klm/eklm/geometry/TransformDataGlobalAligned.h>
18
19#include <CLHEP/Units/SystemOfUnits.h>
20
21#include <framework/logging/Logger.h>
22#include <framework/datastore/StoreObjPtr.h>
23#include <framework/gearbox/Const.h>
24
25#include <tracking/dataobjects/ExtHit.h>
26
27#include <mdst/dataobjects/PIDLikelihood.h>
28
29#include <mva/interface/Interface.h>
30
31using namespace Belle2;
32
33REG_MODULE(KLMMuonIDDNNExpert);
34
36{
37 // Set module properties
38 setDescription(R"DOC(Get information from KLMMuIDLikelihood)DOC");
40}
41
43{
44}
45
47{
48 m_tracks.isRequired();
49
50 m_inputVariable.registerInDataStore();
51 m_tracks.registerRelationTo(m_inputVariable);
52
53 // setup KLM geometry
56
57 m_EndcapScintWidth = eklmGeometry.getStripGeometry()->getWidth() / CLHEP::cm; // in G4e units (cm)
58
59 for (int layer = 1; layer <= m_maxBKLMLayers; ++layer) {
60 const bklm::Module* module =
61 bklmGeometry->findModule(BKLMElementNumbers::c_ForwardSection, 1, layer);
62 m_BarrelPhiStripWidth[layer - 1] = module->getPhiStripWidth(); // in G4e units (cm)
63 m_BarrelZStripWidth[layer - 1] = module->getZStripWidth(); // in G4e units (cm)
64 }
65
67}
68
70{
71 m_expert.reset();
72 m_dataset.reset();
73}
74
76{
77 if (m_weightfile_representation.isValid()) {
78 if (m_weightfile_representation.hasChanged()) {
79 std::stringstream ss(m_weightfile_representation->m_data);
80 auto weightfile = MVA::Weightfile::loadFromStream(ss);
81 initializeMVA(weightfile);
82 }
83 } else {
84 B2FATAL("Payload " << m_identifier << " is not valid!");
85 }
86}
87
89{
90}
91
93{
94 auto supported_interfaces = MVA::AbstractInterface::getSupportedInterfaces();
95 MVA::GeneralOptions general_options;
96 weightfile.getOptions(general_options);
97 m_expert = supported_interfaces[general_options.m_method]->getExpert();
98 m_expert->load(weightfile);
99 std::vector<float> dummy;
100 int nInputVariables = general_options.m_variables.size();
101 if (nInputVariables != 5 + 4 * (m_maxBKLMLayers + m_maxEKLMLayers)) {
102 B2FATAL("Number of input variables mismatch. Required " << 5 + 4 * (m_maxBKLMLayers + m_maxEKLMLayers) << " but " << nInputVariables
103 << " given. ");
104 }
105 dummy.resize(nInputVariables, 0);
106 m_dataset = std::unique_ptr<MVA::SingleDataset>(new MVA::SingleDataset(general_options, std::move(dummy), 0));
107}
108
109
111{
112 for (Track& track : m_tracks) {
113
114 KLMMuidLikelihood* klmll = track.getRelatedTo<KLMMuidLikelihood>();
115
116 if (!klmll) continue;
117
118 // initialize hit pattern arrays
119 m_hitpattern_steplength.fill(-1.);
120 m_hitpattern_width.fill(-1.);
121 m_hitpattern_chi2.fill(-1.);
122 m_hitpattern_hasext.fill(0);
123
124 bool hasExtInKLM = false;
125 for (const ExtHit& exthit : track.getRelationsTo<ExtHit>()) {
126
127 if (exthit.getDetectorID() != Const::EDetector::BKLM
128 and exthit.getDetectorID() != Const::EDetector::EKLM) continue;
129
130 int layer;
131 bool inBKLM = (exthit.getDetectorID() == Const::EDetector::BKLM);
132 int copyid = exthit.getCopyID();
133
134 int section, sector, plane, strip;
135
136 if (inBKLM) {
137 BKLMElementNumbers::moduleNumberToElementNumbers(copyid, &section, &sector, &layer);
138 if (layer > m_maxBKLMLayers) continue;
139 m_hitpattern_hasext.at(layer - 1) = 1;
140 } else {
141 EKLMElementNumbers::Instance().stripNumberToElementNumbers(copyid, &section, &layer, &sector, &plane, &strip);
142 if (layer > m_maxEKLMLayers) continue;
143 m_hitpattern_hasext.at(m_maxBKLMLayers + layer - 1) = 1;
144 }
145
146 hasExtInKLM = true;
147
148 }
149
150 RelationVector<KLMHit2d> KLMHit2drelation = track.getRelationsTo<KLMHit2d>();
151
152 // only apply NN muonID to tracks with at least one KLMHit2d or one ExtHit in KLM.
153 if (not(hasExtInKLM || KLMHit2drelation.size())) continue;
154
155 std::map<int, int> Hit2dMap; // arrange KLMHit2d in the order of layer
156 for (long unsigned int ii = 0; ii < KLMHit2drelation.size(); ii++) {
157 KLMHit2d* klmhit = KLMHit2drelation[ii];
158 bool hit_inBKLM = (klmhit->getSubdetector() == KLMElementNumbers::c_BKLM);
159 unsigned long int hit_layer = klmhit->getLayer();
160
161 int index = hit_layer - 1 + m_maxBKLMLayers * (1 - hit_inBKLM); // BKLM hits are in front of EKLM hits
162 if (index > (m_maxBKLMLayers + m_maxEKLMLayers)) continue;
163 Hit2dMap.insert(std::pair<int, int> {index, ii});
164 }
165
166 int nklmhits = 0;
167 ROOT::Math::XYZVector previousPosition(0., 0., 0.);
168 for (auto itermap = Hit2dMap.begin(); itermap != Hit2dMap.end(); itermap ++) {
169
170 nklmhits += 1;
171
172 KLMHit2d* klmhit = KLMHit2drelation[itermap->second];
173
174 float KFchi2 = KLMHit2drelation.weight(itermap->second);
175 float width = getHitWidth(klmhit);
176
177 ROOT::Math::XYZVector hitPosition = klmhit->getPosition();
178 float steplength = 0.;
179 if (nklmhits > 1) {
180 steplength = (hitPosition - previousPosition).R();
181 }
182 previousPosition = hitPosition;
183
184 // hit pattern creation.
185 int hitpatternindex = itermap->first;
186 m_hitpattern_chi2.at(hitpatternindex) = KFchi2;
187 m_hitpattern_steplength.at(hitpatternindex) = steplength;
188 m_hitpattern_width.at(hitpatternindex) = width;
189 } // loop of Hit2dMap
190
191 Hit2dMap.clear();
192
193 double muprob_nn = getNNmuProbability(&track, klmll);
194 PIDLikelihood* pid = track.getRelated<PIDLikelihood>();
195 pid->addPreOfficialLikelihood("klmMuonIDDNN", muprob_nn);
196 } // loop of tracks
197}
198
200{
201 m_dataset->m_input[0] = klmll->getChiSquared();
202 m_dataset->m_input[1] = klmll->getDegreesOfFreedom();
203 m_dataset->m_input[2] = klmll->getExtLayer() - klmll->getHitLayer();
204 m_dataset->m_input[3] = klmll->getExtLayer();
205 m_dataset->m_input[4] = track->getTrackFitResultWithClosestMass(Const::muon)->getTransverseMomentum();
206
207 for (int layer = 0; layer < (m_maxBKLMLayers + m_maxEKLMLayers); layer ++) {
208 m_dataset->m_input[5 + 4 * layer + 0] = m_hitpattern_width.at(layer); // width
209 m_dataset->m_input[5 + 4 * layer + 1] = m_hitpattern_steplength.at(layer); // steplength
210 m_dataset->m_input[5 + 4 * layer + 2] = m_hitpattern_chi2.at(layer); // chi2
211 m_dataset->m_input[5 + 4 * layer + 3] = m_hitpattern_hasext.at(layer); // hasext
212 }
213
214 KLMMuonIDDNNInputVariable* inputVariable = m_inputVariable.appendNew();
215 inputVariable->setKLMMuonIDDNNInputVariable(m_dataset->m_input);
216 track->addRelationTo(inputVariable);
217
218 float muprob_nn = m_expert->apply(*m_dataset)[0];
219 return muprob_nn;
220}
221
223{
224 float stripwidth1 = 0; // strip width of phi or X direction
225 float stripwidth2 = 0; // strip width of Z or Y direction
226 float stripdiff1 = 0; // max minus min strip number in phi or X direction
227 float stripdiff2 = 0; // max minus min strip number in Z or Y direction
228 if (klmhit->getSubdetector() == KLMElementNumbers::c_BKLM) {
229 stripwidth1 = m_BarrelPhiStripWidth[klmhit->getLayer() - 1];
230 stripwidth2 = m_BarrelZStripWidth[klmhit->getLayer() - 1];
231 stripdiff1 = (klmhit->getPhiStripMax() - klmhit->getPhiStripMin() + 1) * 0.5;
232 stripdiff2 = (klmhit->getZStripMax() - klmhit->getZStripMin() + 1) * 0.5;
233 } else {
234 stripwidth1 = m_EndcapScintWidth;
235 stripwidth2 = m_EndcapScintWidth;
236 stripdiff1 = (klmhit->getXStripMax() - klmhit->getXStripMin() + 1) * 0.5;
237 stripdiff2 = (klmhit->getYStripMax() - klmhit->getYStripMin() + 1) * 0.5;
238 }
239 float width1 = stripwidth1 * stripdiff1;
240 float width2 = stripwidth2 * stripdiff2;
241 return std::sqrt(width1 * width1 + width2 * width2);
242}
243
244
double R
typedef autogenerated by FFTW
static void moduleNumberToElementNumbers(KLMModuleNumber module, int *section, int *sector, int *layer)
Get element numbers by module number.
static const ChargedStable muon
muon particle
Definition: Const.h:660
static const EKLMElementNumbers & Instance()
Instantiation.
void stripNumberToElementNumbers(int stripGlobal, int *section, int *layer, int *sector, int *plane, int *strip) const
Get element numbers by strip global number.
double getWidth() const
Get width.
const StripGeometry * getStripGeometry() const
Get strip geometry data.
EKLM geometry data.
Definition: GeometryData.h:38
static const GeometryData & Instance(enum DataSource dataSource=c_Database, const GearDir *gearDir=nullptr)
Instantiation.
Definition: GeometryData.cc:33
Store one Ext hit as a ROOT object.
Definition: ExtHit.h:31
KLM 2d hit.
Definition: KLMHit2d.h:33
Class to store the likelihoods from KLM with additional information related to the extrapolation.
int getDegreesOfFreedom() const
Get the number of degrees of freedom (= 2 times the number of KLM hits) for the chi-squared computati...
int getHitLayer() const
Get the outermost KLM layer actually crossed by the track.
int getExtLayer() const
Get the outermost KLM layer crossed in the extrapolation.
double getChiSquared() const
Get the chi-squared of the extrapolation.
std::array< float, m_maxBKLMLayers+m_maxEKLMLayers > m_hitpattern_width
Container of hit widths of one track.
std::unique_ptr< MVA::SingleDataset > m_dataset
Pointer to the current dataset.
void initialize() override
Initializer.
float getHitWidth(const KLMHit2d *klmhit)
Get Hit width (cluster size) of a KLMHit2d.
void event() override
This method is called for each event.
float m_EndcapScintWidth
EKLM scintillator strip width (cm).
void endRun() override
This method is called if the current run ends.
static constexpr int m_maxBKLMLayers
Total BKLM layers.
std::array< float, m_maxBKLMLayers+m_maxEKLMLayers > m_hitpattern_chi2
Container of hit chi2 of one track.
void terminate() override
This method is called at the end of the event processing.
std::unique_ptr< MVA::Expert > m_expert
Pointer to the current MVA expert.
void beginRun() override
Called when entering a new run.
StoreArray< Track > m_tracks
Required array for Tracks.
std::array< float, m_maxBKLMLayers+m_maxEKLMLayers > m_hitpattern_steplength
Container of hit steplength of one track.
float getNNmuProbability(const Track *track, const KLMMuidLikelihood *klmll)
Get the NN-based muon probability.
std::array< float, m_maxBKLMLayers > m_BarrelPhiStripWidth
BKLM phi-measuring strip width (cm) by layer.
DBObjPtr< DatabaseRepresentationOfWeightfile > m_weightfile_representation
Database pointer to the database representation of the weightfile.
void initializeMVA(MVA::Weightfile &weightfile)
Initialize mva expert, dataset and features.
std::array< float, m_maxBKLMLayers > m_BarrelZStripWidth
BKLM Z-measuring strip width (cm) by layer.
std::array< bool, m_maxBKLMLayers+m_maxEKLMLayers > m_hitpattern_hasext
Container of extrapolation situation at each KLM layer of one track.
const std::string m_identifier
Database identifier or file used to load the weights.
StoreArray< KLMMuonIDDNNInputVariable > m_inputVariable
Input variables of DNN.
static constexpr int m_maxEKLMLayers
Total EKLM layers.
KLM MuonID DNN input variables datastore object to store the input variables for retraining KLMMuonID...
void setKLMMuonIDDNNInputVariable(const std::vector< float > &inputdata)
set the DNN input variables.
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
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
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:29
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
Class that bundles various TrackFitResults.
Definition: Track.h:25
Provides BKLM geometry parameters for simulation, reconstruction etc (from Gearbox or DataBase)
Definition: GeometryPar.h:37
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
Definition: GeometryPar.cc:721
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Definition: GeometryPar.cc:27
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition: Module.h:76
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:649
Abstract base class for different kinds of events.