diff --git a/Detector/DetCRD/CMakeLists.txt b/Detector/DetCRD/CMakeLists.txt index 0ee51f932889b69a51028e6531fa10b3ad9d7507..6f3d945ae2a3b65705f429c8d3c2be1942d57c7f 100644 --- a/Detector/DetCRD/CMakeLists.txt +++ b/Detector/DetCRD/CMakeLists.txt @@ -57,6 +57,12 @@ foreach(detoption TDR_o1_v01 TDR_o1_v02) ) endforeach() +add_test( + NAME Test_TDR_o1_v01_CaloDigi + COMMAND gaudirun.py Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) + foreach(detoption TDR_o1_v01) add_test( NAME Test_${detoption}_Geo diff --git a/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py b/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py new file mode 100644 index 0000000000000000000000000000000000000000..707db43246582421be23e543e1e0d70f77e8c6de --- /dev/null +++ b/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +import os +from Gaudi.Configuration import * + +from Configurables import k4DataSvc +dsvc = k4DataSvc("EventDataSvc", input="rec00.root") + +from Configurables import RndmGenSvc, HepRndm__Engine_CLHEP__RanluxEngine_ +seed = [12340] +# rndmengine = HepRndm__Engine_CLHEP__RanluxEngine_() # The default engine in Gaudi +rndmengine = HepRndm__Engine_CLHEP__HepJamesRandom_("RndmGenSvc.Engine") # The default engine in Geant4 +rndmengine.SetSingleton = True +rndmengine.Seeds = seed + +rndmgensvc = RndmGenSvc("RndmGenSvc") +rndmgensvc.Engine = rndmengine.name() + +geometry_option = "TDR_o1_v01/TDR_o1_v01.xml" + +if not os.getenv("DETCRDROOT"): + print("Can't find the geometry. Please setup envvar DETCRDROOT." ) + sys.exit(-1) + +geometry_path = os.path.join(os.getenv("DETCRDROOT"), "compact", geometry_option) +if not os.path.exists(geometry_path): + print("Can't find the compact geometry file: %s"%geometry_path) + sys.exit(-1) + +from Configurables import GeomSvc +geosvc = GeomSvc("GeomSvc") +geosvc.compact = geometry_path + +from Configurables import MarlinEvtSeeder +evtseeder = MarlinEvtSeeder("EventSeeder") + +from Configurables import GearSvc +gearsvc = GearSvc("GearSvc") + +from Configurables import TrackSystemSvc +tracksystemsvc = TrackSystemSvc("TrackSystemSvc") + +from Configurables import SimplePIDSvc +pidsvc = SimplePIDSvc("SimplePIDSvc") +cepcswdatatop = "/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest" +pidsvc.ParFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Service/SimplePIDSvc/data/dNdx_TPC.root") + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=[ +# "EventHeader", + "MCParticle", + "EcalBarrelCollection", + "EcalBarrelContributionCollection", + "HcalBarrelCollection", + "HcalBarrelContributionCollection", + "CompleteTracks", + "CompleteTracksParticleAssociation" + ]) + +########## Digitalization ################ + +##ECAL## +from Configurables import EcalDigiAlg +EcalDigi = EcalDigiAlg("EcalDigiAlg") +EcalDigi.ReadOutName = "EcalBarrelCollection" +EcalDigi.SimCaloHitCollection = "EcalBarrelCollection" +EcalDigi.CaloHitCollection = "ECALBarrel" +EcalDigi.CaloAssociationCollection = "ECALBarrelAssoCol" +EcalDigi.CaloMCPAssociationCollection = "ECALBarrelParticleAssoCol" +EcalDigi.SkipEvt = 0 +EcalDigi.Seed = 2079 +#Digitalization parameters +EcalDigi.CalibrECAL = 1. +EcalDigi.AttenuationLength = 7e10 +EcalDigi.TimeResolution = 0.5 #unit: ns +EcalDigi.ChargeThresholdFrac = 0.05 +EcalDigi.Debug=1 +EcalDigi.WriteNtuple = 0 +EcalDigi.OutFileName = "Digi_ECAL.root" +######################################### + +##HCAL## +from Configurables import HcalDigiAlg +HcalDigi = HcalDigiAlg("HcalDigiAlg") +HcalDigi.ReadOutName = "HcalBarrelCollection" +HcalDigi.SimCaloHitCollection = "HcalBarrelCollection" +HcalDigi.CaloHitCollection = "HCALBarrel" +HcalDigi.CaloAssociationCollection = "HCALBarrelAssoCol" +HcalDigi.CaloMCPAssociationCollection = "HCALBarrelParticleAssoCol" +HcalDigi.SkipEvt = 0 +HcalDigi.Seed = 2079 +#Digitalization parameters +HcalDigi.MIPResponse = 0.01 # 0.5 MeV / MIP +HcalDigi.MIPThreshold = 0.5 # Unit: MIP +HcalDigi.CalibrHCAL = 1. +HcalDigi.Debug=0 +HcalDigi.WriteNtuple = 0 +HcalDigi.OutFileName = "Digi_HCAL.root" + + +# output +from Configurables import PodioOutput +out = PodioOutput("outputalg") +out.filename = "CaloDigi_TDR_o1_v01_00.root" +out.outputCommands = ["keep *"] + +# ApplicationMgr +from Configurables import ApplicationMgr +mgr = ApplicationMgr( + TopAlg = [podioinput, EcalDigi, HcalDigi, out], + EvtSel = 'NONE', + EvtMax = 5, + ExtSvc = [dsvc, rndmengine, rndmgensvc, geosvc], + HistogramPersistency = 'ROOT', + OutputLevel = ERROR +) diff --git a/Detector/DetCRD/src/Muon/Muon_Barrel_v01_01.cpp b/Detector/DetCRD/src/Muon/Muon_Barrel_v01_01.cpp index 9e6abc73eb7242667b5481f0af2829370c7166e6..6515e9769b8a5c39d98955a3012950b11528cecc 100644 --- a/Detector/DetCRD/src/Muon/Muon_Barrel_v01_01.cpp +++ b/Detector/DetCRD/src/Muon/Muon_Barrel_v01_01.cpp @@ -320,6 +320,7 @@ static dd4hep::Ref_t create_detector(dd4hep::Detector& theDetector, } dd4hep::Transform3D pv(dd4hep::Rotation3D(dd4hep::RotationX(90*dd4hep::degree)),dd4hep::Position(0,0,0)); dd4hep::PlacedVolume phv = motherVol.placeVolume(envelope,pv); + phv.addPhysVolID("system",x_det.id()); sdet.setPlacement(phv); MYDEBUG("create_detector DONE. "); diff --git a/Detector/DetCRD/src/Muon/Muon_Endcap_v01_01.cpp b/Detector/DetCRD/src/Muon/Muon_Endcap_v01_01.cpp index acb54e5b03a44ad347acd085f0e66338d0e9ecc0..7631b5377206d63f0570a6ddb41702b224791eb7 100644 --- a/Detector/DetCRD/src/Muon/Muon_Endcap_v01_01.cpp +++ b/Detector/DetCRD/src/Muon/Muon_Endcap_v01_01.cpp @@ -294,7 +294,7 @@ static dd4hep::Ref_t create_detector(dd4hep::Detector& theDetector, sdetB.setPlacement(pv); pv = motherVol.placeVolume(assembly); -// pv.addPhysVolID("system",x_det.id()); + pv.addPhysVolID("system",x_det.id()); both_endcaps.setPlacement(pv); both_endcaps.add(sdetA); both_endcaps.add(sdetB); diff --git a/Digitisers/CMakeLists.txt b/Digitisers/CMakeLists.txt index 6f6f2e40403e248ab60d5ab5ddbe435334b0c29d..27da8e2e5b28a073b6a6b8b9ce9d8ddf475e6058 100644 --- a/Digitisers/CMakeLists.txt +++ b/Digitisers/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(DCHDigi) add_subdirectory(G2CDArbor) add_subdirectory(SimHitMerge) add_subdirectory(SimpleDigi) +add_subdirectory(CaloDigi) diff --git a/Digitisers/CaloDigi/CMakeLists.txt b/Digitisers/CaloDigi/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3b4182c62930e7fe0bbce7d972dc0c2d849f8ce --- /dev/null +++ b/Digitisers/CaloDigi/CMakeLists.txt @@ -0,0 +1,22 @@ +# Modules +gaudi_add_module(CaloDigi + SOURCES src/EcalDigiAlg.cpp + SOURCES src/HcalDigiAlg.cpp + LINK k4FWCore::k4FWCore + GearSvc + DetInterface + Gaudi::GaudiKernel + Gaudi::GaudiAlgLib + ${CLHEP_LIBRARIES} + ${GEAR_LIBRARIES} + ${GSL_LIBRARIES} + ${LCIO_LIBRARIES} + ${ROOT_LIBRARIES} + EDM4HEP::edm4hep EDM4HEP::edm4hepDict +) +install(TARGETS CaloDigi + EXPORT CEPCSWTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + COMPONENT dev) + diff --git a/Digitisers/CaloDigi/src/CaloBar.h b/Digitisers/CaloDigi/src/CaloBar.h new file mode 100644 index 0000000000000000000000000000000000000000..57d226bb5b30779038b43bea392f2f4090c8e77a --- /dev/null +++ b/Digitisers/CaloDigi/src/CaloBar.h @@ -0,0 +1,54 @@ +#ifndef _CALOBAR +#define _CALOBAR + +#include <DD4hep/Objects.h> +#include "TVector3.h" + +class CaloBar{ + +public: + CaloBar(unsigned long long _cellID, int _system, int _module, int _slayer, int _dlayer, int _stave, int _bar, TVector3 _pos, double _Q1, double _Q2, double _T1, double _T2) + : cellID(_cellID), system(_system), module(_module), stave(_stave), dlayer(_dlayer), slayer(_slayer), bar(_bar), position(_pos), Q1(_Q1), Q2(_Q2), T1(_T1), T2(_T2) {}; + CaloBar() {}; + + inline bool operator == (const CaloBar &x) const{ + return ( (cellID == x.cellID) && getEnergy()==x.getEnergy() ); + } + unsigned long long getcellID() const { return cellID; } + int getSystem() const { return system; } + int getModule() const { return module; } + int getStave() const { return stave; } + int getDlayer() const { return dlayer; } + int getSlayer() const { return slayer; } + int getBar() const { return bar; } + double getQ1() const { return Q1; } + double getQ2() const { return Q2; } + double getT1() const { return T1; } + double getT2() const { return T2; } + + TVector3 getPosition() const { return position; } + double getEnergy() const { return (Q1+Q2)/2.; } + + void setcellID(unsigned long long _cellid) { cellID = _cellid; } + void setcellID(int _system, int _module, int _stave, int _dlayer, int _slayer, int _bar) { system=_system; module=_module; stave=_stave; dlayer=_dlayer; slayer=_slayer; bar=_bar; } + void setPosition( TVector3 posv3) { position.SetXYZ( posv3.x(), posv3.y(), posv3.z() ); } + void setQ(double _q1, double _q2) { Q1=_q1; Q2=_q2; } + void setT(double _t1, double _t2) { T1=_t1; T2=_t2; } + +private: + unsigned long long cellID; + int system; + int module; + int stave; + int dlayer; + int slayer; + int bar; + TVector3 position; + double Q1; // Q in left readout + double Q2; // Q in right readout; + double T1; // T in left readout; + double T2; // T in right readout; + +}; + +#endif diff --git a/Digitisers/CaloDigi/src/CaloHit.h b/Digitisers/CaloDigi/src/CaloHit.h new file mode 100644 index 0000000000000000000000000000000000000000..2c6017def92096928eae6a24fafec2da0fb15fe5 --- /dev/null +++ b/Digitisers/CaloDigi/src/CaloHit.h @@ -0,0 +1,50 @@ +#ifndef _CALOHIT +#define _CALOHIT + +#include <DD4hep/Objects.h> +#include "TVector3.h" + +class CaloHit{ + +public: + CaloHit(unsigned long long _cellID, int _system, int _module, int _layer, int _stave, int _tower, int _slice, TVector3 _pos, double _E, int _step_numbers) + : cellID(_cellID), system(_system), module(_module), layer(_layer), stave(_stave), tower(_tower), slice(_slice), position(_pos), E(_E), step_numbers(_step_numbers) {}; + CaloHit() {}; + + inline bool operator == (const CaloHit &x) const{ + return ( (cellID == x.cellID) && getEnergy()==x.getEnergy() ); + } + unsigned long long getcellID() const { return cellID; } + int getSystem() const { return system; } + int getModule() const { return module; } + int getStave() const { return stave; } + int getLayer() const { return layer; } + int getTower() const { return tower; } + int getSlice() const { return slice; } + + TVector3 getPosition() const { return position; } + double getEnergy() const { return E; } + int getStep_numbers() const { return step_numbers; } + + void setcellID(unsigned long long _cellid) { cellID = _cellid; } + void setcellID(int _system, int _module, int _layer, int _stave, int _tower, int _slice) { system=_system; module=_module; stave=_stave; layer=_layer; tower=_tower; slice=_slice;} + void setPosition( TVector3 posv3) { position.SetXYZ( posv3.x(), posv3.y(), posv3.z() ); } + void setE(double _E) { E=_E; } + void setStep_numbers(int _step_numbers) { step_numbers=_step_numbers; } + + +private: + unsigned long long cellID; + int system; + int module; + int stave; + int layer; + int tower; + int slice; + TVector3 position; + double E; + int step_numbers; + +}; + +#endif diff --git a/Digitisers/CaloDigi/src/EcalDigiAlg.cpp b/Digitisers/CaloDigi/src/EcalDigiAlg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bba340457624114510e66015c3b318ee0ba90df7 --- /dev/null +++ b/Digitisers/CaloDigi/src/EcalDigiAlg.cpp @@ -0,0 +1,625 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// Unit in code: mm, ns. +// NOTE: This digitialization highly matches detector geometry CRDEcalBarrel_v01/LongCrystalBarBarrelCalorimeter32Polygon_v01. +// TODO: read geometry info automatically. +#include "EcalDigiAlg.h" + +#include "edm4hep/SimCalorimeterHit.h" +#include "edm4hep/CalorimeterHit.h" +#include "edm4hep/Vector3f.h" +#include "edm4hep/Cluster.h" + +#include "DD4hep/Detector.h" +#include <DD4hep/Objects.h> +#include <DDRec/CellIDPositionConverter.h> + +#include "TVector3.h" +#include "TRandom3.h" +#include <math.h> +#include <cmath> +#include <iostream> +#include <algorithm> +#include <map> +#include <random> + +// #include <fstream> +// #include <ctime> + +#define C 299.79 // unit: mm/ns +#define PI 3.141592653 +using namespace std; +using namespace dd4hep; +using dd4hep::rec::LayeredCalorimeterData; +using dd4hep::rec::LayeredCalorimeterStruct; + +DECLARE_COMPONENT( EcalDigiAlg ) + +EcalDigiAlg::EcalDigiAlg(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc), + _nEvt(0) +{ + + // Input collections + declareProperty("SimCaloHitCollection", r_SimCaloCol, "Handle of the Input SimCaloHit collection"); + + // Output collections + declareProperty("CaloHitCollection", w_DigiCaloCol, "Handle of Digi CaloHit collection"); + declareProperty("CaloAssociationCollection", w_CaloAssociationCol, "Handle of CaloAssociation collection"); + declareProperty("CaloMCPAssociationCollection", w_MCPCaloAssociationCol, "Handle of CaloAssociation collection"); + +} + +StatusCode EcalDigiAlg::initialize() +{ + if(_writeNtuple){ + std::string s_outfile = _filename; + m_wfile = new TFile(s_outfile.c_str(), "recreate"); + t_SimCont = new TTree("SimStep", "SimStep"); + t_SimBar = new TTree("SimBarHit", "SimBarHit"); + t_SimCont->Branch("step_x", &m_step_x); + t_SimCont->Branch("step_y", &m_step_y); + t_SimCont->Branch("step_z", &m_step_z); + t_SimCont->Branch("step_t", &m_step_t); // yyy: time of each step + t_SimCont->Branch("stepBar_x", &m_stepBar_x); + t_SimCont->Branch("stepBar_y", &m_stepBar_y); + t_SimCont->Branch("stepBar_z", &m_stepBar_z); + t_SimCont->Branch("step_E", &m_step_E); + t_SimCont->Branch("step_T1", &m_step_T1); + t_SimCont->Branch("step_T2", &m_step_T2); + t_SimBar->Branch("totE_Truth", &totE_Truth); + t_SimBar->Branch("totE_Digi", &totE_Digi); + t_SimBar->Branch("simBar_x", &m_simBar_x); + t_SimBar->Branch("simBar_y", &m_simBar_y); + t_SimBar->Branch("simBar_z", &m_simBar_z); + t_SimBar->Branch("simBar_T1", &m_simBar_T1); + t_SimBar->Branch("simBar_T2", &m_simBar_T2); + t_SimBar->Branch("simBar_Q1_Truth", &m_simBar_Q1_Truth); + t_SimBar->Branch("simBar_Q2_Truth", &m_simBar_Q2_Truth); + t_SimBar->Branch("simBar_Q1_Digi", &m_simBar_Q1_Digi); + t_SimBar->Branch("simBar_Q2_Digi", &m_simBar_Q2_Digi); + t_SimBar->Branch("simBar_module", &m_simBar_module); + t_SimBar->Branch("simBar_stave", &m_simBar_stave); + t_SimBar->Branch("simBar_dlayer", &m_simBar_dlayer); + t_SimBar->Branch("simBar_slayer", &m_simBar_slayer); + t_SimBar->Branch("simBar_cellID", &m_simBar_cellID); + } + + std::cout<<"EcalDigiAlg::m_scale="<<m_scale<<std::endl; + m_geosvc = service<IGeomSvc>("GeomSvc"); + if ( !m_geosvc ) throw "EcalDigiAlg :Failed to find GeomSvc ..."; + m_dd4hep = m_geosvc->lcdd(); + if ( !m_dd4hep ) throw "EcalDigiAlg :Failed to get dd4hep::Detector ..."; + m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep); + m_decoder = m_geosvc->getDecoder(_readoutName); + if (!m_decoder) { + error() << "Failed to get the decoder. " << endmsg; + return StatusCode::FAILURE; + } + + rndm.SetSeed(_seed); + std::cout<<"EcalDigiAlg::initialize"<<std::endl; + return GaudiAlgorithm::initialize(); +} + +StatusCode EcalDigiAlg::execute() +{ + // clock_t yyy_start, yyy_enddigi; + // yyy_start = clock(); // 璁板綍寮€濮嬫椂闂� + + if(_nEvt==0) std::cout<<"EcalDigiAlg::execute Start"<<std::endl; + std::cout<<"Processing event: "<<_nEvt<<std::endl; + if(_nEvt<_Nskip){ _nEvt++; return StatusCode::SUCCESS; } + + Clear(); + + const edm4hep::SimCalorimeterHitCollection* SimHitCol = r_SimCaloCol.get(); + edm4hep::CalorimeterHitCollection* caloVec = w_DigiCaloCol.createAndPut(); + edm4hep::MCRecoCaloAssociationCollection* caloAssoVec = w_CaloAssociationCol.createAndPut(); + edm4hep::MCRecoCaloParticleAssociationCollection* caloMCPAssoVec = w_MCPCaloAssociationCol.createAndPut(); + std::vector<edm4hep::SimCalorimeterHit> m_simhitCol; m_simhitCol.clear(); + std::vector<CaloBar> m_barCol; m_barCol.clear(); + + if(SimHitCol == 0){ + std::cout<<"not found SimCalorimeterHitCollection"<< std::endl; + return StatusCode::SUCCESS; + } + + if(_Debug>=1) std::cout<<"digi, input sim hit size="<< SimHitCol->size() <<std::endl; + + totE_Truth=0; + totE_Digi=0; + + //Merge input simhit(steps) to real simhit(bar). + MergeHits(*SimHitCol, m_simhitCol); + if(_Debug>=1) std::cout<<"Finish Hit Merge, with Nhit: "<<m_simhitCol.size()<<std::endl; + + // DetElement beamcal = m_dd4hep->detector("CaloDetector"); + // LayeredCalorimeterData* bcExtension = beamcal.extension<LayeredCalorimeterData>(); + // std::vector<LayeredCalorimeterStruct::Layer> layers = bcExtension->layers; + + //Loop in SimHit, digitalize SimHit to DigiBar + for(int i=0;i<m_simhitCol.size();i++){ + + auto SimHit = m_simhitCol.at(i); + + unsigned long long id = SimHit.getCellID(); + CaloBar hitbar; + hitbar.setcellID( id); + hitbar.setcellID( m_decoder->get(id, "system"), + m_decoder->get(id, "module"), + m_decoder->get(id, "stave"), + m_decoder->get(id, "dlayer"), + m_decoder->get(id, "slayer"), + m_decoder->get(id, "bar")); + + double Lbar = GetBarLength(hitbar); //NOTE: Is fixed with geometry LongCrystalBarBarrelCalorimeter32Polygon_v01. + + dd4hep::Position hitpos = m_cellIDConverter->position(id); + TVector3 barpos(10*hitpos.x(), 10*hitpos.y(), 10*hitpos.z()); //cm to mm. + hitbar.setPosition(barpos); + + //printf("in bar #%d: cellID [%d, %d, %d, %d], position (%.3f, %.3f, %.3f), energy %.3f \n", hitbar.getModule(), hitbar.getStave(), hitbar.getDlayer(), hitbar.getSlayer(), hitbar.getBar(), + // 10*hitpos.x(), 10*hitpos.y(), 10*hitpos.z(), SimHit.getEnergy() ); + + MCParticleToEnergyWeightMap MCPEnMap; MCPEnMap.clear(); + std::vector<HitStep> DigiLvec; DigiLvec.clear(); + std::vector<HitStep> DigiRvec; DigiRvec.clear(); + double totQ1_Truth = 0; + double totQ2_Truth = 0; + double totQ1_Digi = 0; + double totQ2_Digi = 0; + double totQ1 = 0; + double totQ2 = 0; + + //Loop in all SimHitContribution(G4Step). + //if(_Debug>=2) std::cout<<"SimHit contribution size: "<<SimHit.contributions_size()<<std::endl; + for(int iCont=0; iCont < SimHit.contributions_size(); ++iCont){ + auto conb = SimHit.getContributions(iCont); + if( !conb.isAvailable() ) { std::cout<<"EcalDigiAlg Can not get SimHitContribution: "<<iCont<<std::endl; continue;} + + double en = conb.getEnergy(); + if(en == 0) continue; + + auto mcp = conb.getParticle(); + MCPEnMap[mcp] += en; + TVector3 steppos(conb.getStepPosition().x, conb.getStepPosition().y, conb.getStepPosition().z); + TVector3 rpos = steppos-hitbar.getPosition(); + float step_time = conb.getTime(); // yyy: step time + + m_step_x.push_back(steppos.x()); + m_step_y.push_back(steppos.y()); + m_step_z.push_back(steppos.z()); + m_step_t.push_back(step_time); // yyy: push back step time + m_step_E.push_back(en); + m_stepBar_x.push_back(hitbar.getPosition().x()); + m_stepBar_y.push_back(hitbar.getPosition().y()); + m_stepBar_z.push_back(hitbar.getPosition().z()); + + if(_Debug>=3){ + cout<<"Cell Pos: "<<hitbar.getPosition().x()<<'\t'<<hitbar.getPosition().y()<<'\t'<<hitbar.getPosition().z()<<endl; + cout<<"step pos: "<<steppos.x()<<'\t'<<steppos.y()<<'\t'<<steppos.z()<<endl; + cout<<"Relative pos: "<<rpos.x()<<'\t'<<rpos.y()<<'\t'<<rpos.z()<<endl; + cout<<"Cell: "<<hitbar.getModule()<<" "<<hitbar.getDlayer()<<" "<<hitbar.getSlayer()<<endl; + } + + //Get digitalized signal(Q1, Q2, T1, T2) from step + //Define: 1 is left, 2 is right, clockwise direction in phi. + + int sign=-999; + if(hitbar.getSlayer()==1) sign = rpos.z()==0 ? 1 : rpos.z()/fabs(rpos.z()); + else{ + int _module = hitbar.getModule(); + if(_module<=7 || _module>=25) sign = rpos.x()==0 ? 1: rpos.x()/fabs(rpos.x()); + if(_module>=9 && _module<=23) sign = rpos.x()==0 ? -1:-rpos.x()/fabs(rpos.x()); + else if(_module==8) sign = rpos.y()==0 ? 1: rpos.y()/fabs(rpos.y()); + else if(_module==24) sign = rpos.y()==0 ? -1:-rpos.y()/fabs(rpos.y()); + + } + if(!fabs(sign)) {std::cout<<"ERROR: Wrong bar direction/position!"<<std::endl; continue;} + + // ####### For Charge Digitization ####### + double Ratio_left = exp(-(Lbar/2 + sign*sqrt(rpos.Mag2()))/Latt) / (exp(-(Lbar/2 + sign*sqrt(rpos.Mag2()))/Latt) + exp(-(Lbar/2 - sign*sqrt(rpos.Mag2()))/Latt)); + double Ratio_right = 1 - Ratio_left; + totQ1_Truth += en*Ratio_left; + totQ2_Truth += en*Ratio_right; + + // ####### For Time Digitization ####### + double Qi_left = en*exp(-(Lbar/2 + sign*sqrt(rpos.Mag2()))/Latt); + double Qi_right = en*exp(-(Lbar/2 - sign*sqrt(rpos.Mag2()))/Latt); + + if(_Debug>=3){ + cout<<Qi_left<<'\t'<<Qi_right<<endl; + cout<<Lbar<<'\t'<<sign*sqrt(rpos.Mag2())<<endl; + } + + double Ti_left = -1; int looptime=0; + while(Ti_left<0){ + // Ti_left = Tinit + rndm.Gaus(nMat*(Lbar/2 + sign*sqrt(rpos.Mag2()))/C, Tres); + Ti_left = Tinit + rndm.Gaus(nMat*(Lbar/2 + sign*sqrt(rpos.Mag2()))/C, Tres) + step_time; // yyy: add step time + looptime++; + if(looptime>500){ std::cout<<"ERROR: Step "<<iCont<<" can not get a positive left-side time!"<<std::endl; break;} + } + if(looptime>500) continue; + double Ti_right = -1; looptime=0; + while(Ti_right<0){ + // Ti_right = Tinit + rndm.Gaus(nMat*(Lbar/2 - sign*sqrt(rpos.Mag2()))/C, Tres); + Ti_right = Tinit + rndm.Gaus(nMat*(Lbar/2 - sign*sqrt(rpos.Mag2()))/C, Tres) + step_time; // yyy: add step time + looptime++; + if(looptime>500){ + std::cout<<"ERROR: Step "<<iCont<<" can not get a positive right-side time!"<<std::endl; + std::cout<<" Initial time "<<Tinit<<", transport time central value "<<nMat*(Lbar/2 - sign*sqrt(rpos.Mag2()))/C<<std::endl; + break; + } + } + if(looptime>500) continue; + + m_step_T1.push_back(Ti_left); + m_step_T2.push_back(Ti_right); + totQ1 += Qi_left; + totQ2 += Qi_right; + + HitStep stepoutL, stepoutR; + stepoutL.setQ(Qi_left); stepoutL.setT(Ti_left); + stepoutR.setQ(Qi_right); stepoutR.setT(Ti_right); + DigiLvec.push_back(stepoutL); + DigiRvec.push_back(stepoutR); + } + + // ####################################### + // ####### Ideal Time Digitization ####### + // ####################################### + + //if(_Debug>=2) std::cout<<"Time Digitalize: time at Q >"<<_Qthfrac<<"*totQ"<<std::endl; + std::sort(DigiLvec.begin(), DigiLvec.end()); + std::sort(DigiRvec.begin(), DigiRvec.end()); + double thQ1=0; + double thQ2=0; + double thT1, thT2; + for(int iCont=0;iCont<DigiLvec.size();iCont++){ + thQ1 += DigiLvec[iCont].getQ(); + if(thQ1>totQ1*_Qthfrac){ + thT1 = DigiLvec[iCont].getT(); + if(_Debug>=3) std::cout<<"Get T1 at index: "<<iCont<<std::endl; + break; + } + } + for(int iCont=0;iCont<DigiRvec.size();iCont++){ + thQ2 += DigiRvec[iCont].getQ(); + if(thQ2>totQ2*_Qthfrac){ + thT2 = DigiRvec[iCont].getT(); + if(_Debug>=3) std::cout<<"Get T2 at index: "<<iCont<<std::endl; + break; + } + } + + if(_UseRelDigi){ + // ############################################# + // ####### Realistic Charge Digitization ####### + // ############################################# + + // double sEcalCryMipLY = gRandom->Gaus(fEcalCryMipLY, 0.1 * fEcalCryMipLY); + double sEcalCryMipLY = fEcalCryMipLY; + + //TODO: fEcalMIPEnergy should depends on crystal size. + int ScinGen = std::round(gRandom->Poisson((totQ1_Truth+totQ2_Truth)*1000 / fEcalMIPEnergy * sEcalCryMipLY)); + + totQ1_Digi = EnergyDigi(ScinGen*totQ1_Truth/(totQ1_Truth+totQ2_Truth), sEcalCryMipLY)/1000; + totQ2_Digi = EnergyDigi(ScinGen*totQ2_Truth/(totQ1_Truth+totQ2_Truth), sEcalCryMipLY)/1000; + } + else{ + double totQ1_Digi_tmp = totQ1_Truth; + double totQ2_Digi_tmp = totQ2_Truth; + if( (totQ1_Digi_tmp+totQ2_Digi_tmp)!=0 ){ + totQ1_Digi = totQ1_Digi_tmp/(totQ1_Digi_tmp+totQ2_Digi_tmp); + totQ2_Digi = totQ2_Digi_tmp/(totQ1_Digi_tmp+totQ2_Digi_tmp); + } + if( totQ1_Digi/fEcalMIPEnergy < fEcalMIP_Thre ) totQ1_Digi = 0; + if( totQ2_Digi/fEcalMIPEnergy < fEcalMIP_Thre ) totQ2_Digi = 0; + } + if(totQ1_Digi==0 && totQ2_Digi==0) continue; + + hitbar.setQ(totQ1_Digi, totQ2_Digi); + hitbar.setT(thT1, thT2); + + // ################################## + // ####### Some associations ####### + // ################################## + + //2 hits with double-readout time. + edm4hep::Vector3f m_pos(hitbar.getPosition().X(), hitbar.getPosition().Y(), hitbar.getPosition().Z()); + auto digiHit1 = caloVec->create(); + digiHit1.setCellID(hitbar.getcellID()); + digiHit1.setEnergy(hitbar.getQ1()); + digiHit1.setTime(hitbar.getT1()); + digiHit1.setPosition(m_pos); + auto digiHit2 = caloVec->create(); + digiHit2.setCellID(hitbar.getcellID()); + digiHit2.setEnergy(hitbar.getQ2()); + digiHit2.setTime(hitbar.getT2()); + digiHit2.setPosition(m_pos); + + //SimHit - CaloHit association + auto rel1 = caloAssoVec->create(); + rel1.setRec(digiHit1); + rel1.setSim(SimHit); + rel1.setWeight( hitbar.getQ1()/(hitbar.getQ1()+hitbar.getQ2()) ); + auto rel2 = caloAssoVec->create(); + rel2.setRec(digiHit2); + rel2.setSim(SimHit); + rel2.setWeight( hitbar.getQ2()/(hitbar.getQ1()+hitbar.getQ2()) ); + + //MCParticle - CaloHit association + //float maxMCE = -99.; + //edm4hep::MCParticle selMCP; + for(auto iter : MCPEnMap){ + //if(iter.second>maxMCE){ + // maxMCE = iter.second; + // selMCP = iter.first; + //} + auto rel_MCP1 = caloMCPAssoVec->create(); + rel_MCP1.setRec(digiHit1); + rel_MCP1.setSim(iter.first); + rel_MCP1.setWeight(iter.second/SimHit.getEnergy()); + auto rel_MCP2 = caloMCPAssoVec->create(); + rel_MCP2.setRec(digiHit2); + rel_MCP2.setSim(iter.first); + rel_MCP2.setWeight(iter.second/SimHit.getEnergy()); + } + + //if(selMCP.isAvailable()){ + // auto rel_MCP1 = caloMCPAssoVec->create(); + // rel_MCP1.setRec(digiHit1); + // rel_MCP1.setSim(selMCP); + // rel_MCP1.setWeight(1.); + // auto rel_MCP2 = caloMCPAssoVec->create(); + // rel_MCP2.setRec(digiHit2); + // rel_MCP2.setSim(selMCP); + // rel_MCP2.setWeight(1.); + //} + + // ######################################## + // ####### Temp: write into trees. ####### + // ######################################## + + m_barCol.push_back(hitbar); + if(hitbar.getQ1()>0 && hitbar.getQ2()>0) totE_Digi+=(hitbar.getQ1()+hitbar.getQ2()); + if(totQ1_Truth>(fEcalMIPEnergy*fEcalMIP_Thre/1000.) && totQ2_Truth>(fEcalMIPEnergy*fEcalMIP_Thre/1000.)){ + // cout<<"Truth Energy:"<<totQ1_Truth<<" "<<totQ2_Truth<<endl; + totE_Truth+=(totQ1_Truth+totQ2_Truth); + } + + if(_writeNtuple){ + m_simBar_x.push_back(hitbar.getPosition().x()); + m_simBar_y.push_back(hitbar.getPosition().y()); + m_simBar_z.push_back(hitbar.getPosition().z()); + m_simBar_Q1_Truth.push_back(totQ1_Truth); + m_simBar_Q2_Truth.push_back(totQ2_Truth); + m_simBar_Q1_Digi.push_back(hitbar.getQ1()); + m_simBar_Q2_Digi.push_back(hitbar.getQ2()); + m_simBar_T1.push_back(hitbar.getT1()); + m_simBar_T2.push_back(hitbar.getT2()); + m_simBar_module.push_back(hitbar.getModule()); + m_simBar_stave.push_back(hitbar.getStave()); + m_simBar_dlayer.push_back(hitbar.getDlayer()); + m_simBar_slayer.push_back(hitbar.getSlayer()); + m_simBar_cellID.push_back(hitbar.getcellID()); + } + } + + if(_writeNtuple){ + t_SimCont->Fill(); + t_SimBar->Fill(); + } + + if(_Debug>=1) std::cout<<"End Loop: Bar Digitalization!"<<std::endl; + std::cout<<"Total Truth Energy: "<<totE_Truth<<std::endl; + std::cout<<"Total Digi Energy: "<<totE_Digi<<std::endl; + + // yyy_enddigi = clock(); + // double duration_digi = double(yyy_enddigi - yyy_start) / CLOCKS_PER_SEC; + // // 灏嗘椂闂磋緭鍑哄埌txt鏂囦欢涓� + // std::ofstream outfile("runtime_ecaldigi.txt", std::ios::app); + // outfile << _nEvt << " " << duration_digi << std::endl; + // outfile.close(); + + _nEvt ++ ; + //delete SimHitCol, caloVec, caloAssoVec; + m_simhitCol.clear(); + return StatusCode::SUCCESS; +} + +StatusCode EcalDigiAlg::finalize() +{ + if(_writeNtuple){ + m_wfile->cd(); + t_SimCont->Write(); + t_SimBar->Write(); + m_wfile->Close(); + delete m_wfile, t_SimCont, t_SimBar; + } + info() << "Processed " << _nEvt << " events " << endmsg; + delete m_cellIDConverter, m_decoder, m_geosvc; + return GaudiAlgorithm::finalize(); +} + +double EcalDigiAlg::EnergyDigi(double ScinGen, double sEcalCryMipLY){ + Int_t sPix = int(ScinGen); + + // if(sPix/sEcalCryMipLY < fEcalMIP_Thre) return 0; + // return sPix/sEcalCryMipLY*fEcalMIPEnergy; + + // return sPix/sEcalCryMipLY*fEcalMIPEnergy; + + // ####### SiPM Saturation ####### + // sPix = std::round(fEcalSiPMPixels * (1 - TMath::Exp(-sPix / fEcalSiPMPixels))); + + // ################################ + // ####### ADC Digitization ####### + // ################################ + + Bool_t Use_G1 = kFALSE; + Bool_t Use_G2 = kFALSE; + Bool_t Use_G3 = kFALSE; + + Double_t sADCMean = sPix * fEcalChargeADCMean; + Double_t sADCSigma = std::sqrt(sPix * fEcalChargeADCSigma * fEcalChargeADCSigma + fEcalNoiseADCSigma * fEcalNoiseADCSigma); + Int_t sADC = -1; + sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma)); + + if(sADC <= fADCSwitch){ + Use_G1 = kTRUE; + sADC = std::round(gRandom->Gaus(sADC, fEcalADCError * sADC)); + Double_t sMIP = sADC / fEcalChargeADCMean / sEcalCryMipLY; + if(sMIP < fEcalMIP_Thre) return 0; + return sMIP * fEcalMIPEnergy; + } + else if(sADC > fADCSwitch && int(sADC/fGainRatio_12) <= fADCSwitch){ + Use_G2 = kTRUE; + sADCMean = sPix * fEcalChargeADCMean / fGainRatio_12; + sADCSigma = std::sqrt(sPix * fEcalChargeADCSigma / fGainRatio_12 * fEcalChargeADCSigma / fGainRatio_12 + fEcalNoiseADCSigma * fEcalNoiseADCSigma); + sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma)); + sADC = std::round(gRandom->Gaus(sADC, fEcalADCError * sADC)); + Double_t sMIP = sADC / fEcalChargeADCMean * fGainRatio_12 / sEcalCryMipLY; + if(sMIP < fEcalMIP_Thre) return 0; + return sMIP * fEcalMIPEnergy; + } + else if(int(sADC/fGainRatio_12) > fADCSwitch){ + Use_G3 = kTRUE; + sADCMean = sPix * fEcalChargeADCMean / fGainRatio_12 / fGainRatio_23; + sADCSigma = std::sqrt(sPix * fEcalChargeADCSigma / fGainRatio_12 / fGainRatio_23 * fEcalChargeADCSigma / fGainRatio_12 / fGainRatio_23 + fEcalNoiseADCSigma * fEcalNoiseADCSigma); + sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma)); + sADC = std::round(gRandom->Gaus(sADC, fEcalADCError * sADC)); + if (sADC > fADC-1) sADC = fADC-1; + Double_t sMIP = sADC / fEcalChargeADCMean * fGainRatio_12 * fGainRatio_23 / sEcalCryMipLY; + if(sMIP < fEcalMIP_Thre) return 0; + return sMIP * fEcalMIPEnergy; + } +} + +StatusCode EcalDigiAlg::MergeHits( const edm4hep::SimCalorimeterHitCollection& m_col, std::vector<edm4hep::SimCalorimeterHit>& m_hits ){ + + m_hits.clear(); + std::vector<edm4hep::MutableSimCalorimeterHit> m_mergedhit; + m_mergedhit.clear(); + + for(int iter=0; iter<m_col.size(); iter++){ + edm4hep::SimCalorimeterHit m_step = m_col[iter]; + if(!m_step.isAvailable()){ cout<<"ERROR HIT!"<<endl; continue;} + if(m_step.getEnergy()==0 || m_step.contributions_size()<1) continue; + unsigned long long cellid = m_step.getCellID(); + dd4hep::Position hitpos = m_cellIDConverter->position(cellid); + edm4hep::Vector3f pos(hitpos.x()*10, hitpos.y()*10, hitpos.z()*10); + + edm4hep::MutableCaloHitContribution conb; + conb.setEnergy(m_step.getEnergy()); + conb.setStepPosition(m_step.getPosition()); + conb.setParticle( m_step.getContributions(0).getParticle() ); + conb.setTime(m_step.getContributions(0).getTime()); + + edm4hep::MutableSimCalorimeterHit m_hit = find(m_mergedhit, cellid); + if(m_hit.getCellID()==0){ + m_hit.setCellID(cellid); + m_hit.setPosition(pos); + m_mergedhit.push_back(m_hit); + } + m_hit.addToContributions(conb); + m_hit.setEnergy(m_hit.getEnergy()+m_step.getEnergy()); + } + + for(auto iter = m_mergedhit.begin(); iter!=m_mergedhit.end(); iter++){ + edm4hep::SimCalorimeterHit constsimhit = *iter; + m_hits.push_back( constsimhit ); + } + return StatusCode::SUCCESS; +} + +double EcalDigiAlg::GetBarLength(CaloBar& bar){ + //TODO: reading bar length from geosvc. + if(bar.getSlayer()==1) return 375.133; + else{ + if(bar.getModule()%2 == 0){ + return 295.905 + (bar.getDlayer()-1)* 6.13231; + } + else{ + return 416.843 - (bar.getDlayer()+1)* 2.25221; + } + + } +} + + +/* +dd4hep::Position EcalDigiAlg::GetCellPos(dd4hep::Position& pos, CaloBar& bar){ + dd4hep::Position rpos = pos-bar.getPosition(); + TVector3 vec(0,0,0); + if(bar.getSlayer()==1) vec.SetXYZ(0, 0, floor(rpos.z()/10)*10+5 ); + else if(bar.getSlayer()==0){ + if((bar.getModule()==0||bar.getModule()==4) && bar.getDlayer()%2==1) vec.SetXYZ(floor(rpos.x()/10)*10+5,0,0); + if((bar.getModule()==0||bar.getModule()==4) && bar.getDlayer()%2==0) vec.SetXYZ(floor((rpos.x()-5)/10)*10+10,0,0); + if((bar.getModule()==2||bar.getModule()==6) && bar.getDlayer()%2==1) vec.SetXYZ(0, floor(rpos.y()/10)*10+5,0); + if((bar.getModule()==2||bar.getModule()==6) && bar.getDlayer()%2==0) vec.SetXYZ(0, floor((rpos.y()-5)/10)*10+10,0); + if(bar.getModule()==1 || bar.getModule()==5){ + TVector3 unitv(1./sqrt(2), -1./sqrt(2), 0); + if(bar.getDlayer()%2==1) vec = (floor(rpos.Dot(unitv)/10)*10+5)*unitv; + if(bar.getDlayer()%2==0) vec = (floor((rpos.Dot(unitv)-5)/10)*10+10)*unitv; + } + if(bar.getModule()==3 || bar.getModule()==7){ + TVector3 unitv(1./sqrt(2), 1./sqrt(2), 0); + if(bar.getDlayer()%2==1) vec = (floor(rpos.Dot(unitv)/10)*10+5)*unitv; + if(bar.getDlayer()%2==0) vec = (floor((rpos.Dot(unitv)-5)/10)*10+10)*unitv; + } + } + dd4hep::Position relv(vec.x(), vec.y(), vec.z()); + return relv+bar.getPosition(); +} + + +edm4hep::MutableSimCalorimeterHit EcalDigiAlg::find(edm4hep::SimCalorimeterHitCollection& m_col, dd4hep::Position& pos){ + for(int i=0;i<m_col.size();i++){ + edm4hep::MutableSimCalorimeterHit hit = m_col[i]; + dd4hep::Position ipos(hit.getPosition().x, hit.getPosition().y, hit.getPosition().z); + if(ipos==pos) return hit; + } + edm4hep::MutableSimCalorimeterHit hit; + hit.setCellID(0); + return hit; +} +*/ +edm4hep::MutableSimCalorimeterHit EcalDigiAlg::find(const std::vector<edm4hep::MutableSimCalorimeterHit>& m_col, unsigned long long& cellid) const{ + for(int i=0;i<m_col.size();i++){ + edm4hep::MutableSimCalorimeterHit hit=m_col.at(i); + if(hit.getCellID() == cellid) return hit; + } + edm4hep::MutableSimCalorimeterHit hit ; + hit.setCellID(0); + return hit; +} + +void EcalDigiAlg::Clear(){ + totE_Truth = -99; + totE_Digi = -99; + m_step_x.clear(); + m_step_y.clear(); + m_step_z.clear(); + m_step_t.clear(); // yyy: clear + m_step_E.clear(); + m_stepBar_x.clear(); + m_stepBar_y.clear(); + m_stepBar_z.clear(); + m_step_T1.clear(); + m_step_T2.clear(); + m_simBar_x.clear(); + m_simBar_y.clear(); + m_simBar_z.clear(); + m_simBar_T1.clear(); + m_simBar_T2.clear(); + m_simBar_Q1_Truth.clear(); + m_simBar_Q2_Truth.clear(); + m_simBar_Q1_Digi.clear(); + m_simBar_Q2_Digi.clear(); + m_simBar_module.clear(); + m_simBar_stave.clear(); + m_simBar_dlayer.clear(); + m_simBar_slayer.clear(); + m_simBar_cellID.clear(); +} diff --git a/Digitisers/CaloDigi/src/EcalDigiAlg.h b/Digitisers/CaloDigi/src/EcalDigiAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..058a06bda8cd80e027b2f9912cda16da0eccc885 --- /dev/null +++ b/Digitisers/CaloDigi/src/EcalDigiAlg.h @@ -0,0 +1,132 @@ +#ifndef _ECAL_DIGI_ALG_H +#define _ECAL_DIGI_ALG_H + +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" +#include "edm4hep/MutableCaloHitContribution.h" +#include "edm4hep/MutableSimCalorimeterHit.h" +#include "edm4hep/SimCalorimeterHit.h" +#include "edm4hep/CalorimeterHit.h" +#include "edm4hep/CalorimeterHitCollection.h" +#include "edm4hep/SimCalorimeterHitCollection.h" +#include "edm4hep/MCRecoCaloAssociationCollection.h" +#include "edm4hep/MCRecoCaloParticleAssociationCollection.h" +#include "CaloBar.h" +#include "HitStep.h" + +#include <DDRec/DetectorData.h> +#include <DDRec/CellIDPositionConverter.h> +#include <DD4hep/Segmentations.h> +#include "DetInterface/IGeomSvc.h" +#include "TVector3.h" +#include "TRandom3.h" +#include "TFile.h" +#include "TString.h" +#include "TH3.h" +#include "TH1.h" + +#include <cstdlib> +#include "time.h" +#include <TTimeStamp.h> +#include <ctime> + +#define C 299.79 // unit: mm/ns +#define PI 3.141592653 + +class EcalDigiAlg : public GaudiAlgorithm +{ + +public: + + EcalDigiAlg(const std::string& name, ISvcLocator* svcLoc); + + /** Called at the begin of the job before anything is read. + * Use to initialize the processor, e.g. book histograms. + */ + virtual StatusCode initialize() ; + + /** Called for every event - the working horse. + */ + virtual StatusCode execute() ; + + /** Called after data processing for clean up. + */ + virtual StatusCode finalize() ; + + + StatusCode MergeHits(const edm4hep::SimCalorimeterHitCollection& m_col, std::vector<edm4hep::SimCalorimeterHit>& m_hits); + + double GetBarLength(CaloBar& bar); //TODO: should read from geom file! + edm4hep::MutableSimCalorimeterHit find(const std::vector<edm4hep::MutableSimCalorimeterHit>& m_col, unsigned long long& cellid) const; + // double Digitization(double edepCry, double fCrosstalkChannel); + double EnergyDigi(double ScinGen, double sEcalCryMipLY); + + void Clear(); + +protected: + + SmartIF<IGeomSvc> m_geosvc; + typedef std::vector<float> FloatVec; + typedef std::map<const edm4hep::MCParticle, float> MCParticleToEnergyWeightMap; + + int _nEvt ; + float m_length; + TRandom3 rndm; + TFile* m_wfile; + TTree* t_SimCont; + TTree* t_SimBar; + + double totE_Truth, totE_Digi; + FloatVec m_step_t; // yyy: time of each step + FloatVec m_step_x, m_step_y, m_step_z, m_step_E, m_step_T1, m_step_T2, m_stepBar_x, m_stepBar_y, m_stepBar_z; + FloatVec m_simBar_x, m_simBar_y, m_simBar_z, m_simBar_T1, m_simBar_T2, m_simBar_Q1_Truth, m_simBar_Q2_Truth, m_simBar_Q1_Digi, m_simBar_Q2_Digi, m_simBar_dlayer, m_simBar_stave, m_simBar_slayer, m_simBar_module; + std::vector<unsigned long long> m_simBar_cellID; + + + dd4hep::rec::CellIDPositionConverter* m_cellIDConverter; + dd4hep::DDSegmentation::BitFieldCoder* m_decoder; + dd4hep::Detector* m_dd4hep; + + Gaudi::Property<float> m_scale{ this, "Scale", 1 }; + + // Input collections + DataHandle<edm4hep::SimCalorimeterHitCollection> r_SimCaloCol{"SimCaloCol", Gaudi::DataHandle::Reader, this}; + mutable Gaudi::Property<std::string> _readoutName{this, "ReadOutName", "CaloHitsCollection", "Readout name"}; + mutable Gaudi::Property<std::string> _filename{this, "OutFileName", "testout.root", "Output file name"}; + mutable Gaudi::Property<int> _UseRelDigi{this, "UseRealisticDigi", 1, "If use the realistic model"}; + + //Input parameters + mutable Gaudi::Property<int> _writeNtuple{this, "WriteNtuple", 1, "Write ntuple"}; + mutable Gaudi::Property<int> _Nskip{this, "SkipEvt", 0, "Skip event"}; + mutable Gaudi::Property<float> _seed{this, "Seed", 2131, "Random Seed"}; + mutable Gaudi::Property<int> _Debug{this, "Debug", 0, "Debug level"}; + mutable Gaudi::Property<float> _Eth {this, "EnergyThreshold", 0.001, "Energy Threshold (/GeV)"}; + mutable Gaudi::Property<float> r_cali{this, "CalibrECAL", 1, "Calibration coefficients for ECAL"}; + mutable Gaudi::Property<float> Latt{this, "AttenuationLength", 7000, "Crystal Attenuation Length(mm)"}; + mutable Gaudi::Property<float> Tres{this, "TimeResolution", 0.1, "Crystal time resolution in one side (ns)"}; + mutable Gaudi::Property<float> nMat{this, "MatRefractive", 2.15, "Material refractive index of crystal"}; + mutable Gaudi::Property<float> Tinit{this, "InitalTime", 2, "Start time (ns)"}; + + mutable Gaudi::Property<float> _Qthfrac {this, "ChargeThresholdFrac", 0.05, "Charge threshold fraction"}; + + mutable Gaudi::Property<int> fADC{this, "ADC", 4096, "Total ADC conuts"}; + mutable Gaudi::Property<int> fNofGain{this, "NofGain", 3, "Number of gain modes"}; + mutable Gaudi::Property<int> fADCSwitch{this, "ADCSwitch", 4000, "switching point of different gain mode"}; + mutable Gaudi::Property<float> fGainRatio_12{this, "GainRatio_12", 15, "Gain-1 over Gain-2"}; + mutable Gaudi::Property<float> fGainRatio_23{this, "GainRatio_23", 10, "Gain-2 over Gain-3"}; + mutable Gaudi::Property<float> fEcalCryMipLY{this, "EcalCryMipLY", 100, "Crystal light yield (p.e./MIP)"}; + mutable Gaudi::Property<float> fEcalMIPEnergy{this, "EcalMIPEnergy", 8.9, "MIP Energy deposit in 1cm BGO (MeV/MIP)"}; + mutable Gaudi::Property<int> fEcalSiPMPixels{this, "EcalSiPMPixels", 250000, "Pixels number of SiPM"}; + mutable Gaudi::Property<float> fEcalChargeADCMean{this, "EcalChargeADCMean", 5, "ADC per p.e. for Gain-1 (ADC)"}; + mutable Gaudi::Property<float> fEcalChargeADCSigma{this, "EcalChargeADCSigma", 2.5, "Sigma of ADC per p.e. for Gain-1 (ADC)"}; + mutable Gaudi::Property<float> fEcalADCError{this, "EcalADCError", 0.002, "ADC precision"}; + mutable Gaudi::Property<float> fEcalNoiseADCSigma{this, "EcalNoiseADCSigma", 3, "Sigma of electronic noise (ADC)"}; + mutable Gaudi::Property<float> fEcalMIP_Thre{this, "EcalMIP_Thre", 0.1, "Energy threshold for single readout end (MIP)"}; + + // Output collections + DataHandle<edm4hep::CalorimeterHitCollection> w_DigiCaloCol{"DigiCaloCol", Gaudi::DataHandle::Writer, this}; + DataHandle<edm4hep::MCRecoCaloAssociationCollection> w_CaloAssociationCol{"ECALBarrelAssoCol", Gaudi::DataHandle::Writer, this}; + DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection> w_MCPCaloAssociationCol{"ECALBarrelParticleAssoCol", Gaudi::DataHandle::Writer, this}; +}; + +#endif diff --git a/Digitisers/CaloDigi/src/HcalDigiAlg.cpp b/Digitisers/CaloDigi/src/HcalDigiAlg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a72a30cb22f501b1992d0e7ae3447e2387d6b41d --- /dev/null +++ b/Digitisers/CaloDigi/src/HcalDigiAlg.cpp @@ -0,0 +1,252 @@ +// /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// // Unit in code: mm, ns. + +#include "HcalDigiAlg.h" + +#include "edm4hep/SimCalorimeterHit.h" +#include "edm4hep/CalorimeterHit.h" +#include "edm4hep/Vector3f.h" +#include "edm4hep/Cluster.h" + +#include "DD4hep/Detector.h" +#include <DD4hep/Objects.h> +#include <DDRec/CellIDPositionConverter.h> + +#include "TVector3.h" +#include <math.h> +#include <cmath> +#include <iostream> +#include <algorithm> +#include <map> + +// #include <fstream> +// #include <ctime> + +#define C 299.79 // unit: mm/ns +#define PI 3.141592653 +using namespace std; +using namespace dd4hep; + +DECLARE_COMPONENT( HcalDigiAlg ) + +HcalDigiAlg::HcalDigiAlg(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc), + _nEvt(0) +{ + + // Input collections + declareProperty("SimCaloHitCollection", r_SimCaloCol, "Handle of the Input SimCaloHit collection"); + + // Output collections + declareProperty("CaloHitCollection", w_DigiCaloCol, "Handle of Digi CaloHit collection"); + declareProperty("CaloAssociationCollection", w_CaloAssociationCol, "Handle of CaloAssociation collection"); + declareProperty("CaloMCPAssociationCollection", w_MCPCaloAssociationCol, "Handle of CaloAssociation collection"); +} + +StatusCode HcalDigiAlg::initialize() +{ + if(_writeNtuple){ + std::string s_outfile = _filename; + m_wfile = new TFile(s_outfile.c_str(), "recreate"); + t_simHit = new TTree("simHit", "simHit"); + + t_simHit->Branch("totE", &m_totE); + t_simHit->Branch("simHit_x", &m_simHit_x); + t_simHit->Branch("simHit_y", &m_simHit_y); + t_simHit->Branch("simHit_z", &m_simHit_z); + t_simHit->Branch("simHit_E", &m_simHit_E); + t_simHit->Branch("simHit_HG", &m_simHit_HG); + t_simHit->Branch("simHit_LG", &m_simHit_LG); + t_simHit->Branch("simHit_steps", &m_simHit_steps); + + t_simHit->Branch("simHit_module", &m_simHit_module); + t_simHit->Branch("simHit_stave", &m_simHit_stave); + t_simHit->Branch("simHit_layer", &m_simHit_layer); + t_simHit->Branch("simHit_tower", &m_simHit_tower); + t_simHit->Branch("simHit_slice", &m_simHit_slice); + t_simHit->Branch("simHit_cellID", &m_simHit_cellID); + } + std::cout<<"HcalDigiAlg::m_scale="<<m_scale<<std::endl; + m_geosvc = service<IGeomSvc>("GeomSvc"); + if ( !m_geosvc ) throw "HcalDigiAlg :Failed to find GeomSvc ..."; + dd4hep::Detector* m_dd4hep = m_geosvc->lcdd(); + if ( !m_dd4hep ) throw "HcalDigiAlg :Failed to get dd4hep::Detector ..."; + m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep); + m_decoder = m_geosvc->getDecoder(_readoutName); + if (!m_decoder) { + error() << "Failed to get the decoder. " << endmsg; + return StatusCode::FAILURE; + } + + + rndm.SetSeed(_seed); + std::cout<<"HcalDigiAlg::initialize"<<std::endl; + return GaudiAlgorithm::initialize(); +} + +StatusCode HcalDigiAlg::execute() +{ +// clock_t yyy_start, yyy_enddigi; +// yyy_start = clock(); // 璁板綍寮€濮嬫椂闂� + + if(_nEvt==0) std::cout<<"HcalDigiAlg::execute Start"<<std::endl; + std::cout<<"Processing event: "<<_nEvt<<std::endl; + if(_nEvt<_Nskip){ _nEvt++; return StatusCode::SUCCESS; } + + Clear(); + m_totE = 0.; + const edm4hep::SimCalorimeterHitCollection* SimHitCol = r_SimCaloCol.get(); + + edm4hep::CalorimeterHitCollection* caloVec = w_DigiCaloCol.createAndPut(); + edm4hep::MCRecoCaloAssociationCollection* caloAssoVec = w_CaloAssociationCol.createAndPut(); + edm4hep::MCRecoCaloParticleAssociationCollection* caloMCPAssoVec = w_MCPCaloAssociationCol.createAndPut(); + + if(SimHitCol == 0) + { + std::cout<<"not found SimCalorimeterHitCollection"<< std::endl; + return StatusCode::SUCCESS; + } + if(_Debug>=1) std::cout<<"digi, input sim hit size="<< SimHitCol->size() <<std::endl; + + + for(int isim=0; isim<SimHitCol->size(); isim++){ + + auto simhit = SimHitCol->at(isim); + if(!simhit.isAvailable()) continue; + if(simhit.getEnergy()==0) continue; + + unsigned long long id = simhit.getCellID(); + double Ehit = simhit.getEnergy(); + + double sChargeOutHG = 0; + double sChargeOutLG = 0; + //Digitization + if(_UseRelDigi){ + // -- Scintillation (Energy -> MIP -> Np.e.) + int sPix = gRandom->Poisson(Ehit / _MIPCali * (_MIPADC / _PeADCMean)); + // -- Tile non-uniformity + sPix = sPix * (1.0 + gRandom->Uniform(-_TileRes, _TileRes)); + // -- SiPM Saturation (Np.e. -> Npixel) + sPix = std::round(_Pixel * (1.0 - TMath::Exp(-sPix * 1.0 / _Pixel))); + // -- ADC response (Npixel -> ADC) + double sChargeMean = sPix * _PeADCMean; + double sChargeSigma = sqrt(sPix * _PeADCSigma * _PeADCSigma); + double sChargeOut = gRandom->Gaus(sChargeMean, sChargeSigma); + // -- (ADC->MIP) + sChargeOutHG = sChargeOut + gRandom->Gaus(_BaselineHG, _BaselineSigmaHG); + sChargeOutLG = sChargeOut / _HLRatio + gRandom->Gaus(_BaselineLG, _BaselineSigmaLG); + sChargeOutHG = std::round(gRandom->Gaus(sChargeOutHG, sChargeOutHG * _ADCError)); + sChargeOutLG = std::round(gRandom->Gaus(sChargeOutLG, sChargeOutLG * _ADCError)); + if (sChargeOutLG > _ADCLimit) + sChargeOutLG = _ADCLimit; + Double_t sMIP = 0; + if (sChargeOutHG > _ADCSwitch) + { + sMIP = (sChargeOutLG - _BaselineLG) * _HLRatio / _MIPADC; + sChargeOutHG = _ADCSwitch; + } + else + { + sMIP = (sChargeOutHG - _BaselineHG) / _MIPADC; + } + Ehit = sMIP * _MIPCali; + } + if(Ehit<_MIPCali*_Eth_Mip) continue; + + //Global calibration. + //TODO: add more digitization terms here. + double Ehit_cali = Ehit*r_cali; + + //Loop contributions to get hit time and MCParticle. + double Thit_ave = 0.; + double Ehit_raw = 0.; + MCParticleToEnergyWeightMap MCPEnMap; MCPEnMap.clear(); + for(int iConb=0; iConb<simhit.contributions_size(); ++iConb){ + auto conb = simhit.getContributions(iConb); + if(!conb.isAvailable()) continue; + if(conb.getEnergy()==0) continue; + + Thit_ave += conb.getTime(); + + auto mcp = conb.getParticle(); + MCPEnMap[mcp] += conb.getEnergy(); + Ehit_raw += conb.getEnergy(); + } + Thit_ave = Thit_ave/simhit.contributions_size(); + //Create DigiHit + auto digiHit = caloVec->create(); + digiHit.setCellID(id); + digiHit.setEnergy(Ehit_cali); + digiHit.setTime(Thit_ave); + digiHit.setPosition(simhit.getPosition()); + + //Create SimHit-DigiHit association. + auto rel = caloAssoVec->create(); + rel.setRec(digiHit); + rel.setSim(simhit); + rel.setWeight(1.); + + //Create DigiHit-MCParticle association. + for(auto iter : MCPEnMap){ + auto rel_MC = caloMCPAssoVec->create(); + rel_MC.setRec(digiHit); + rel_MC.setSim(iter.first); + rel_MC.setWeight(iter.second/Ehit_raw); + } + + if(_writeNtuple){ + m_totE += digiHit.getEnergy(); + m_simHit_x.push_back(digiHit.getPosition().x); + m_simHit_y.push_back(digiHit.getPosition().y); + m_simHit_z.push_back(digiHit.getPosition().z); + m_simHit_E.push_back(digiHit.getEnergy()); + m_simHit_HG.push_back(sChargeOutHG); + m_simHit_LG.push_back(sChargeOutLG); + m_simHit_steps.push_back(simhit.contributions_size()); + m_simHit_module.push_back(m_decoder->get(id, "module")); + m_simHit_stave.push_back(m_decoder->get(id, "stave")); + m_simHit_layer.push_back(m_decoder->get(id, "layer")); + m_simHit_slice.push_back(m_decoder->get(id, "slice")); + m_simHit_tower.push_back(m_decoder->get(id, "tower")); + m_simHit_cellID.push_back(id); + } + } + + if(_writeNtuple) t_simHit->Fill(); + + _nEvt ++ ; + return StatusCode::SUCCESS; +} + +StatusCode HcalDigiAlg::finalize() +{ + if(_writeNtuple){ + m_wfile->cd(); + t_simHit->Write(); + m_wfile->Close(); + delete m_wfile, t_simHit; + } + + info() << "Processed " << _nEvt << " events " << endmsg; + delete m_cellIDConverter, m_decoder, m_geosvc; + return GaudiAlgorithm::finalize(); +} + + +void HcalDigiAlg::Clear(){ + m_totE = -99; + m_simHit_x.clear(); + m_simHit_y.clear(); + m_simHit_z.clear(); + m_simHit_E.clear(); + m_simHit_HG.clear(); + m_simHit_LG.clear(); + m_simHit_steps.clear(); + m_simHit_module.clear(); + m_simHit_stave.clear(); + m_simHit_layer.clear(); + m_simHit_slice.clear(); + m_simHit_tower.clear(); + m_simHit_cellID.clear(); +} + diff --git a/Digitisers/CaloDigi/src/HcalDigiAlg.h b/Digitisers/CaloDigi/src/HcalDigiAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..c65f3d5aeab25a004d382bd7cb266a75a480edd5 --- /dev/null +++ b/Digitisers/CaloDigi/src/HcalDigiAlg.h @@ -0,0 +1,115 @@ +#ifndef HCAL_DIGI_ALG_H +#define HCAL_DIGI_ALG_H + +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" +#include "edm4hep/MutableCaloHitContribution.h" +#include "edm4hep/MutableSimCalorimeterHit.h" +#include "edm4hep/SimCalorimeterHit.h" +#include "edm4hep/CalorimeterHit.h" +#include "edm4hep/CalorimeterHitCollection.h" +#include "edm4hep/SimCalorimeterHitCollection.h" +#include "edm4hep/MCRecoCaloAssociationCollection.h" +#include "edm4hep/MCRecoCaloParticleAssociationCollection.h" +#include "edm4hep/MCParticle.h" + +#include <DDRec/DetectorData.h> +#include <DDRec/CellIDPositionConverter.h> +#include <DD4hep/Segmentations.h> +#include "DetInterface/IGeomSvc.h" +#include "TVector3.h" +#include "TRandom3.h" +#include "TFile.h" +#include "TString.h" +#include "TH3.h" +#include "TH1.h" + +#include <cstdlib> +#include "time.h" +#include <TTimeStamp.h> +#include <ctime> + +#define C 299.79 // unit: mm/ns +#define PI 3.141592653 + +class HcalDigiAlg : public GaudiAlgorithm +{ + +public: + + HcalDigiAlg(const std::string& name, ISvcLocator* svcLoc); + + /** Called at the begin of the job before anything is read. + * Use to initialize the processor, e.g. book histograms. + */ + virtual StatusCode initialize() ; + + /** Called for every event - the working horse. + */ + virtual StatusCode execute() ; + + /** Called after data processing for clean up. + */ + virtual StatusCode finalize() ; + + void Clear(); + +protected: + + SmartIF<IGeomSvc> m_geosvc; + typedef std::vector<float> FloatVec; + typedef std::map<const edm4hep::MCParticle, float> MCParticleToEnergyWeightMap; + + int _nEvt ; + TRandom3 rndm; + TFile* m_wfile; + TTree* t_simHit; + + double m_totE; + FloatVec m_simHit_x, m_simHit_y, m_simHit_z, m_simHit_E, m_simHit_slice, m_simHit_layer, m_simHit_tower, m_simHit_stave, m_simHit_module, m_simHit_HG, m_simHit_LG; + std::vector<unsigned long long> m_simHit_cellID; + std::vector<int> m_simHit_steps; + + + dd4hep::rec::CellIDPositionConverter* m_cellIDConverter; + dd4hep::DDSegmentation::BitFieldCoder* m_decoder; + + Gaudi::Property<float> m_scale{ this, "Scale", 1 }; + + // Input collections + DataHandle<edm4hep::SimCalorimeterHitCollection> r_SimCaloCol{"SimCaloCol", Gaudi::DataHandle::Reader, this}; + mutable Gaudi::Property<std::string> _readoutName{this, "ReadOutName", "CaloHitsCollection", "Readout name"}; + mutable Gaudi::Property<std::string> _filename{this, "OutFileName", "testout.root", "Output file name"}; + + //Input parameters + mutable Gaudi::Property<int> _writeNtuple{this, "WriteNtuple", 1, "Write ntuple"}; + mutable Gaudi::Property<int> _Nskip{this, "SkipEvt", 0, "Skip event"}; + mutable Gaudi::Property<float> _seed{this, "Seed", 2131, "Random Seed"}; + mutable Gaudi::Property<int> _Debug{this, "Debug", 0, "Debug level"}; + mutable Gaudi::Property<float> r_cali{this, "CalibrHCAL", 1, "Global calibration coefficients for HCAL"}; + mutable Gaudi::Property<int> _UseRelDigi{this, "UseRealisticDigi", 1, "If use the realistic model"}; + + //add digitization parameters from AHCAL prototype + mutable Gaudi::Property<float> _MIPCali{this, "MIPResponse", 0.000461, "MIP response (/GeV)"}; + mutable Gaudi::Property<float> _Eth_Mip{this, "MIPThreshold", 0.5, "Energy Threshold (/MIP)"}; + mutable Gaudi::Property<int> _Pixel{this, "SiPMPixel", 7284, "number of SiPM pixels"}; + mutable Gaudi::Property<float> _ADCError{this, "ADCError", 0.0002, "ADC Error (/ADC)"}; + mutable Gaudi::Property<float> _MIPADC{this, "MIPADCMean", 345.7, "Mean value of MIP response adc (/ADC)"}; + mutable Gaudi::Property<float> _TileRes{this, "TileNonUniformity", 0.05, "Non-uniformity level of one tile response"}; + mutable Gaudi::Property<float> _PeADCMean{this, "PeADCMean", 30.0, "Mean value of single photons adc (/ADC)"}; + mutable Gaudi::Property<float> _PeADCSigma{this, "PeADCSigma", 3.5, "Sigma of single photons adc (/ADC)"}; + mutable Gaudi::Property<float> _BaselineHG{this, "ADCBaselineHG", 377.4, "Mean value of HG baseline adc (/ADC)"}; + mutable Gaudi::Property<float> _BaselineSigmaHG{this, "ADCBaselineSigmaHG", 3.3, "Sigma of HG baseline adc (/ADC)"}; + mutable Gaudi::Property<float> _BaselineLG{this, "ADCBaselineLG", 373.9, "Mean value of LG baseline adc (/ADC)"}; + mutable Gaudi::Property<float> _BaselineSigmaLG{this, "ADCBaselineSigmaLG", 2.2, "Sigma of LG baseline adc (/ADC)"}; + mutable Gaudi::Property<float> _HLRatio{this, "ADCHLRatio", 29.9, "The ratio of HG to LG"}; + mutable Gaudi::Property<float> _ADCSwitch{this, "ADCSwitch", 2930, "transition point from HG to LG (/ADC)"}; + mutable Gaudi::Property<float> _ADCLimit{this, "ADCLimit", 3000, "ADC saturation of LG (/ADC)"}; + + // Output collections + DataHandle<edm4hep::CalorimeterHitCollection> w_DigiCaloCol{"DigiCaloCol", Gaudi::DataHandle::Writer, this}; + DataHandle<edm4hep::MCRecoCaloAssociationCollection> w_CaloAssociationCol{"HCALBarrelAssoCol", Gaudi::DataHandle::Writer, this}; + DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection> w_MCPCaloAssociationCol{"HCALBarrelParticleAssoCol", Gaudi::DataHandle::Writer, this}; +}; + +#endif diff --git a/Digitisers/CaloDigi/src/HitStep.h b/Digitisers/CaloDigi/src/HitStep.h new file mode 100644 index 0000000000000000000000000000000000000000..2ae0715bed78e667dc5f0e437205d9d7f24a8b37 --- /dev/null +++ b/Digitisers/CaloDigi/src/HitStep.h @@ -0,0 +1,26 @@ +#ifndef HIT_STEP_H +#define HIT_STEP_H + +class HitStep{ + +public: + HitStep (double _Q, double _T): Q(_Q), T(_T) {}; + //HitStep (double _Q, double _T) { Q=_Q; T=_T; }; + HitStep() {}; + + void setQ(double _Q) { Q =_Q; } + void setT(double _T) { T =_T; } + + double getQ() const { return Q; } + double getT() const { return T; } + inline bool operator < (const HitStep &x) const { + return T <x.T ; + } + +private: + double Q; + double T; + +}; + +#endif