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
31#include <boost/algorithm/string/predicate.hpp>
32
33using namespace Belle2;
34
35REG_MODULE(KLMMuonIDDNNExpert);
36
38{
39 // Set module properties
40 setDescription(R"DOC(Get information from KLMMuIDLikelihood)DOC");
42}
43
45{
46}
47
49{
50 m_tracks.isRequired();
51
52 m_inputVariable.registerInDataStore();
53 m_tracks.registerRelationTo(m_inputVariable);
54
55 // setup KLM geometry
58
59 m_EndcapScintWidth = eklmGeometry.getStripGeometry()->getWidth() / CLHEP::cm; // in G4e units (cm)
60
61 for (int layer = 1; layer <= m_maxBKLMLayers; ++layer) {
62 const bklm::Module* module =
63 bklmGeometry->findModule(BKLMElementNumbers::c_ForwardSection, 1, layer);
64 m_BarrelPhiStripWidth[layer - 1] = module->getPhiStripWidth(); // in G4e units (cm)
65 m_BarrelZStripWidth[layer - 1] = module->getZStripWidth(); // in G4e units (cm)
66 }
67
69}
70
72{
73 m_expert.reset();
74 m_dataset.reset();
75}
76
78{
79 if (m_weightfile_representation.isValid()) {
80 if (m_weightfile_representation.hasChanged()) {
81 std::stringstream ss(m_weightfile_representation->m_data);
82 auto weightfile = MVA::Weightfile::loadFromStream(ss);
83 initializeMVA(weightfile);
84 }
85 } else {
86 B2FATAL("Payload " << m_identifier << " is not valid!");
87 }
88}
89
91{
92}
93
95{
96 auto supported_interfaces = MVA::AbstractInterface::getSupportedInterfaces();
97 MVA::GeneralOptions general_options;
98 weightfile.getOptions(general_options);
99 m_expert = supported_interfaces[general_options.m_method]->getExpert();
100 m_expert->load(weightfile);
101 std::vector<float> dummy;
102 int nInputVariables = general_options.m_variables.size();
103 if (nInputVariables != 5 + 4 * (m_maxBKLMLayers + m_maxEKLMLayers)) {
104 B2FATAL("Number of input variables mismatch. Required " << 5 + 4 * (m_maxBKLMLayers + m_maxEKLMLayers) << " but " << nInputVariables
105 << " given. ");
106 }
107 dummy.resize(nInputVariables, 0);
108 m_dataset = std::unique_ptr<MVA::SingleDataset>(new MVA::SingleDataset(general_options, std::move(dummy), 0));
109}
110
111
113{
114 for (Track& track : m_tracks) {
115
116 KLMMuidLikelihood* klmll = track.getRelatedTo<KLMMuidLikelihood>();
117
118 if (!klmll) continue;
119
120 // initialize hit pattern arrays
121 m_hitpattern_steplength.fill(-1.);
122 m_hitpattern_width.fill(-1.);
123 m_hitpattern_chi2.fill(-1.);
124 m_hitpattern_hasext.fill(0);
125
126 bool hasExtInKLM = false;
127 for (const ExtHit& exthit : track.getRelationsTo<ExtHit>()) {
128
129 if (exthit.getDetectorID() != Const::EDetector::BKLM
130 and exthit.getDetectorID() != Const::EDetector::EKLM) continue;
131
132 int layer;
133 bool inBKLM = (exthit.getDetectorID() == Const::EDetector::BKLM);
134 int copyid = exthit.getCopyID();
135
136 int section, sector, plane, strip;
137
138 if (inBKLM) {
139 BKLMElementNumbers::moduleNumberToElementNumbers(copyid, &section, &sector, &layer);
140 if (layer > m_maxBKLMLayers) continue;
141 m_hitpattern_hasext.at(layer - 1) = 1;
142 } else {
143 EKLMElementNumbers::Instance().stripNumberToElementNumbers(copyid, &section, &layer, &sector, &plane, &strip);
144 if (layer > m_maxEKLMLayers) continue;
145 m_hitpattern_hasext.at(m_maxBKLMLayers + layer - 1) = 1;
146 }
147
148 hasExtInKLM = true;
149
150 }
151
152 RelationVector<KLMHit2d> KLMHit2drelation = track.getRelationsTo<KLMHit2d>();
153
154 // only apply NN muonID to tracks with at least one KLMHit2d or one ExtHit in KLM.
155 if (not(hasExtInKLM || KLMHit2drelation.size())) continue;
156
157 std::map<int, int> Hit2dMap; // arrange KLMHit2d in the order of layer
158 for (long unsigned int ii = 0; ii < KLMHit2drelation.size(); ii++) {
159 KLMHit2d* klmhit = KLMHit2drelation[ii];
160 bool hit_inBKLM = (klmhit->getSubdetector() == KLMElementNumbers::c_BKLM);
161 unsigned long int hit_layer = klmhit->getLayer();
162
163 int index = hit_layer - 1 + m_maxBKLMLayers * (1 - hit_inBKLM); // BKLM hits are in front of EKLM hits
164 if (index > (m_maxBKLMLayers + m_maxEKLMLayers)) continue;
165 Hit2dMap.insert(std::pair<int, int> {index, ii});
166 }
167
168 int nklmhits = 0;
169 ROOT::Math::XYZVector previousPosition(0., 0., 0.);
170 for (auto itermap = Hit2dMap.begin(); itermap != Hit2dMap.end(); itermap ++) {
171
172 nklmhits += 1;
173
174 KLMHit2d* klmhit = KLMHit2drelation[itermap->second];
175
176 float KFchi2 = KLMHit2drelation.weight(itermap->second);
177 float width = getHitWidth(klmhit);
178
179 ROOT::Math::XYZVector hitPosition = klmhit->getPosition();
180 float steplength = 0.;
181 if (nklmhits > 1) {
182 steplength = (hitPosition - previousPosition).R();
183 }
184 previousPosition = hitPosition;
185
186 // hit pattern creation.
187 int hitpatternindex = itermap->first;
188 m_hitpattern_chi2.at(hitpatternindex) = KFchi2;
189 m_hitpattern_steplength.at(hitpatternindex) = steplength;
190 m_hitpattern_width.at(hitpatternindex) = width;
191 } // loop of Hit2dMap
192
193 Hit2dMap.clear();
194
195 double muprob_nn = getNNmuProbability(&track, klmll);
196 PIDLikelihood* pid = track.getRelated<PIDLikelihood>();
197 pid->addPreOfficialLikelihood("klmMuonIDDNN", muprob_nn);
198 } // loop of tracks
199}
200
202{
203 m_dataset->m_input[0] = klmll->getChiSquared();
204 m_dataset->m_input[1] = klmll->getDegreesOfFreedom();
205 m_dataset->m_input[2] = klmll->getExtLayer() - klmll->getHitLayer();
206 m_dataset->m_input[3] = klmll->getExtLayer();
207 m_dataset->m_input[4] = track->getTrackFitResultWithClosestMass(Const::muon)->getTransverseMomentum();
208
209 for (int layer = 0; layer < (m_maxBKLMLayers + m_maxEKLMLayers); layer ++) {
210 m_dataset->m_input[5 + 4 * layer + 0] = m_hitpattern_width.at(layer); // width
211 m_dataset->m_input[5 + 4 * layer + 1] = m_hitpattern_steplength.at(layer); // steplength
212 m_dataset->m_input[5 + 4 * layer + 2] = m_hitpattern_chi2.at(layer); // chi2
213 m_dataset->m_input[5 + 4 * layer + 3] = m_hitpattern_hasext.at(layer); // hasext
214 }
215
216 KLMMuonIDDNNInputVariable* inputVariable = m_inputVariable.appendNew();
217 inputVariable->setKLMMuonIDDNNInputVariable(m_dataset->m_input);
218 track->addRelationTo(inputVariable);
219
220 float muprob_nn = m_expert->apply(*m_dataset)[0];
221 return muprob_nn;
222}
223
225{
226 float stripwidth1 = 0; // strip width of phi or X direction
227 float stripwidth2 = 0; // strip width of Z or Y direction
228 float stripdiff1 = 0; // max minus min strip number in phi or X direction
229 float stripdiff2 = 0; // max minus min strip number in Z or Y direction
230 if (klmhit->getSubdetector() == KLMElementNumbers::c_BKLM) {
231 stripwidth1 = m_BarrelPhiStripWidth[klmhit->getLayer() - 1];
232 stripwidth2 = m_BarrelZStripWidth[klmhit->getLayer() - 1];
233 stripdiff1 = (klmhit->getPhiStripMax() - klmhit->getPhiStripMin() + 1) * 0.5;
234 stripdiff2 = (klmhit->getZStripMax() - klmhit->getZStripMin() + 1) * 0.5;
235 } else {
236 stripwidth1 = m_EndcapScintWidth;
237 stripwidth2 = m_EndcapScintWidth;
238 stripdiff1 = (klmhit->getXStripMax() - klmhit->getXStripMin() + 1) * 0.5;
239 stripdiff2 = (klmhit->getYStripMax() - klmhit->getYStripMin() + 1) * 0.5;
240 }
241 float width1 = stripwidth1 * stripdiff1;
242 float width2 = stripwidth2 * stripdiff2;
243 return std::sqrt(width1 * width1 + width2 * width2);
244}
245
246
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:650
Abstract base class for different kinds of events.