diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/CMakeLists.txt b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/CMakeLists.txt index 841244ff8fec9c15c8db3b0eaae3cd5beb3bc1f8..661a73d698e922250351f17bff06658064ac32f6 100644 --- a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/CMakeLists.txt +++ b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/CMakeLists.txt @@ -23,6 +23,8 @@ atlas_depends_on_subdirs( find_package( CLHEP ) find_package( HepPDT ) find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO Matrix Physics ) +find_package( lwtnn REQUIRED ) +find_package( LibXml2 ) # Remove the --as-needed linker flags: atlas_disable_as_needed() @@ -64,6 +66,7 @@ atlas_add_root_dictionary( ISF_FastCaloSimEvent _dictSource ISF_FastCaloSimEvent/TFCSEnergyParametrization.h ISF_FastCaloSimEvent/TFCSPCAEnergyParametrization.h ISF_FastCaloSimEvent/TFCSEnergyBinParametrization.h + ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h ISF_FastCaloSimEvent/TFCSLateralShapeParametrization.h ISF_FastCaloSimEvent/TFCSLateralShapeParametrizationHitBase.h ISF_FastCaloSimEvent/TFCSLateralShapeParametrizationHitChain.h @@ -92,9 +95,9 @@ atlas_add_root_dictionary( ISF_FastCaloSimEvent _dictSource atlas_add_library( ISF_FastCaloSimEvent ISF_FastCaloSimEvent/*.h ${_dictSource} src/*.cxx PUBLIC_HEADERS ISF_FastCaloSimEvent - INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} DEFINITIONS ${CLHEP_DEFINITIONS} - LINK_LIBRARIES ${CLHEP_LIBRARIES} ${HEPPDT_LIBRARIES} ${ROOT_LIBRARIES} AthContainers SGTools AthenaKernel AthenaBaseComps CaloDetDescrLib + LINK_LIBRARIES ${CLHEP_LIBRARIES} ${HEPPDT_LIBRARIES} ${ROOT_LIBRARIES} AthContainers SGTools AthenaKernel AthenaBaseComps CaloDetDescrLib ${LWTNN_LIBRARIES} ${LIBXML2_LIBRARIES} CaloGeoHelpers TileSimEvent PRIVATE_LINK_LIBRARIES GaudiKernel ) diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/LinkDef.h b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/LinkDef.h index b0b004bf34018e54cdee51c057f2c275dd68ed2f..503cdc8a1af64a32745dfa43edb768c02256acff 100644 --- a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/LinkDef.h +++ b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/LinkDef.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ #include "ISF_FastCaloSimEvent/DoubleArray.h" @@ -39,6 +39,7 @@ #include "ISF_FastCaloSimEvent/TFCSEnergyParametrization.h" #include "ISF_FastCaloSimEvent/TFCSPCAEnergyParametrization.h" #include "ISF_FastCaloSimEvent/TFCSEnergyBinParametrization.h" +#include "ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h" #include "ISF_FastCaloSimEvent/TFCSLateralShapeParametrization.h" #include "ISF_FastCaloSimEvent/TFCSLateralShapeParametrizationHitBase.h" @@ -202,6 +203,7 @@ #pragma link C++ class TFCSEnergyParametrization+; #pragma link C++ class TFCSPCAEnergyParametrization-; #pragma link C++ class TFCSEnergyBinParametrization+; +#pragma link C++ class TFCSEnergyAndHitGAN-; #pragma link C++ class TFCSLateralShapeParametrization+; #pragma link C++ class TFCSLateralShapeParametrizationHitBase+; diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h new file mode 100644 index 0000000000000000000000000000000000000000..a97c4905f2368b629c8508b60210b58f3eb0ce11 --- /dev/null +++ b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ISF_FASTCALOSIMEVENT_TFCSEnergyAndHitGAN_h +#define ISF_FASTCALOSIMEVENT_TFCSEnergyAndHitGAN_h + +#include "ISF_FastCaloSimEvent/TFCSParametrizationBinnedChain.h" +#include "ISF_FastCaloSimEvent/TFCSSimulationState.h" +#include "lwtnn/LightweightGraph.hh" +#include <string> +#include "TH2D.h" + +class TFCSEnergyAndHitGAN:public TFCSParametrizationBinnedChain { +public: + // type of input requested by lwtnn + typedef std::map<std::string, std::map<std::string, double> > NetworkInputs ; + typedef std::map<std::string, double> NetworkOutputs; + typedef std::map<int, TH2D> Binning; + + TFCSEnergyAndHitGAN(const char* name=nullptr, const char* title=nullptr); + virtual ~TFCSEnergyAndHitGAN(); + + ///Status bit for chain persistency + enum FCSGANfreemem { + kGANfreemem = BIT(17) ///< Set this bit in the TObject bit if the memory for m_input should be freed after reading in athena + }; + + bool GANfreemem() const {return TestBit(kGANfreemem);}; + void set_GANfreemem() {SetBit(kGANfreemem);}; + void reset_GANfreemem() {ResetBit(kGANfreemem);}; + + /// use the layer to be done as binning of the GAN chain + virtual int get_bin(TFCSSimulationState& simulstate,const TFCSTruthState*, const TFCSExtrapolationState*) const override {return simulstate.getAuxInfo<int>("GANlayer"_FCShash);}; + virtual const std::string get_variable_text(TFCSSimulationState& simulstate,const TFCSTruthState*, const TFCSExtrapolationState*) const override; + + unsigned int get_nr_of_init(unsigned int bin) const; + void set_nr_of_init(unsigned int bin,unsigned int ninit); + + const Binning& get_Binning() const {return m_Binning;}; + const lwt::LightweightGraph* get_graph() const {return m_graph;}; + const std::string* get_input() const {return m_input;}; + + bool initializeNetwork(int pid,int etaMin,std::string FastCaloGANInputFolderName); + + bool fillFastCaloGanNetworkInputs(TFCSSimulationState& simulstate,const TFCSTruthState* truth, NetworkInputs & inputs,double & trueEnergy) const; + bool fillEnergy(TFCSSimulationState& simulstate, const TFCSTruthState* truth, const TFCSExtrapolationState* extrapol, NetworkInputs inputs) const; + virtual FCSReturnCode simulate(TFCSSimulationState& simulstate,const TFCSTruthState* truth, const TFCSExtrapolationState* extrapol) const override; + + virtual void Print(Option_t *option="") const override; + + static void unit_test(TFCSSimulationState* simulstate=nullptr,const TFCSTruthState* truth=nullptr, const TFCSExtrapolationState* extrapol=nullptr); + +protected: + void GetBinning(int pid,int etaMax,std::string FastCaloGANInputFolderName); + +private: + std::vector< int > m_bin_ninit; + + //Persistify configuration in string m_input. A custom Streamer(...) builds m_graph on the fly when reading from file. + //Inside Athena, if GANfreemem() is true, the content of m_input is deleted after reading in order to free memory + std::string* m_input=nullptr; + lwt::LightweightGraph* m_graph=nullptr;//!Do not persistify + + Binning m_Binning; + + // specific to architecture + // preprocessing of input + int m_GANLatentSize = 0; + + ClassDefOverride(TFCSEnergyAndHitGAN,2) //TFCSEnergyAndHitGAN +}; + +#endif diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSEnergyAndHitGAN.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSEnergyAndHitGAN.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a4a241619301a932489ada786996a82d6f88a80e --- /dev/null +++ b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSEnergyAndHitGAN.cxx @@ -0,0 +1,603 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ISF_FastCaloSimEvent/TFCSEnergyAndHitGAN.h" +#include "ISF_FastCaloSimEvent/TFCSLateralShapeParametrizationHitBase.h" +#include "ISF_FastCaloSimEvent/TFCSSimulationState.h" +#include "ISF_FastCaloSimEvent/TFCSTruthState.h" +#include "ISF_FastCaloSimEvent/TFCSExtrapolationState.h" +#include "ISF_FastCaloSimEvent/TFCSCenterPositionCalculation.h" + +#include "TFile.h" + +#include "HepPDT/ParticleData.hh" +#include "HepPDT/ParticleDataTable.hh" + +#include "CLHEP/Random/RandGauss.h" +#include "CLHEP/Random/RandFlat.h" + +#if defined(__FastCaloSimStandAlone__) +#include "CLHEP/Random/TRandomEngine.h" +#else +#include <CLHEP/Random/RanluxEngine.h> +#endif + +#include <iostream> +#include <fstream> + +//LWTNN +#include "lwtnn/parse_json.hh" + +// XML reader +#include <libxml/xmlmemory.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xmlreader.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +//============================================= +//======= TFCSEnergyAndHitGAN ========= +//============================================= + +TFCSEnergyAndHitGAN::TFCSEnergyAndHitGAN(const char* name, const char* title):TFCSParametrizationBinnedChain(name,title) +{ + set_GANfreemem(); +} + +TFCSEnergyAndHitGAN::~TFCSEnergyAndHitGAN() +{ + if(m_input!=nullptr) { + delete m_input; + } + if(m_graph!=nullptr) { + delete m_graph; + } +} + +unsigned int TFCSEnergyAndHitGAN::get_nr_of_init(unsigned int bin) const +{ + if(bin>=m_bin_ninit.size()) return 0; + return m_bin_ninit[bin]; +} + +void TFCSEnergyAndHitGAN::set_nr_of_init(unsigned int bin,unsigned int ninit) +{ + if(bin<=m_bin_ninit.size()) { + m_bin_ninit.resize(bin+1,0); + m_bin_ninit.shrink_to_fit(); + } + m_bin_ninit[bin]=ninit; +} + +// initialize lwtnn network +bool TFCSEnergyAndHitGAN::initializeNetwork(int pid,int etaMin,std::string FastCaloGANInputFolderName) +{ + + // initialize all necessary constants + // FIXME eventually all these could be stored in the .json file + + ATH_MSG_INFO("Using FastCaloGANInputFolderName: " << FastCaloGANInputFolderName ); + // get neural net JSON file as an std::istream object + int etaMax = etaMin + 5; + + reset_match_all_pdgid(); + set_pdgid(pid); + if(pid==11) add_pdgid(-pid); + if(pid==211) add_pdgid(-pid); + set_eta_min(etaMin/100.0); + set_eta_max(etaMax/100.0); + set_eta_nominal((etaMin+etaMax)/200.0); + + std::string inputFile = FastCaloGANInputFolderName + "/neural_net_" + std::to_string(pid) +"_eta_" + std::to_string(etaMin) +"_" + std::to_string(etaMax) +".json"; + if (inputFile.empty()){ + ATH_MSG_ERROR("Could not find json file " << inputFile ); + return false; + } else { + ATH_MSG_INFO("For pid: " << pid <<" and eta " << etaMin <<"-" << etaMax <<", loading json file " << inputFile ); + std::ifstream input(inputFile); + std::stringstream sin; + sin << input.rdbuf(); + input.close(); + // build the graph + auto config=lwt::parse_json_graph(sin); + m_graph=new lwt::LightweightGraph(config); + if (m_graph==nullptr){ + ATH_MSG_ERROR("Could not create LightWeightGraph from " << inputFile ); + return false; + } + if(m_input!=nullptr) { + delete m_input; + } + m_input = new std::string(sin.str()); + } + m_GANLatentSize = 50; + + //Get all Binning histograms to store in memory + GetBinning(pid,(etaMin+etaMax)/2,FastCaloGANInputFolderName); + + if (m_GANLatentSize==0){ + ATH_MSG_ERROR("m_GANLatentSize uninitialized!"); + return false; + } + + return true; +} + +void TFCSEnergyAndHitGAN::GetBinning(int pid,int etaMid,std::string FastCaloGANInputFolderName){ + std::string xmlFullFileName = FastCaloGANInputFolderName + "/binning.xml"; + ATH_MSG_DEBUG("Opening XML file in "<< xmlFullFileName); + + std::vector<Binning> AllBinning; + std::vector<int> EtaMaxList; + + xmlDocPtr doc = xmlParseFile( xmlFullFileName.c_str() ); + for( xmlNodePtr nodeRoot = doc->children; nodeRoot != NULL; nodeRoot = nodeRoot->next) { + if (xmlStrEqual( nodeRoot->name, BAD_CAST "Bins" )) { + for( xmlNodePtr nodeBin = nodeRoot->children; nodeBin != NULL; nodeBin = nodeBin->next ) { + if (xmlStrEqual( nodeBin->name, BAD_CAST "Bin" )) { + int nodePid = atof( (const char*) xmlGetProp( nodeBin, BAD_CAST "pid" ) ); + //int nodeEtaMin = atof( (const char*) xmlGetProp( nodeBin, BAD_CAST "etaMin" ) ); + int nodeEtaMax = atof( (const char*) xmlGetProp( nodeBin, BAD_CAST "etaMax" ) ); + + Binning binsInLayer; + bool correctentry=true; + if(nodePid!=pid) correctentry=false; + + for( xmlNodePtr nodeLayer = nodeBin->children; nodeLayer != NULL; nodeLayer = nodeLayer->next ) { + if( xmlStrEqual( nodeLayer->name, BAD_CAST "Layer" ) ) { + std::vector<double> edges; + std::string s( (const char*)xmlGetProp( nodeLayer, BAD_CAST "r_edges" ) ); + + std::istringstream ss(s); + std::string token; + + while(std::getline(ss, token, ',')) { + edges.push_back(atof( token.c_str() )); + } + + int binsInAlpha = atof( (const char*) xmlGetProp( nodeLayer, BAD_CAST "n_bin_alpha" ) ); + int layer = atof( (const char*) xmlGetProp( nodeLayer, BAD_CAST "id" ) ); + + if(correctentry) ATH_MSG_DEBUG("nodepid="<<nodePid<<" nodeEtaMax="<<nodeEtaMax<<" Layer: "<<layer<<" binsInAlpha: "<<binsInAlpha<<" edges: "<< s); + + std::string name = "hist_pid_" + std::to_string(nodePid) + "_etaSliceNumber_" + std::to_string(EtaMaxList.size()) + "_layer_" + std::to_string(layer); + int xBins = edges.size()-1; + if (xBins == 0) xBins = 1; //remove warning + binsInLayer[layer] = TH2D(name.c_str(), name.c_str(), xBins, &edges[0], binsInAlpha, -TMath::Pi(), TMath::Pi()); + } + } + + if(!correctentry) continue; + AllBinning.push_back(binsInLayer); + EtaMaxList.push_back(nodeEtaMax); + } + } + } + } + + int index = 0; + for (int etaMax : EtaMaxList){ + if (etaMid < etaMax) { + m_Binning=AllBinning[index]; + break; + } + index++; + } + + ATH_MSG_DEBUG("Done XML file"); +} + + +const std::string TFCSEnergyAndHitGAN::get_variable_text(TFCSSimulationState& simulstate,const TFCSTruthState*, const TFCSExtrapolationState*) const +{ + return std::string(Form("layer=%d",simulstate.getAuxInfo<int>("GANlayer"_FCShash))); +} + +bool TFCSEnergyAndHitGAN::fillFastCaloGanNetworkInputs(TFCSSimulationState& simulstate,const TFCSTruthState* truth, NetworkInputs & inputs,double & trueEnergy) const +{ + // fill randomize latent space + //FIXME: should this really be momentum + trueEnergy = truth->P(); + double randUniformZ = 0.; + //FIXME: make dependency on input particle eta, pdgid and energy + for (int i = 0; i< m_GANLatentSize; i ++) + { + randUniformZ = CLHEP::RandFlat::shoot(simulstate.randomEngine(), -1., 1.); + inputs["node_0"].insert ( std::pair<std::string,double>(std::to_string(i), randUniformZ) ); + } + + //std::cout << "Check label: " <<trueEnergy <<" "<<std::pow(2,22)<<" "<<trueEnergy/std::pow(2,22)<<std::endl; + inputs["node_1"].insert ( std::pair<std::string,double>("0", trueEnergy/(std::pow(2,22))) ); + + return true; +} + +bool TFCSEnergyAndHitGAN::fillEnergy(TFCSSimulationState& simulstate, const TFCSTruthState* truth, const TFCSExtrapolationState* extrapol, NetworkInputs inputs) const +{ + const int pdgId = truth->pdgid(); + const double charge = HepPDT::ParticleID(pdgId).charge(); + const double EKin = truth->Ekin(); + + ATH_MSG_VERBOSE("Momentum " << truth->P() <<" pdgId " << truth->pdgid()); + + // compute the network output values + //ATH_MSG_VERBOSE("neural network input = "<<inputs); + ATH_MSG_VERBOSE("input size " << inputs["node_0"].size()); + NetworkOutputs outputs = m_graph->compute(inputs); + //ATH_MSG_VERBOSE("neural network output = "<<outputs); + + ATH_MSG_VERBOSE("neural network output size = "<<outputs.size()); + + const Binning& binsInLayers = m_Binning; + ATH_MSG_VERBOSE("Get binning"); + + int vox = 0; + for (auto element : binsInLayers){ + int layer = element.first; + simulstate.setAuxInfo<int>("GANlayer"_FCShash,layer); + TFCSLateralShapeParametrizationHitBase::Hit hit; + + if(get_number_of_bins()>0) { + const int bin=get_bin(simulstate,truth,extrapol); + if(bin>=0 && bin<(int)get_number_of_bins()) { + for(unsigned int ichain=m_bin_start[bin];ichain<TMath::Min(m_bin_start[bin]+get_nr_of_init(bin),m_bin_start[bin+1]);++ichain) { + ATH_MSG_DEBUG("for "<<get_variable_text(simulstate,truth,extrapol)<<" run init "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()); + if(chain()[ichain]->InheritsFrom(TFCSLateralShapeParametrizationHitBase::Class())) { + TFCSLateralShapeParametrizationHitBase* sim=(TFCSLateralShapeParametrizationHitBase*)(chain()[ichain]); + if(sim->simulate_hit(hit,simulstate,truth,extrapol)!=FCSSuccess) { + ATH_MSG_ERROR("error for "<<get_variable_text(simulstate,truth,extrapol)<<" run init "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()); + return false; + } + } else { + ATH_MSG_ERROR("for "<<get_variable_text(simulstate,truth,extrapol)<<" run init "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()<<" does not inherit from TFCSLateralShapeParametrizationHitBase"); + return false; + } + } + } else { + ATH_MSG_WARNING("nothing to init for "<<get_variable_text(simulstate,truth,extrapol)<<": "<<get_bin_text(bin)); + } + } + + int binResolution = 5; + if (layer == 1 || layer == 5){ + binResolution = 1; + } + + const double center_eta = hit.center_eta(); + const double center_phi = hit.center_phi(); + const double center_r = hit.center_r(); + const double center_z = hit.center_z(); + + ATH_MSG_VERBOSE(" Layer "<< layer + << " Extrap eta " << center_eta + << " phi " << center_phi + << " R " << center_r); + + const float dist000 = TMath::Sqrt(center_r * center_r + center_z * center_z); + const float eta_jakobi = TMath::Abs(2.0 * TMath::Exp(-center_eta) / (1.0 + TMath::Exp(-2 * center_eta))); + + int nHitsAlpha; + int nHitsR; + + TH2D* h = &element.second; + int xBinNum = h->GetNbinsX(); + //If only one bin in r means layer is empty, no value should be added + if (xBinNum == 1) { + ATH_MSG_VERBOSE(" Layer "<< layer + << " has only one bin in r, this means is it not used, skipping (this is needed to keep correct syncronisation of voxel and layers)"); + //delete h; + continue; + } + int yBinNum = h->GetNbinsY(); + for (int iy = 1; iy <= yBinNum; ++iy){ + for (int ix = 1; ix <= xBinNum; ++ix){ + double energyInVoxel = outputs["out_" + std::to_string(vox)]; + ATH_MSG_VERBOSE(" Vox "<< vox + << " energy " << energyInVoxel + << " binx " << ix + << " biny " << iy); + + if (energyInVoxel == 0){ + vox++; + continue; + } + + simulstate.add_E(layer,EKin*energyInVoxel); + + TAxis* x = (TAxis*)h->GetXaxis(); + nHitsR = x->GetBinUpEdge(ix) - x->GetBinLowEdge(ix); + if (yBinNum == 1){ + //nbins in alpha depend on circumference lenght + double r = x->GetBinUpEdge(ix); + nHitsAlpha = ceil(2 * TMath::Pi() * r / binResolution); + } + else{ + //d = 2•r•sin (a/2r) this distance at the upper r must be 1mm for layer 1 or 5, 5mm otherwise. + TAxis* y = (TAxis*)h->GetYaxis(); + double angle = y->GetBinUpEdge(iy) - y->GetBinLowEdge(iy); + double r = x->GetBinUpEdge(ix); + double d = 2 * r * sin(angle/2*r); + nHitsAlpha = ceil(d/binResolution); + } + + nHitsAlpha = std::min(10,std::max(1,nHitsAlpha)); + nHitsR = std::min(10,std::max(1,nHitsR)); + + for (int ir = 0; ir < nHitsR; ++ir){ + TAxis* x = (TAxis*)h->GetXaxis(); + double r = x->GetBinLowEdge(ix) + x->GetBinWidth(ix)/(nHitsR+1)*ir; + + + for (int ialpha = 0; ialpha < nHitsAlpha; ++ialpha){ + double alpha; + if (yBinNum == 1){ + alpha = CLHEP::RandFlat::shoot(simulstate.randomEngine(), -M_PI , M_PI); + } + else { + TAxis* y = (TAxis*)h->GetYaxis(); + alpha = y->GetBinLowEdge(iy) + y->GetBinWidth(iy)/(nHitsAlpha+1)*ialpha; + } + + hit.reset(); + hit.E()=EKin*energyInVoxel/(nHitsAlpha*nHitsR); + + if (layer <=20){ + float delta_eta_mm = r * cos(alpha); + float delta_phi_mm = r * sin(alpha); + + ATH_MSG_VERBOSE("delta_eta_mm "<< delta_eta_mm << " delta_phi_mm "<< delta_phi_mm); + + // Particles with negative eta are expected to have the same shape as those with positive eta after transformation: delta_eta --> -delta_eta + if(center_eta<0.)delta_eta_mm = -delta_eta_mm; + // Particle with negative charge are expected to have the same shape as positively charged particles after transformation: delta_phi --> -delta_phi + if(charge < 0.) delta_phi_mm = -delta_phi_mm; + + const float delta_eta = delta_eta_mm / eta_jakobi / dist000; + const float delta_phi = delta_phi_mm / center_r; + + hit.eta() = center_eta + delta_eta; + hit.phi() = center_phi + delta_phi; + + ATH_MSG_VERBOSE(" Hit eta " << hit.eta() + << " phi " << hit.phi() + << " layer " << layer ); + } + else { //FCAL is in (x,y,z) + const float hit_r = r*cos(alpha) + center_r; + float delta_phi = r*sin(alpha)/center_r; + + // Particle with negative charge are expected to have the same shape as positively charged particles after transformation: delta_phi --> -delta_phi + if(charge < 0.) delta_phi = -delta_phi; + const float hit_phi= delta_phi + center_phi; + hit.x() = hit_r*cos(hit_phi); + hit.y() = hit_r*sin(hit_phi); + hit.z() = center_z; + ATH_MSG_VERBOSE(" Hit x " << hit.x() + << " y " << hit.y() + << " layer " << layer ); + } + + if(get_number_of_bins()>0) { + const int bin=get_bin(simulstate,truth,extrapol); + if(bin>=0 && bin<(int)get_number_of_bins()) { + for(unsigned int ichain=m_bin_start[bin]+get_nr_of_init(bin);ichain<m_bin_start[bin+1];++ichain) { + ATH_MSG_DEBUG("for "<<get_variable_text(simulstate,truth,extrapol)<<" run "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()); + if(chain()[ichain]->InheritsFrom(TFCSLateralShapeParametrizationHitBase::Class())) { + TFCSLateralShapeParametrizationHitBase* sim=(TFCSLateralShapeParametrizationHitBase*)(chain()[ichain]); + if(sim->simulate_hit(hit,simulstate,truth,extrapol)!=FCSSuccess) { + ATH_MSG_ERROR("error for "<<get_variable_text(simulstate,truth,extrapol)<<" run init "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()); + return false; + } + } else { + ATH_MSG_ERROR("for "<<get_variable_text(simulstate,truth,extrapol)<<" run init "<<get_bin_text(bin)<<": "<<chain()[ichain]->GetName()<<" does not inherit from TFCSLateralShapeParametrizationHitBase"); + return false; + } + } + } else { + ATH_MSG_WARNING("nothing to do for "<<get_variable_text(simulstate,truth,extrapol)<<": "<<get_bin_text(bin)); + } + } else { + ATH_MSG_WARNING("no bins defined, is this intended?"); + } + } + } + vox++; + } + } + + ATH_MSG_VERBOSE("Number of voxels " << vox); + + //delete h; + ATH_MSG_VERBOSE("Done layer "<<layer); + } + for(int ilayer=0;ilayer<CaloCell_ID_FCS::MaxSample;++ilayer) { + simulstate.set_Efrac(ilayer,simulstate.E(ilayer)/simulstate.E()); + } + + ATH_MSG_VERBOSE("Done particle"); + + return true; +} + + + +FCSReturnCode TFCSEnergyAndHitGAN::simulate(TFCSSimulationState& simulstate,const TFCSTruthState* truth, const TFCSExtrapolationState* extrapol) const +{ + for(unsigned int ichain=0;ichain<m_bin_start[0];++ichain) { + ATH_MSG_DEBUG("now run for all bins: "<<chain()[ichain]->GetName()); + if (simulate_and_retry(chain()[ichain], simulstate, truth, extrapol) != FCSSuccess) { + return FCSFatal; + } + } + + //Compute all inputs to the network + NetworkInputs inputs; + double trueEnergy; + ATH_MSG_VERBOSE("Get Inputs"); + if (!fillFastCaloGanNetworkInputs(simulstate,truth,inputs,trueEnergy)) { + ATH_MSG_WARNING("Could not initialize network "); + // bail out but do not stop the job + return FCSSuccess; + } + + ATH_MSG_VERBOSE("Fill Energies"); + if (!fillEnergy(simulstate,truth,extrapol,inputs)) { + ATH_MSG_WARNING("Could not fill energies "); + // bail out but do not stop the job + return FCSSuccess; + } + + + for(unsigned int ichain=m_bin_start.back();ichain<size();++ichain) { + ATH_MSG_DEBUG("now run for all bins: "<<chain()[ichain]->GetName()); + if (simulate_and_retry(chain()[ichain], simulstate, truth, extrapol) != FCSSuccess) { + return FCSFatal; + } + } + + return FCSSuccess; +} + +void TFCSEnergyAndHitGAN::Print(Option_t *option) const +{ + TFCSParametrization::Print(option); + TString opt(option); + bool shortprint=opt.Index("short")>=0; + bool longprint=msgLvl(MSG::DEBUG) || (msgLvl(MSG::INFO) && !shortprint); + TString optprint=opt;optprint.ReplaceAll("short",""); + + if(longprint) { + ATH_MSG_INFO(optprint<<" "<<"Graph="<<m_graph<<"; json input"<<m_input<<"; free mem="<<GANfreemem()<<"; latent space="<<m_GANLatentSize<<"; Binning size="<<m_Binning.size()); + for(auto& l : m_Binning) if(l.second.GetNbinsX()>1) { + ATH_MSG_INFO(optprint<<" "<<"layer="<<l.first<<" nR="<<l.second.GetNbinsX()<<" nalpha="<<l.second.GetNbinsY()); + } + } + + TString prefix="- "; + for(unsigned int ichain=0;ichain<size();++ichain) { + if(ichain==0 && ichain!=m_bin_start.front()) { + prefix="> "; + if(longprint) ATH_MSG_INFO(optprint<<prefix<<"Run for all bins"); + } + for(unsigned int ibin=0;ibin<get_number_of_bins();++ibin) { + if(ichain==m_bin_start[ibin]) { + if(ibin<get_number_of_bins()-1) if(ichain==m_bin_start[ibin+1]) continue; + prefix=Form("%-2d",ibin); + if(longprint) ATH_MSG_INFO(optprint<<prefix<<"Run for "<<get_bin_text(ibin)); + } + } + if(ichain==m_bin_start.back()) { + prefix="< "; + if(longprint) ATH_MSG_INFO(optprint<<prefix<<"Run for all bins"); + } + chain()[ichain]->Print(opt+prefix); + } +} + +void TFCSEnergyAndHitGAN::Streamer(TBuffer &R__b) +{ + // Stream an object of class TFCSEnergyAndHitGAN + + if (R__b.IsReading()) { + R__b.ReadClassBuffer(TFCSEnergyAndHitGAN::Class(),this); + if(m_graph!=nullptr) { + delete m_graph; + m_graph=nullptr; + } + if(m_input) { + std::stringstream sin; + sin.str(*m_input); + auto config=lwt::parse_json_graph(sin); + m_graph=new lwt::LightweightGraph(config); + } +#ifndef __FastCaloSimStandAlone__ + //When running inside Athena, delete config to free the memory + if(GANfreemem()) { + delete m_input; + m_input=nullptr; + } +#endif + } else { + R__b.WriteClassBuffer(TFCSEnergyAndHitGAN::Class(),this); + } +} + +void TFCSEnergyAndHitGAN::unit_test(TFCSSimulationState* simulstate,const TFCSTruthState* truth, const TFCSExtrapolationState* extrapol) +{ + if(!simulstate) { + simulstate=new TFCSSimulationState(); +#if defined(__FastCaloSimStandAlone__) + simulstate->setRandomEngine(new CLHEP::TRandomEngine()); +#else + simulstate->setRandomEngine(new CLHEP::RanluxEngine()); +#endif + } + if(!truth) { + TFCSTruthState* t=new TFCSTruthState(); + t->SetPtEtaPhiM(20000,0.225,0,130); + t->set_pdgid(211); + truth=t; + } + if(!extrapol) { + TFCSExtrapolationState* e=new TFCSExtrapolationState(); + e->set_CaloSurface_eta(truth->Eta()); + e->set_IDCaloBoundary_eta(truth->Eta()); + for(int i=0;i<24;++i) { + e->set_eta(i, TFCSExtrapolationState::SUBPOS_ENT, truth->Eta()); + e->set_eta(i, TFCSExtrapolationState::SUBPOS_EXT, truth->Eta()); + e->set_eta(i, TFCSExtrapolationState::SUBPOS_MID, truth->Eta()); + e->set_phi(i, TFCSExtrapolationState::SUBPOS_ENT, 0); + e->set_phi(i, TFCSExtrapolationState::SUBPOS_EXT, 0); + e->set_phi(i, TFCSExtrapolationState::SUBPOS_MID, 0); + e->set_r(i, TFCSExtrapolationState::SUBPOS_ENT, 1500+i*10); + e->set_r(i, TFCSExtrapolationState::SUBPOS_EXT, 1510+i*10); + e->set_r(i, TFCSExtrapolationState::SUBPOS_MID, 1505+i*10); + e->set_z(i, TFCSExtrapolationState::SUBPOS_ENT, 3500+i*10); + e->set_z(i, TFCSExtrapolationState::SUBPOS_EXT, 3510+i*10); + e->set_z(i, TFCSExtrapolationState::SUBPOS_MID, 3505+i*10); + } + extrapol=e; + } + + TFCSEnergyAndHitGAN GAN("GAN","GAN"); + GAN.setLevel(MSG::VERBOSE); + int pid=211; + int etaMin=20; + int etaMax = etaMin + 5; + GAN.initializeNetwork(pid,etaMin,"/eos/atlas/atlascerngroupdisk/proj-simul/VoxalisationOutputs/nominal/GAN_michele_normE_MaxE/input_for_service_new"); + for(int i=0;i<24;++i) { + TFCSCenterPositionCalculation* c=new TFCSCenterPositionCalculation(Form("center%d",i),Form("center layer %d",i)); + c->set_calosample(i); + c->setExtrapWeight(0.5); + c->setLevel(MSG::VERBOSE); + c->set_pdgid(pid); + if(pid==11) c->add_pdgid(-pid); + if(pid==211) c->add_pdgid(-pid); + c->set_eta_min(etaMin/100.0); + c->set_eta_max(etaMax/100.0); + c->set_eta_nominal((etaMin+etaMax)/200.0); + + GAN.push_back_in_bin(c,i); + GAN.set_nr_of_init(i,1); + } + + GAN.Print(); + + TFile* fGAN=TFile::Open("FCSGANtest.root","recreate"); + GAN.Write(); + fGAN->ls(); + fGAN->Close(); + + fGAN=TFile::Open("FCSGANtest.root"); + TFCSEnergyAndHitGAN* GAN2=(TFCSEnergyAndHitGAN*)(fGAN->Get("GAN")); + if(GAN2) { + GAN2->Print(); + } + + GAN2->setLevel(MSG::DEBUG); + GAN2->simulate(*simulstate,truth,extrapol); + simulstate->Print(); +} +