ATLAS Offline Software
Loading...
Searching...
No Matches
TFCSPredictExtrapWeights.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
11
12#include "TFile.h"
13#include "TClass.h"
14
15#include "HepPDT/ParticleData.hh"
16#include "HepPDT/ParticleDataTable.hh"
17
18#include "CLHEP/Random/RandGauss.h"
19#include "CLHEP/Random/RandFlat.h"
20
21#if defined(__FastCaloSimStandAlone__)
22#include "CLHEP/Random/TRandomEngine.h"
23#else
24#include <CLHEP/Random/RanluxEngine.h>
25#endif
26
27#include <iostream>
28#include <fstream>
29
30// LWTNN
31#include "lwtnn/LightweightGraph.hh"
32#include "lwtnn/LightweightNeuralNetwork.hh"
33#include "lwtnn/parse_json.hh"
34
35// XML reader
36#include <libxml/xmlmemory.h>
37#include <libxml/parser.h>
38#include <libxml/tree.h>
39#include <libxml/xmlreader.h>
40#include <libxml/xpath.h>
41#include <libxml/xpathInternals.h>
42
43//=============================================
44//======= TFCSPredictExtrapWeights =========
45//=============================================
46
53
54// Destructor
56 if (m_input != nullptr) {
57 delete m_input;
58 }
59 if (m_relevantLayers != nullptr) {
60 delete m_relevantLayers;
61 }
62 if (m_normLayers != nullptr) {
63 delete m_normLayers;
64 }
65 if (m_normMeans != nullptr) {
66 delete m_normMeans;
67 }
68 if (m_normStdDevs != nullptr) {
69 delete m_normStdDevs;
70 }
71 if (m_nn != nullptr) {
72 delete m_nn;
73 }
74}
75
77 const TFCSParametrizationBase &ref) const {
78 if (IsA() != ref.IsA()) {
79 ATH_MSG_DEBUG("operator==: different class types "
80 << IsA()->GetName() << " != " << ref.IsA()->GetName());
81 return false;
82 }
83 const TFCSPredictExtrapWeights &ref_typed =
84 static_cast<const TFCSPredictExtrapWeights &>(ref);
85
87 return true;
89 return false;
91 return false;
92
93 return (m_input->compare(*ref_typed.m_input) == 0);
94}
95
96// getNormInputs()
97// Get values needed to normalize inputs
99 const std::string &etaBin, const std::string &FastCaloTXTInputFolderName) {
100 ATH_MSG_DEBUG(" Getting normalization inputs... ");
101
102 // Open corresponding TXT file and extract mean/std dev for each variable
103 if (m_normLayers != nullptr) {
104 m_normLayers->clear();
105 } else {
106 m_normLayers = new std::vector<int>();
107 }
108 if (m_normMeans != nullptr) {
109 m_normMeans->clear();
110 } else {
111 m_normMeans = new std::vector<float>();
112 }
113 if (m_normStdDevs != nullptr) {
114 m_normStdDevs->clear();
115 } else {
116 m_normStdDevs = new std::vector<float>();
117 }
118 std::string inputFileName = FastCaloTXTInputFolderName +
119 "MeanStdDevEnergyFractions_eta_" + etaBin +
120 ".txt";
121 ATH_MSG_DEBUG(" Opening " << inputFileName);
122 std::ifstream inputTXT(inputFileName);
123 if (inputTXT.is_open()) {
124 std::string line;
125 while (getline(inputTXT, line)) {
126 std::stringstream ss(line);
127 unsigned int counter = 0;
128 while (ss.good()) {
129 std::string substr;
130 getline(ss, substr, ' ');
131 if (counter == 0) { // Get index (#layer or -1 if var == etrue)
132 if (substr != "etrue") {
133 int index = std::stoi(substr.substr(substr.find('_') + 1));
134 m_normLayers->push_back(index);
135 } else { // etrue
136 m_normLayers->push_back(-1);
137 }
138 } else if (counter == 1) {
139 m_normMeans->push_back(std::stof(substr));
140 } else if (counter == 2) {
141 m_normStdDevs->push_back(std::stof(substr));
142 }
143 counter++;
144 }
145 }
146 inputTXT.close();
147 } else {
148 ATH_MSG_ERROR(" Unable to open file " << inputFileName);
149 return false;
150 }
151
152 return true;
153}
154
155// prepareInputs()
156// Prepare input variables to the Neural Network
157std::map<std::string, double>
159 const float truthE) const {
160 std::map<std::string, double> inputVariables;
161 for (int ilayer = 0; ilayer < CaloCell_ID_FCS::MaxSample; ++ilayer) {
162 if (std::find(m_relevantLayers->cbegin(), m_relevantLayers->cend(),
163 ilayer) != m_relevantLayers->cend()) {
164 const std::string layer = std::to_string(ilayer);
165 // Find index
166 auto itr =
167 std::find(m_normLayers->cbegin(), m_normLayers->cend(), ilayer);
168 if (itr != m_normLayers->cend()) {
169 const int index = std::distance(m_normLayers->cbegin(), itr);
170 inputVariables["ef_" + layer] =
171 (simulstate.Efrac(ilayer) - std::as_const(m_normMeans)->at(index)) /
172 std::as_const(m_normStdDevs)->at(index);
173 } else {
174 ATH_MSG_ERROR("Normalization information not found for layer "
175 << ilayer);
176 }
177 }
178 }
179 // Find index for truth energy
180 auto itr = std::find(m_normLayers->cbegin(), m_normLayers->cend(), -1);
181 int index = std::distance(m_normLayers->cbegin(), itr);
182 inputVariables["etrue"] = (truthE - std::as_const(m_normMeans)->at(index)) /
183 std::as_const(m_normStdDevs)->at(index);
184 if (is_match_pdgid(22)) {
185 inputVariables["pdgId"] = 1; // one hot enconding
186 } else if (is_match_pdgid(11) || is_match_pdgid(-11)) {
187 inputVariables["pdgId"] = 0; // one hot enconding
188 }
189 return inputVariables;
190}
191
192// simulate()
193// get predicted extrapolation weights and save them as AuxInfo in simulstate
195 TFCSSimulationState &simulstate, const TFCSTruthState *truth,
196 const TFCSExtrapolationState * /*extrapol*/) const {
197
198 // Get inputs to Neural Network
199 std::map<std::string, double> inputVariables =
200 prepareInputs(simulstate, truth->E() * 0.001);
201
202 // Get predicted extrapolation weights
203 auto outputs = m_nn->compute(inputVariables);
204 for (int ilayer = 0; ilayer < CaloCell_ID_FCS::MaxSample; ++ilayer) {
205 if (std::find(m_relevantLayers->cbegin(), m_relevantLayers->cend(),
206 ilayer) != m_relevantLayers->cend()) {
207 ATH_MSG_DEBUG("TFCSPredictExtrapWeights::simulate: layer: "
208 << ilayer << " weight: "
209 << outputs["extrapWeight_" + std::to_string(ilayer)]);
210 float weight = outputs["extrapWeight_" + std::to_string(ilayer)];
211 // Protections
212 if (weight < 0) {
213 weight = 0;
214 } else if (weight > 1) {
215 weight = 1;
216 }
217 simulstate.setAuxInfo<float>(ilayer, weight);
218 } else { // use weight=0.5 for non-relevant layers
220 "Setting weight=0.5 for layer = " << std::to_string(ilayer));
221 simulstate.setAuxInfo<float>(ilayer, float(0.5));
222 }
223 }
224 return FCSSuccess;
225}
226
227// simulate_hit()
229 Hit &hit, TFCSSimulationState &simulstate, const TFCSTruthState * /*truth*/,
230 const TFCSExtrapolationState *extrapol) {
231
232 const int cs = calosample();
233
234 // Get corresponding predicted extrapolation weight from simulstate
235 float extrapWeight;
236 if (simulstate.hasAuxInfo(cs)) {
237 extrapWeight = simulstate.getAuxInfo<float>(cs);
238 } else { // missing AuxInfo
240 "Simulstate is not decorated with extrapolation weights for cs = "
241 << std::to_string(cs));
242 return FCSFatal;
243 }
244
245 double eta = (1. - extrapWeight) * extrapol->eta(cs, SUBPOS_ENT) +
246 extrapWeight * extrapol->eta(cs, SUBPOS_EXT);
247 double phi = (1. - extrapWeight) * extrapol->phi(cs, SUBPOS_ENT) +
248 extrapWeight * extrapol->phi(cs, SUBPOS_EXT);
249 float extrapWeight_for_r_z = extrapWeight;
250 if (UseHardcodedWeight()) {
251 extrapWeight_for_r_z = 0.5;
253 "Will use extrapWeight=0.5 for r and z when constructing a hit");
254 } else {
255 ATH_MSG_DEBUG("Will use predicted extrapWeight also for r and z when "
256 "constructing a hit");
257 }
258 double r = (1. - extrapWeight_for_r_z) * extrapol->r(cs, SUBPOS_ENT) +
259 extrapWeight_for_r_z * extrapol->r(cs, SUBPOS_EXT);
260 double z = (1. - extrapWeight_for_r_z) * extrapol->z(cs, SUBPOS_ENT) +
261 extrapWeight_for_r_z * extrapol->z(cs, SUBPOS_EXT);
262
263 if (!std::isfinite(r) || !std::isfinite(z) || !std::isfinite(eta) ||
264 !std::isfinite(phi)) {
265 ATH_MSG_WARNING("Extrapolator contains NaN or infinite number.\nSetting "
266 "center position to calo boundary.");
267 ATH_MSG_WARNING("Before fix: center_r: "
268 << r << " center_z: " << z << " center_phi: " << phi
269 << " center_eta: " << eta << " weight: " << extrapWeight
270 << " cs: " << cs);
271 // If extrapolator fails we can set position to calo boundary
272 r = extrapol->IDCaloBoundary_r();
273 z = extrapol->IDCaloBoundary_z();
274 eta = extrapol->IDCaloBoundary_eta();
275 phi = extrapol->IDCaloBoundary_phi();
276 ATH_MSG_WARNING("After fix: center_r: "
277 << r << " center_z: " << z << " center_phi: " << phi
278 << " center_eta: " << eta << " weight: " << extrapWeight
279 << " cs: " << cs);
280 }
281
282 hit.setCenter_r(r);
283 hit.setCenter_z(z);
284 hit.setCenter_eta(eta);
285 hit.setCenter_phi(phi);
286
287 ATH_MSG_DEBUG("TFCSPredictExtrapWeights: center_r: "
288 << hit.center_r() << " center_z: " << hit.center_z()
289 << " center_phi: " << hit.center_phi()
290 << " center_eta: " << hit.center_eta()
291 << " weight: " << extrapWeight << " cs: " << cs);
292
293 return FCSSuccess;
294}
295
296// initializeNetwork()
297// Initialize lwtnn network
299 int pid, const std::string &etaBin,
300 const std::string &FastCaloNNInputFolderName) {
301
303 "Using FastCaloNNInputFolderName: " << FastCaloNNInputFolderName);
304 set_pdgid(pid);
305
306 std::string inputFileName =
307 FastCaloNNInputFolderName + "NN_" + etaBin + ".json";
308 ATH_MSG_DEBUG("Will read JSON file: " << inputFileName);
309 if (inputFileName.empty()) {
310 ATH_MSG_ERROR("Could not find json file " << inputFileName);
311 return false;
312 } else {
313 ATH_MSG_INFO("For pid: " << pid << " and etaBin" << etaBin
314 << ", loading json file " << inputFileName);
315 std::ifstream input(inputFileName);
316 std::stringstream sin;
317 sin << input.rdbuf();
318 input.close();
319 auto config = lwt::parse_json(sin);
320 m_nn = new lwt::LightweightNeuralNetwork(config.inputs, config.layers,
321 config.outputs);
322 if (m_nn == nullptr) {
323 ATH_MSG_ERROR("Could not create LightWeightNeuralNetwork from "
324 << inputFileName);
325 return false;
326 }
327 if (m_input != nullptr) {
328 delete m_input;
329 }
330 m_input = new std::string(sin.str());
331 // Extract relevant layers from the outputs
332 m_relevantLayers = new std::vector<int>();
333 for (auto name : config.outputs) {
334 int layer = std::stoi(
335 name.erase(0, 13)); // remove "extrapWeight_" and convert to int
336 m_relevantLayers->push_back(layer);
337 }
338 }
339 return true;
340}
341
342// Streamer()
343void TFCSPredictExtrapWeights::Streamer(TBuffer &R__b) {
344 // Stream an object of class TFCSPredictExtrapWeights
345
346 if (R__b.IsReading()) {
347 R__b.ReadClassBuffer(TFCSPredictExtrapWeights::Class(), this);
348 if (m_nn != nullptr) {
349 delete m_nn;
350 m_nn = nullptr;
351 }
352 if (m_input && !m_input->empty()) {
353 std::stringstream sin;
354 sin.str(*m_input);
355 auto config = lwt::parse_json(sin);
356 m_nn = new lwt::LightweightNeuralNetwork(config.inputs, config.layers,
357 config.outputs);
358 }
359#ifndef __FastCaloSimStandAlone__
360 // When running inside Athena, delete input/config/normInputs to free the
361 // memory
362 if (freemem()) {
363 delete m_input;
364 m_input = nullptr;
365 }
366#endif
367 } else {
368 R__b.WriteClassBuffer(TFCSPredictExtrapWeights::Class(), this);
369 }
370}
371
372// unit_test()
373// Function for testing
375 TFCSSimulationState *simulstate, const TFCSTruthState *truth,
376 const TFCSExtrapolationState *extrapol) {
377 const std::string this_file = __FILE__;
378 const std::string parent_dir = this_file.substr(0, this_file.find("/src/"));
379 const std::string norm_path = parent_dir + "/share/NormPredExtrapSample/";
380 std::string net_path = "/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/"
381 "FastCaloSim/LWTNNPredExtrapSample/";
382 test_path(net_path, norm_path, simulstate, truth, extrapol);
383 //net_path = "/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/FastCaloSim/"
384 // "ONNXPredExtrapSample/";
385 //test_path(net_path, norm_path, simulstate, truth, extrapol);
386}
387
388// test_path()
389// Function for testing
391 std::string &net_path, std::string const &norm_path,
392 TFCSSimulationState *simulstate, const TFCSTruthState *truth,
393 const TFCSExtrapolationState *extrapol) {
395 ATH_MSG_NOCLASS(logger, "Testing net path ..."
396 << net_path.substr(net_path.length() - 20)
397 << " and norm path ..."
398 << norm_path.substr(norm_path.length() - 20));
399 if (!simulstate) {
400 simulstate = new TFCSSimulationState();
401#if defined(__FastCaloSimStandAlone__)
402 simulstate->setRandomEngine(new CLHEP::TRandomEngine());
403#else
404 simulstate->setRandomEngine(new CLHEP::RanluxEngine());
405#endif
406 }
407 if (!truth) {
409 t->SetPtEtaPhiM(524288000, 0, 0, 130); // 524288 GeV
410 t->set_pdgid(22); // photon
411 truth = t;
412 }
413 if (!extrapol) {
415 e->set_IDCaloBoundary_eta(truth->Eta());
416 for (int i = 0; i < 24; ++i) {
417 e->set_eta(i, TFCSExtrapolationState::SUBPOS_ENT, truth->Eta());
418 e->set_eta(i, TFCSExtrapolationState::SUBPOS_EXT, truth->Eta());
419 e->set_eta(i, TFCSExtrapolationState::SUBPOS_MID, truth->Eta());
420 e->set_phi(i, TFCSExtrapolationState::SUBPOS_ENT, 0);
421 e->set_phi(i, TFCSExtrapolationState::SUBPOS_EXT, 0);
422 e->set_phi(i, TFCSExtrapolationState::SUBPOS_MID, 0);
423 e->set_r(i, TFCSExtrapolationState::SUBPOS_ENT, 1500 + i * 10);
424 e->set_r(i, TFCSExtrapolationState::SUBPOS_EXT, 1510 + i * 10);
425 e->set_r(i, TFCSExtrapolationState::SUBPOS_MID, 1505 + i * 10);
426 e->set_z(i, TFCSExtrapolationState::SUBPOS_ENT, 3500 + i * 10);
427 e->set_z(i, TFCSExtrapolationState::SUBPOS_EXT, 3510 + i * 10);
428 e->set_z(i, TFCSExtrapolationState::SUBPOS_MID, 3505 + i * 10);
429 }
430 extrapol = e;
431 }
432
433 // Set energy in layers which then will be retrieved in simulate_hit()
434 simulstate->set_E(0, 1028.77124023);
435 simulstate->set_E(1, 68199.0625);
436 simulstate->set_E(2, 438270.78125);
437 simulstate->set_E(3, 3024.02929688);
438 simulstate->set_E(12, 1330.10131836);
439 simulstate->set_E(1028.77124023 + 68199.0625 + 438270.78125 + 3024.02929688 +
440 1330.10131836);
441 simulstate->set_Efrac(0, simulstate->E(0) / simulstate->E());
442 simulstate->set_Efrac(1, simulstate->E(1) / simulstate->E());
443 simulstate->set_Efrac(2, simulstate->E(2) / simulstate->E());
444 simulstate->set_Efrac(3, simulstate->E(3) / simulstate->E());
445 simulstate->set_Efrac(12, simulstate->E(12) / simulstate->E());
446
447 const int pdgId = truth->pdgid();
448 const float Ekin = truth->Ekin();
449 const float eta = truth->Eta();
450
451 ATH_MSG_NOCLASS(logger, "True energy " << Ekin << " pdgId " << pdgId
452 << " eta " << eta);
453
454 // Find eta bin
455 const int Eta = eta * 10;
456 std::string etaBin = "";
457 for (int i = 0; i <= 25; ++i) {
458 int etaTmp = i * 5;
459 if (Eta >= etaTmp && Eta < (etaTmp + 5)) {
460 etaBin = std::to_string(i * 5) + "_" + std::to_string((i + 1) * 5);
461 }
462 }
463
464 ATH_MSG_NOCLASS(logger, "etaBin = " << etaBin);
465
466 TFCSPredictExtrapWeights NN("NN", "NN");
467 NN.setLevel(MSG::INFO);
468 const int pid = truth->pdgid();
469 NN.initializeNetwork(pid, etaBin, net_path);
470 NN.getNormInputs(etaBin, norm_path);
471
472 // Get extrapWeights and save them as AuxInfo in simulstate
473
474 // Get inputs to Neural Network
475 std::map<std::string, double> inputVariables =
476 NN.prepareInputs(*simulstate, truth->E() * 0.001);
477
478 // Get predicted extrapolation weights
479 ATH_MSG_NOCLASS(logger, "computing with m_nn");
480 auto outputs = NN.m_nn->compute(inputVariables);
481 const std::vector<int> layers = {0, 1, 2, 3, 12};
482 for (int ilayer : layers) {
483 simulstate->setAuxInfo<float>(
484 ilayer, outputs["extrapWeight_" + std::to_string(ilayer)]);
485 }
486
487 // Simulate
488 const int layer = 0;
489 NN.set_calosample(layer);
491 NN.simulate_hit(hit, *simulstate, truth, extrapol);
492
493 // Write
494 TFile *fNN = new TFile("FCSNNtest.root", "RECREATE");
495 NN.Write();
496 fNN->ls();
497 fNN->Close();
498 delete fNN;
499
500 // Open
501 fNN = TFile::Open("FCSNNtest.root");
502 TFCSPredictExtrapWeights *NN2 = (TFCSPredictExtrapWeights *)(fNN->Get("NN"));
503
504 NN2->setLevel(MSG::INFO);
505 NN2->simulate_hit(hit, *simulstate, truth, extrapol);
506 //simulstate->Print();
507
508 return;
509}
510
511void TFCSPredictExtrapWeights::Print(Option_t *option) const {
512 TString opt(option);
513 bool shortprint = opt.Index("short") >= 0;
514 bool longprint = msgLvl(MSG::DEBUG) || (msgLvl(MSG::INFO) && !shortprint);
515 TString optprint = opt;
516 optprint.ReplaceAll("short", "");
518
519 if (longprint)
520 ATH_MSG_INFO(optprint << " m_input (TFCSPredictExtrapWeights): "
522 if (longprint)
523 ATH_MSG_INFO(optprint << " Address of m_nn: " << (void *)m_nn);
524}
const boost::regex ref(r_ef)
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t ss
#define ATH_MSG_NOCLASS(logger_name, x)
Definition MLogging.h:52
FCSReturnCode
Base class for all FastCaloSim parametrizations Functionality in derivde classes is provided through ...
#define z
Helper for getting a const version of a pointer.
Cut down AthMessaging.
Definition MLogging.h:176
bool msgLvl(const MSG::Level lvl) const
Check whether the logging system is active at the provided verbosity level.
Definition MLogging.h:222
virtual void setLevel(MSG::Level lvl)
Update outputlevel.
Definition MLogging.cxx:105
TFCSLateralShapeParametrizationHitBase(const char *name=nullptr, const char *title=nullptr)
void Print(Option_t *option="") const override
bool compare(const TFCSParametrizationBase &ref) const
bool compare(const TFCSParametrizationBase &ref) const
Do not persistify!
virtual bool is_match_pdgid(int id) const override
virtual void set_pdgid(int id)
bool compare(const TFCSParametrizationBase &ref) const
virtual FCSReturnCode simulate(TFCSSimulationState &simulstate, const TFCSTruthState *truth, const TFCSExtrapolationState *extrapol) const override
Method in all derived classes to do some simulation.
bool getNormInputs(const std::string &etaBin, const std::string &FastCaloTXTInputFolderName)
std::vector< float > * m_normMeans
lwt::LightweightNeuralNetwork * m_nn
virtual bool operator==(const TFCSParametrizationBase &ref) const override
The == operator compares the content of instances.
TFCSPredictExtrapWeights(const char *name=nullptr, const char *title=nullptr)
std::vector< float > * m_normStdDevs
std::vector< int > * m_relevantLayers
void Print(Option_t *option="") const override
std::vector< int > * m_normLayers
Do not persistify.
std::map< std::string, double > prepareInputs(TFCSSimulationState &simulstate, const float truthE) const
virtual FCSReturnCode simulate_hit(Hit &hit, TFCSSimulationState &simulstate, const TFCSTruthState *truth, const TFCSExtrapolationState *extrapol) override
simulated one hit position with some energy.
static void test_path(std::string &net_path, std::string const &norm_path, TFCSSimulationState *simulstate=nullptr, const TFCSTruthState *truth=nullptr, const TFCSExtrapolationState *extrapol=nullptr)
static void unit_test(TFCSSimulationState *simulstate=nullptr, const TFCSTruthState *truth=nullptr, const TFCSExtrapolationState *extrapol=nullptr)
bool initializeNetwork(int pid, const std::string &etaBin, const std::string &FastCaloNNInputFolderName)
double Efrac(int sample) const
void set_E(int sample, double Esample)
bool hasAuxInfo(std::uint32_t index) const
const T getAuxInfo(std::uint32_t index) const
void set_Efrac(int sample, double Efracsample)
void setAuxInfo(std::uint32_t index, const T &val)
void setRandomEngine(CLHEP::HepRandomEngine *engine)
int pdgid() const
double Ekin() const
int r
Definition globals.cxx:22
static Root::TMsgLogger logger("iLumiCalc")
const T * as_const_ptr(const T *p)
Helper for getting a const version of a pointer.
Definition index.py:1
#define IsA
Declare the TObject style functions.