From 2db586a17f771cf430984b175c8179a5c9ff4ec5 Mon Sep 17 00:00:00 2001
From: "guofangyi@ihep.ac.cn" <guofangyi@ihep.ac.cn>
Date: Mon, 2 Dec 2024 07:26:09 +0000
Subject: [PATCH] Update CyberPFA

---
 Analysis/CMakeLists.txt                       |    1 +
 Analysis/GenMatch/CMakeLists.txt              |   22 +
 Analysis/GenMatch/jcls_genmatch.py            |   44 +
 Analysis/GenMatch/src/GenMatch.cpp            |  708 ++++++++++
 Analysis/GenMatch/src/GenMatch.h              |  103 ++
 Detector/DetCRD/CMakeLists.txt                |    7 +
 .../Ecal_Crystal_Endcap_v01_02.xml            |   61 +
 .../DetCRD/compact/TDR_o1_v01/TDR_o1_v01.xml  |    2 +-
 .../DetCRD/scripts/TDR_o1_v01/calodigi.py     |  113 +-
 Detector/DetCRD/scripts/TDR_o1_v01/rec.py     |  167 +++
 .../LongCrystalBarEndcapCalorimeter_v02.cpp   |  598 +++++++++
 Digitization/DigiCalo/CMakeLists.txt          |    1 +
 Digitization/DigiCalo/src/CaloBar.h           |    7 +-
 Digitization/DigiCalo/src/CaloCrystalShort.h  |   89 ++
 Digitization/DigiCalo/src/EcalDigiAlg.cpp     | 1167 +++++++++++------
 Digitization/DigiCalo/src/EcalDigiAlg.h       |  135 +-
 .../DigiCalo/src/EcalDigiAlgShort.cpp         |  535 ++++++++
 Digitization/DigiCalo/src/EcalDigiAlgShort.h  |  137 ++
 Digitization/DigiCalo/src/HcalDigiAlg.cpp     |  531 +++++---
 Digitization/DigiCalo/src/HcalDigiAlg.h       |   95 +-
 Reconstruction/RecPFACyber/CMakeLists.txt     |    2 +
 .../RecPFACyber/include/CyberPFAlg.h          |   20 +-
 .../include/Objects/Calo2DCluster.h           |    5 +-
 .../include/Objects/Calo3DCluster.h           |    3 +
 .../RecPFACyber/include/Objects/CaloUnit.h    |    3 +-
 .../RecPFACyber/include/Objects/HoughObject.h |    4 +-
 .../include/Tools/CaloHitsCreator.h           |    3 +-
 .../RecPFACyber/include/Tools/TrackCreator.h  |    7 +
 Reconstruction/RecPFACyber/script/ana.py      |   43 +
 Reconstruction/RecPFACyber/script/digi.py     |  121 +-
 Reconstruction/RecPFACyber/script/rec.py      |   33 +-
 .../RecPFACyber/script/roofit_jets.cpp        |  229 ++++
 Reconstruction/RecPFACyber/script/sim.py      |    9 +-
 Reconstruction/RecPFACyber/script/tracking.py |   44 +-
 .../src/Algorithm/PFOReclusteringAlg.cpp      |  360 ++---
 .../Algorithm/TrackClusterConnectingAlg.cpp   |   20 +-
 Reconstruction/RecPFACyber/src/CyberPFAlg.cpp |   66 +-
 .../RecPFACyber/src/Objects/Calo1DCluster.cc  |    7 +-
 .../RecPFACyber/src/Objects/Calo2DCluster.cc  |    4 +-
 .../RecPFACyber/src/Objects/Calo3DCluster.cc  |    6 +-
 .../RecPFACyber/src/Objects/CaloUnit.cc       |    2 +-
 .../RecPFACyber/src/Tools/CaloHitsCreator.cpp |  158 ++-
 .../RecPFACyber/src/Tools/OutputCreator.cpp   |   46 +-
 .../RecPFACyber/src/Tools/TrackCreator.cpp    |  146 ++-
 44 files changed, 4866 insertions(+), 998 deletions(-)
 create mode 100644 Analysis/GenMatch/CMakeLists.txt
 create mode 100644 Analysis/GenMatch/jcls_genmatch.py
 create mode 100644 Analysis/GenMatch/src/GenMatch.cpp
 create mode 100644 Analysis/GenMatch/src/GenMatch.h
 create mode 100755 Detector/DetCRD/compact/CRD_common_v01/Ecal_Crystal_Endcap_v01_02.xml
 create mode 100644 Detector/DetCRD/scripts/TDR_o1_v01/rec.py
 create mode 100755 Detector/DetCRD/src/Calorimeter/LongCrystalBarEndcapCalorimeter_v02.cpp
 create mode 100644 Digitization/DigiCalo/src/CaloCrystalShort.h
 create mode 100644 Digitization/DigiCalo/src/EcalDigiAlgShort.cpp
 create mode 100644 Digitization/DigiCalo/src/EcalDigiAlgShort.h
 create mode 100644 Reconstruction/RecPFACyber/script/ana.py
 create mode 100644 Reconstruction/RecPFACyber/script/roofit_jets.cpp

diff --git a/Analysis/CMakeLists.txt b/Analysis/CMakeLists.txt
index 49735726..6fc2f919 100644
--- a/Analysis/CMakeLists.txt
+++ b/Analysis/CMakeLists.txt
@@ -4,3 +4,4 @@ add_subdirectory(TrackInspect)
 add_subdirectory(DumpEvent)
 add_subdirectory(ReadDigi)
 add_subdirectory(JetClustering)
+add_subdirectory(GenMatch)
diff --git a/Analysis/GenMatch/CMakeLists.txt b/Analysis/GenMatch/CMakeLists.txt
new file mode 100644
index 00000000..ad3b745f
--- /dev/null
+++ b/Analysis/GenMatch/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Set the CMake module path if necessary
+
+
+# Modules
+gaudi_add_module(GenMatch
+                 SOURCES src/GenMatch.cpp
+                 LINK GearSvc
+                      Gaudi::GaudiKernel
+                      k4FWCore::k4FWCore
+                      DetInterface
+                      DataHelperLib
+                      ${GEAR_LIBRARIES} 
+                      ${GSL_LIBRARIES} 
+                      ${ROOT_LIBRARIES}
+                      ${FASTJET_LIBRARY}
+                      EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+)
+install(TARGETS GenMatch
+  EXPORT CEPCSWTargets
+  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin
+  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib
+  COMPONENT dev)
diff --git a/Analysis/GenMatch/jcls_genmatch.py b/Analysis/GenMatch/jcls_genmatch.py
new file mode 100644
index 00000000..5229515e
--- /dev/null
+++ b/Analysis/GenMatch/jcls_genmatch.py
@@ -0,0 +1,44 @@
+import os, sys
+from Gaudi.Configuration import *
+
+########### k4DataSvc ####################
+from Configurables import k4DataSvc
+#podioevent = k4DataSvc("EventDataSvc", input="./FullSim_Samples/nnHgg/Rec_TDR_o1_v01_E240_nnh_gg_test_003.root")
+podioevent = k4DataSvc("EventDataSvc", input="/publicfs/cms/user/wangzebing/CEPC/CEPCSW_tdr24.9.1/CEPCSW/FullSim_samples/Rec_TDR_o1_v01_E240_nnh_gg.root")
+##########################################
+
+########## CEPCSWData ################# 
+cepcswdatatop ="/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest"
+#######################################
+
+
+########## Podio Input ###################
+from Configurables import PodioInput
+inp = PodioInput("InputReader")
+inp.collections = [ "CyberPFO", "MCParticle" ]
+##########################################
+
+
+
+from Configurables import GenMatch
+genmatch = GenMatch("GenMatch")
+genmatch.nJets = 2
+genmatch.R = 0.6
+genmatch.OutputFile = "./RecJets_TDR_o1_v01_E240_nnh_gg.root"
+#genmatch.OutputFile = "./FullSim_samples/RecJets_TDR_o1_v01_E240_nnh_gg_CalHits.root"
+
+##############################################################################
+# POD I/O
+##############################################################################
+
+
+########################################
+
+from Configurables import ApplicationMgr
+ApplicationMgr( 
+    TopAlg=[inp, genmatch ],
+    EvtSel="NONE",
+    EvtMax=3,
+    ExtSvc=[podioevent],
+    #OutputLevel=DEBUG
+)
diff --git a/Analysis/GenMatch/src/GenMatch.cpp b/Analysis/GenMatch/src/GenMatch.cpp
new file mode 100644
index 00000000..a2d45125
--- /dev/null
+++ b/Analysis/GenMatch/src/GenMatch.cpp
@@ -0,0 +1,708 @@
+#include "GenMatch.h"
+
+#include "GaudiKernel/DataObject.h"
+#include "GaudiKernel/IHistogramSvc.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/SmartDataPtr.h"
+
+#include "DetInterface/IGeomSvc.h"
+#include "DD4hep/Detector.h"
+#include "DD4hep/DD4hepUnits.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+#include <math.h>
+#include "fastjet/ClusterSequence.hh"
+#include "fastjet/PseudoJet.hh"
+//time measurement
+#include <chrono>
+
+#include "TLorentzVector.h"
+
+using namespace fastjet;
+using namespace std;
+
+DECLARE_COMPONENT( GenMatch )
+
+//------------------------------------------------------------------------------
+GenMatch::GenMatch( const string& name, ISvcLocator* pSvcLocator )
+    : Algorithm( name, pSvcLocator ) {
+
+  declareProperty("InputPFOs", m_PFOColHdl, "Handle of the Input PFO collection");
+  declareProperty("InputGEN", m_MCParticleGenHdl, "Handle of the Input GEN collection");
+  //declareProperty("Algorithm", m_algo, "Jet clustering algorithm");
+  //declareProperty("nJets", m_nJets, "Number of jets to be clustered");
+  //declareProperty("R", m_R, "Jet clustering radius");
+  //declareProperty("OutputFile", m_outputFile, "Output file name");
+
+}
+
+//------------------------------------------------------------------------------
+StatusCode GenMatch::initialize(){
+
+  _nEvt = 0;
+
+  // Create a new TTree
+  _file = TFile::Open(m_outputFile.value().c_str(), "RECREATE");
+  _tree = new TTree("jets", "jets");
+
+  _tree->Branch("jet1_px", &jet1_px, "jet1_px/D");
+  _tree->Branch("jet1_py", &jet1_py, "jet1_py/D");
+  _tree->Branch("jet1_pz", &jet1_pz, "jet1_pz/D");
+  _tree->Branch("jet1_E", &jet1_E, "jet1_E/D");
+  _tree->Branch("jet1_costheta", &jet1_costheta, "jet1_costheta/D");
+  _tree->Branch("jet1_phi", &jet1_phi, "jet1_phi/D");
+  _tree->Branch("jet1_pt", &jet1_pt, "jet1_pt/D");
+  _tree->Branch("jet1_nconstituents", &jet1_nconstituents, "jet1_nconstituents/I");
+  _tree->Branch("jet2_px", &jet2_px, "jet2_px/D");
+  _tree->Branch("jet2_py", &jet2_py, "jet2_py/D");
+  _tree->Branch("jet2_pz", &jet2_pz, "jet2_pz/D");
+  _tree->Branch("jet2_E", &jet2_E, "jet2_E/D");
+  _tree->Branch("jet2_costheta", &jet2_costheta, "jet2_costheta/D");
+  _tree->Branch("jet2_phi", &jet2_phi, "jet2_phi/D");
+  _tree->Branch("jet2_pt", &jet2_pt, "jet2_pt/D");
+  _tree->Branch("jet2_nconstituents", &jet2_nconstituents, "jet2_nconstituents/I");
+  _tree->Branch("constituents_E1tot", &constituents_E1tot, "constituents_E1tot/D");
+  _tree->Branch("constituents_E2tot", &constituents_E2tot, "constituents_E2tot/D");
+  _tree->Branch("mass", &mass, "mass/D");
+  _tree->Branch("ymerge", ymerge, "ymerge[6]/D");
+  _tree->Branch("nparticles", &nparticles, "nparticles/I");
+  _tree->Branch("jet1_GENMatch_id", &jet1_GENMatch_id, "jet1_GENMatch_id/I");
+  _tree->Branch("jet2_GENMatch_id", &jet2_GENMatch_id, "jet2_GENMatch_id/I");
+  _tree->Branch("jet1_GENMatch_mindR", &jet1_GENMatch_mindR, "jet1_GENMatch_mindR/D");
+  _tree->Branch("jet2_GENMatch_mindR", &jet2_GENMatch_mindR, "jet2_GENMatch_mindR/D");
+
+  _tree->Branch("PFO_Energy_muon", &PFO_Energy_muon);
+  _tree->Branch("PFO_Energy_muon_GENMatch_dR", &PFO_Energy_muon_GENMatch_dR);
+  _tree->Branch("PFO_Energy_muon_GENMatch_ID", &PFO_Energy_muon_GENMatch_ID);
+  _tree->Branch("PFO_Energy_muon_GENMatch_E", &PFO_Energy_muon_GENMatch_E);
+  _tree->Branch("PFO_Energy_Charge", &PFO_Energy_Charge);
+  _tree->Branch("PFO_Energy_Charge_Ecal", &PFO_Energy_Charge_Ecal);
+  _tree->Branch("PFO_Energy_Charge_Hcal", &PFO_Energy_Charge_Hcal);
+  _tree->Branch("PFO_Energy_Charge_GENMatch_dR", &PFO_Energy_Charge_GENMatch_dR);
+  _tree->Branch("PFO_Energy_Charge_GENMatch_ID", &PFO_Energy_Charge_GENMatch_ID);
+  _tree->Branch("PFO_Energy_Charge_GENMatch_E", &PFO_Energy_Charge_GENMatch_E);
+  _tree->Branch("PFO_Hits_Charge_E", &PFO_Hits_Charge_E);
+  _tree->Branch("PFO_Hits_Charge_R", &PFO_Hits_Charge_R);
+  _tree->Branch("PFO_Hits_Charge_theta", &PFO_Hits_Charge_theta);
+  _tree->Branch("PFO_Hits_Charge_phi", &PFO_Hits_Charge_phi);
+
+  _tree->Branch("PFO_Energy_Neutral", &PFO_Energy_Neutral);
+  _tree->Branch("PFO_Energy_Neutral_singleCluster", &PFO_Energy_Neutral_singleCluster);
+  _tree->Branch("PFO_Energy_Neutral_singleCluster_R", &PFO_Energy_Neutral_singleCluster_R);
+  _tree->Branch("PFO_Hits_Neutral_E", &PFO_Hits_Neutral_E);
+  _tree->Branch("PFO_Hits_Neutral_R", &PFO_Hits_Neutral_R);
+  _tree->Branch("PFO_Hits_Neutral_theta", &PFO_Hits_Neutral_theta);
+  _tree->Branch("PFO_Hits_Neutral_phi", &PFO_Hits_Neutral_phi);
+
+  _tree->Branch("GEN_PFO_Energy_muon", &GEN_PFO_Energy_muon);
+  _tree->Branch("GEN_PFO_Energy_pipm", &GEN_PFO_Energy_pipm);
+  _tree->Branch("GEN_PFO_Energy_pi0", &GEN_PFO_Energy_pi0);
+  _tree->Branch("GEN_PFO_Energy_ppm", &GEN_PFO_Energy_ppm);
+  _tree->Branch("GEN_PFO_Energy_kpm", &GEN_PFO_Energy_kpm);
+  _tree->Branch("GEN_PFO_Energy_kL", &GEN_PFO_Energy_kL);
+  _tree->Branch("GEN_PFO_Energy_gamma", &GEN_PFO_Energy_gamma);
+  _tree->Branch("GEN_PFO_Energy_n", &GEN_PFO_Energy_n);
+  _tree->Branch("GEN_PFO_Energy_e", &GEN_PFO_Energy_e);
+
+
+  _tree->Branch("particle_index_muon", &particle_index_muon, "particle_index_muon/I");
+  _tree->Branch("particle_index_Charge", &particle_index_Charge, "particle_index_Charge/I");
+  _tree->Branch("particle_index_Neutral", &particle_index_Neutral, "particle_index_Neutral/I");
+  _tree->Branch("particle_index_Neutral_singleCluster", &particle_index_Neutral_singleCluster, "particle_index_Neutral_singleCluster/I");
+
+  _tree->Branch("GEN_particle_gamma_index", &GEN_particle_gamma_index, "GEN_particle_gamma_index/I");
+  _tree->Branch("GEN_particle_pipm_index", &GEN_particle_pipm_index, "GEN_particle_pipm_index/I");
+  _tree->Branch("GEN_particle_pi0_index", &GEN_particle_pi0_index, "GEN_particle_pi0_index/I");
+  _tree->Branch("GEN_particle_ppm_index", &GEN_particle_ppm_index, "GEN_particle_ppm_index/I");
+  _tree->Branch("GEN_particle_kpm_index", &GEN_particle_kpm_index, "GEN_particle_kpm_index/I");
+  _tree->Branch("GEN_particle_kL_index", &GEN_particle_kL_index, "GEN_particle_kL_index/I");
+  _tree->Branch("GEN_particle_n_index", &GEN_particle_n_index, "GEN_particle_n_index/I");
+  _tree->Branch("GEN_particle_e_index", &GEN_particle_e_index, "GEN_particle_e_index/I");
+
+  _tree->Branch("ymerge_gen", ymerge_gen, "ymerge_gen[6]/D");
+
+  _tree->Branch("mass_gen_match", &mass_gen_match, "mass_gen_match/D");
+  _tree->Branch("GEN_jet1_px", &GEN_jet1_px, "GEN_jet1_px/D");
+  _tree->Branch("GEN_jet1_py", &GEN_jet1_py, "GEN_jet1_py/D");
+  _tree->Branch("GEN_jet1_pz", &GEN_jet1_pz, "GEN_jet1_pz/D");
+  _tree->Branch("GEN_jet1_E", &GEN_jet1_E, "GEN_jet1_E/D");
+  _tree->Branch("GEN_jet1_costheta", &GEN_jet1_costheta, "GEN_jet1_costheta/D");
+  _tree->Branch("GEN_jet1_phi", &GEN_jet1_phi, "GEN_jet1_phi/D");
+  _tree->Branch("GEN_jet1_pt", &GEN_jet1_pt, "GEN_jet1_pt/D");
+  _tree->Branch("GEN_jet1_nconstituents", &GEN_jet1_nconstituents, "GEN_jet1_nconstituents/I");
+  _tree->Branch("GEN_jet2_px", &GEN_jet2_px, "GEN_jet2_px/D");
+  _tree->Branch("GEN_jet2_py", &GEN_jet2_py, "GEN_jet2_py/D");
+  _tree->Branch("GEN_jet2_pz", &GEN_jet2_pz, "GEN_jet2_pz/D");
+  _tree->Branch("GEN_jet2_E", &GEN_jet2_E, "GEN_jet2_E/D");
+  _tree->Branch("GEN_jet2_costheta", &GEN_jet2_costheta, "GEN_jet2_costheta/D");
+  _tree->Branch("GEN_jet2_phi", &GEN_jet2_phi, "GEN_jet2_phi/D");
+  _tree->Branch("GEN_jet2_pt", &GEN_jet2_pt, "GEN_jet2_pt/D");
+  _tree->Branch("GEN_jet2_nconstituents", &GEN_jet2_nconstituents, "GEN_jet2_nconstituents/I");
+  _tree->Branch("GEN_ISR_E", &GEN_ISR_E, "GEN_ISR_E/D");
+  _tree->Branch("GEN_ISR_pt", &GEN_ISR_pt, "GEN_ISR_pt/D");
+  _tree->Branch("GEN_inv_E", &GEN_inv_E, "GEN_inv_E/D");
+  _tree->Branch("GEN_inv_pt", &GEN_inv_pt, "GEN_inv_pt/D");
+  _tree->Branch("GEN_constituents_E1tot", &GEN_constituents_E1tot, "GEN_constituents_E1tot/D");
+  _tree->Branch("GEN_constituents_E2tot", &GEN_constituents_E2tot, "GEN_constituents_E2tot/D");
+  _tree->Branch("GEN_mass", &GEN_mass, "GEN_mass/D");
+  _tree->Branch("barrelRatio", &barrelRatio, "barrelRatio/D");
+  _tree->Branch("mass_allParticles", &mass_allParticles, "mass_allParticles/D");
+  _tree->Branch("GEN_nparticles", &GEN_nparticles, "GEN_nparticles/I");
+  
+  return StatusCode::SUCCESS;
+
+}
+
+//------------------------------------------------------------------------------
+StatusCode GenMatch::execute(){
+  
+  const edm4hep::ReconstructedParticleCollection* PFO = nullptr;
+  try {
+    PFO = m_PFOColHdl.get();
+  }
+  catch ( GaudiException &e ){
+    info() << "Collection " << m_PFOColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg;
+    return StatusCode::SUCCESS;
+  }
+  // Check if the collection is empty
+  if ( PFO->size() == 0 ) {
+    info() << "Collection " << m_PFOColHdl.fullKey() << " is empty in event " << _nEvt << endmsg;
+    return StatusCode::SUCCESS;
+  }
+
+  const edm4hep::MCParticleCollection* MCParticlesGen = nullptr;
+  try {
+    MCParticlesGen = m_MCParticleGenHdl.get();
+  }
+  catch ( GaudiException &e ){
+    info() << "Collection " << m_MCParticleGenHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg;
+    return StatusCode::SUCCESS;
+  }
+  // Check if the collection is empty
+  if ( MCParticlesGen->size() == 0 ) {
+    info() << "Collection " << m_MCParticleGenHdl.fullKey() << " is empty in event " << _nEvt << endmsg;
+    return StatusCode::SUCCESS;
+  }
+  //initial indces
+  CleanVars();
+  
+  //resize particles. there are many particles are empty, maybe upstream bugs
+  vector<PseudoJet> input_particles;
+  TLorentzVector input_particles_sum;
+  for(const auto& pfo : *PFO){
+    if ( isnan(pfo.getMomentum()[0]) || isnan(pfo.getMomentum()[1]) || isnan(pfo.getMomentum()[2]) || pfo.getEnergy() == 0) {
+      info() << "Particle " << _particle_index << " px: " << pfo.getMomentum()[0] << " py: " << pfo.getMomentum()[1] << " pz: " << pfo.getMomentum()[2] << " E: " << pfo.getEnergy()  << endmsg;
+      _particle_index++;
+      continue;
+    }
+    else{
+      input_particles.push_back(PseudoJet(pfo.getMomentum()[0], pfo.getMomentum()[1], pfo.getMomentum()[2], pfo.getEnergy()));
+      _particle_index++;
+      _nparticles++;
+      TLorentzVector p4_pfo;
+      p4_pfo.SetPxPyPzE(pfo.getMomentum()[0], pfo.getMomentum()[1], pfo.getMomentum()[2], pfo.getEnergy());
+      input_particles_sum += p4_pfo;
+      //std::cout << "Particle " << _particle_index << " px: "<<pfo.getMomentum()[0]<<" py: "<<pfo.getMomentum()[1]<<" pz: "<<pfo.getMomentum()[2]<<" E: "<<pfo.getEnergy() << ", mass "<< pfo.getMass() << std::endl;
+
+      if (abs(pfo.getCharge()) > 0 && pfo.clusters_size() == 0){
+        //PFO_Energy_muon[_particle_index_muon] = pfo.getEnergy();
+        //_particle_index_muon++;
+        PFO_Energy_muon.push_back(pfo.getEnergy());
+
+        float mini_dR = 99.0;
+        float dR_temp = 99.0; 
+        float deta = 99.0; 
+        float dphi = 99.0;
+        int PFO_Energy_muon_GENMatch_ID_temp = -999;
+        float PFO_Energy_muon_GENMatch_E_temp = -999;
+        for(const auto& Gen : *MCParticlesGen){
+          if (Gen.getGeneratorStatus() != 1) continue;
+          if ( abs(Gen.getPDG())==12 || abs(Gen.getPDG())==14 || abs(Gen.getPDG())==16 ) continue;
+          TLorentzVector p4_gen;
+          p4_gen.SetPxPyPzE(Gen.getMomentum()[0], Gen.getMomentum()[1], Gen.getMomentum()[2], Gen.getEnergy());
+          deta = p4_pfo.Eta() - p4_gen.Eta();
+          dphi = TVector2::Phi_mpi_pi(p4_pfo.Phi() - p4_gen.Phi());
+          dR_temp = TMath::Sqrt(deta*deta + dphi*dphi);
+          if (dR_temp < mini_dR){
+            mini_dR = dR_temp;
+            PFO_Energy_muon_GENMatch_ID_temp = Gen.getPDG();
+            PFO_Energy_muon_GENMatch_E_temp = Gen.getEnergy();
+          }
+        }
+        PFO_Energy_muon_GENMatch_dR.push_back(mini_dR);
+        PFO_Energy_muon_GENMatch_ID.push_back(PFO_Energy_muon_GENMatch_ID_temp);
+        PFO_Energy_muon_GENMatch_E.push_back(PFO_Energy_muon_GENMatch_E_temp);
+
+      } 
+      else if (abs(pfo.getCharge()) > 0 && pfo.clusters_size() > 0){
+        //PFO_Energy_Charge[_particle_index_Charge] = pfo.getEnergy();
+        //_particle_index_Charge++;
+        PFO_Energy_Charge.push_back(pfo.getEnergy());
+
+        float PFO_Energy_Charge_Ecal_temp = 0;
+        float PFO_Energy_Charge_Hcal_temp = 0;
+        int PFO_Energy_Charge_GENMatch_ID_temp = -999;
+        float PFO_Energy_Charge_GENMatch_E_temp = -999;
+        for (unsigned i = 0; i < pfo.clusters_size(); i++){
+          if (TMath::Sqrt(pfo.getClusters(i).getPosition().x * pfo.getClusters(i).getPosition().x + pfo.getClusters(i).getPosition().y * pfo.getClusters(i).getPosition().y) < 2130){
+            PFO_Energy_Charge_Ecal_temp += pfo.getClusters(i).getEnergy();
+          }else{
+            PFO_Energy_Charge_Hcal_temp += pfo.getClusters(i).getEnergy();
+          }
+        }
+
+        PFO_Energy_Charge_Ecal.push_back(PFO_Energy_Charge_Ecal_temp);
+        PFO_Energy_Charge_Hcal.push_back(PFO_Energy_Charge_Hcal_temp);
+
+        float mini_dR = 99.0;
+        float dR_temp = 99.0; 
+        float deta = 99.0; 
+        float dphi = 99.0;
+        for(const auto& Gen : *MCParticlesGen){
+          if (Gen.getGeneratorStatus() != 1) continue;
+          if ( abs(Gen.getPDG())==12 || abs(Gen.getPDG())==14 || abs(Gen.getPDG())==16 ) continue;
+          TLorentzVector p4_gen;
+          p4_gen.SetPxPyPzE(Gen.getMomentum()[0], Gen.getMomentum()[1], Gen.getMomentum()[2], Gen.getEnergy());
+          deta = p4_pfo.Eta() - p4_gen.Eta();
+          dphi = TVector2::Phi_mpi_pi(p4_pfo.Phi() - p4_gen.Phi());
+          dR_temp = TMath::Sqrt(deta*deta + dphi*dphi);
+          if (dR_temp < mini_dR){
+            mini_dR = dR_temp;
+            PFO_Energy_Charge_GENMatch_ID_temp = Gen.getPDG();
+            PFO_Energy_Charge_GENMatch_E_temp = Gen.getEnergy();
+          }
+        }
+        PFO_Energy_Charge_GENMatch_dR.push_back(mini_dR);
+        PFO_Energy_Charge_GENMatch_ID.push_back(PFO_Energy_Charge_GENMatch_ID_temp);
+        PFO_Energy_Charge_GENMatch_E.push_back(PFO_Energy_Charge_GENMatch_E_temp);
+
+        
+        for (unsigned i = 0; i < pfo.clusters_size(); i++){
+          std::vector<double> PFO_Hits_Charge_perCluster_E;
+          std::vector<double> PFO_Hits_Charge_perCluster_R;
+          std::vector<double> PFO_Hits_Charge_perCluster_theta;
+          std::vector<double> PFO_Hits_Charge_perCluster_phi;
+          for (unsigned j = 0; j < pfo.getClusters(i).hits_size(); j++){
+            PFO_Hits_Charge_perCluster_E.push_back(pfo.getClusters(i).getHits(j).getEnergy());
+            PFO_Hits_Charge_perCluster_R.push_back(TMath::Sqrt(pfo.getClusters(i).getHits(j).getPosition().x*pfo.getClusters(i).getHits(j).getPosition().x + pfo.getClusters(i).getHits(j).getPosition().y*pfo.getClusters(i).getHits(j).getPosition().y));
+            PFO_Hits_Charge_perCluster_theta.push_back(pfo.getClusters(i).getHits(j).getPosition().z/std::asin(TMath::Sqrt(pfo.getClusters(i).getHits(j).getPosition().x*pfo.getClusters(i).getHits(j).getPosition().x + pfo.getClusters(i).getHits(j).getPosition().y*pfo.getClusters(i).getHits(j).getPosition().y + pfo.getClusters(i).getHits(j).getPosition().z*pfo.getClusters(i).getHits(j).getPosition().z)));
+            PFO_Hits_Charge_perCluster_phi.push_back(std::atan2(pfo.getClusters(i).getHits(j).getPosition().y, pfo.getClusters(i).getHits(j).getPosition().x));
+          }
+          //info() << "[Clusters Hits] " << PFO_Hits_Charge_perCluster_E << endmsg;
+          //std::copy(PFO_Hits_Charge_perCluster_E.begin(), PFO_Hits_Charge_perCluster_E.end(), std::ostream_iterator<double>(std::cout, " "));
+          //std::cout << "[Clusters Hits] " << std::endl;
+          PFO_Hits_Charge_E.push_back(PFO_Hits_Charge_perCluster_E);
+          PFO_Hits_Charge_R.push_back(PFO_Hits_Charge_perCluster_R);
+          PFO_Hits_Charge_theta.push_back(PFO_Hits_Charge_perCluster_theta);
+          PFO_Hits_Charge_phi.push_back(PFO_Hits_Charge_perCluster_phi);
+        }
+
+
+      }
+      else if (abs(pfo.getCharge()) == 0 && pfo.clusters_size() > 1){
+        //PFO_Energy_Neutral[_particle_index_Neutral] += pfo.getEnergy();
+        //_particle_index_Neutral++;
+        PFO_Energy_Neutral.push_back(pfo.getEnergy());
+      }
+      else if (abs(pfo.getCharge()) == 0 && pfo.clusters_size() == 1){
+        //PFO_Energy_Neutral_singleCluster[_particle_index_Neutral_singleCluster] = pfo.getEnergy();
+        //PFO_Energy_Neutral_singleCluster_R[_particle_index_Neutral_singleCluster] = TMath::Sqrt(pfo.getClusters(0).getPosition().x * pfo.getClusters(0).getPosition().x + pfo.getClusters(0).getPosition().y * pfo.getClusters(0).getPosition().y + pfo.getClusters(0).getPosition().z * pfo.getClusters(0).getPosition().z);
+        //_particle_index_Neutral_singleCluster++;
+        PFO_Energy_Neutral_singleCluster.push_back(pfo.getEnergy());
+        PFO_Energy_Neutral_singleCluster_R.push_back(TMath::Sqrt(pfo.getClusters(0).getPosition().x * pfo.getClusters(0).getPosition().x + pfo.getClusters(0).getPosition().y * pfo.getClusters(0).getPosition().y));
+
+        for (unsigned i = 0; i < pfo.clusters_size(); i++){
+          std::vector<double> PFO_Hits_Neutral_perCluster_E;
+          std::vector<double> PFO_Hits_Neutral_perCluster_R;
+          std::vector<double> PFO_Hits_Neutral_perCluster_theta;
+          std::vector<double> PFO_Hits_Neutral_perCluster_phi;
+          for (unsigned j = 0; j < pfo.getClusters(i).hits_size(); j++){
+            PFO_Hits_Neutral_perCluster_E.push_back(pfo.getClusters(i).getHits(j).getEnergy());
+            PFO_Hits_Neutral_perCluster_R.push_back(TMath::Sqrt(pfo.getClusters(i).getHits(j).getPosition().x*pfo.getClusters(i).getHits(j).getPosition().x + pfo.getClusters(i).getHits(j).getPosition().y*pfo.getClusters(i).getHits(j).getPosition().y));
+            PFO_Hits_Neutral_perCluster_theta.push_back(pfo.getClusters(i).getHits(j).getPosition().z/std::asin(TMath::Sqrt(pfo.getClusters(i).getHits(j).getPosition().x*pfo.getClusters(i).getHits(j).getPosition().x + pfo.getClusters(i).getHits(j).getPosition().y*pfo.getClusters(i).getHits(j).getPosition().y + pfo.getClusters(i).getHits(j).getPosition().z*pfo.getClusters(i).getHits(j).getPosition().z)));
+            PFO_Hits_Neutral_perCluster_phi.push_back(std::atan2(pfo.getClusters(i).getHits(j).getPosition().y, pfo.getClusters(i).getHits(j).getPosition().x));
+          }
+          PFO_Hits_Neutral_E.push_back(PFO_Hits_Neutral_perCluster_E);
+          PFO_Hits_Neutral_R.push_back(PFO_Hits_Neutral_perCluster_R);
+          PFO_Hits_Neutral_theta.push_back(PFO_Hits_Neutral_perCluster_theta);
+          PFO_Hits_Neutral_phi.push_back(PFO_Hits_Neutral_perCluster_phi);
+        }
+      }
+    }
+  }
+
+  particle_index_muon = _particle_index_muon;
+  particle_index_Charge = _particle_index_Charge;
+  particle_index_Neutral = _particle_index_Neutral;
+  particle_index_Neutral_singleCluster = _particle_index_Neutral_singleCluster;
+
+  // create a jet definition
+  int nJets = m_nJets;
+  double R = m_R;
+
+  JetDefinition jet_def(ee_kt_algorithm);
+  //JetDefinition jet_def(antikt_algorithm, R);
+
+  // run the clustering, extract the jets
+  //std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
+
+  ClusterSequence clust_seq(input_particles, jet_def);
+  
+  vector<PseudoJet> jets = sorted_by_pt(clust_seq.exclusive_jets(nJets));
+  
+  //std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+  
+  //_time = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() / 1000000.0;
+  
+  //info() << "FastJet clustering done in seconds: " << _time << endmsg;
+  
+  //string jet_def_str = jet_def.description();
+  //debug() << "Clustering with " << jet_def_str << " for " << nJets << " jets with R = " << R << endmsg;
+  
+  // print the jets
+  TLorentzVector Particles_Gen_match_sum;
+  //info() << "                     px           py           pz           E           costheta  phi " << endmsg;
+  for (unsigned i = 0; i < jets.size(); i++) {
+    //info() << "   jet " << i << "             " << jets[i].px() << " " << jets[i].py() << " " << jets[i].pz() << " " << jets[i].E() << " " << jets[i].cos_theta() << " " << jets[i].phi() << endmsg;
+    vector<PseudoJet> constituents = jets[i].constituents();
+
+    for (unsigned j = 0; j < constituents.size(); j++) {
+      if ( i == 1 ){
+        constituents_E1tot += constituents[j].E();
+        jet1_nparticles++;
+        }
+      if ( i == 2 ) {
+        constituents_E2tot += constituents[j].E();
+        jet2_nparticles++;
+        }
+      //info() << "    constituent  " << j << " " << constituents[j].px() << " " << constituents[j].py() << " " << constituents[j].pz() << " " << constituents[j].E() << " " << constituents[j].cos_theta() << " " << constituents[j].phi() << endmsg;
+
+      TLorentzVector p4_pfo;
+      p4_pfo.SetPxPyPzE(constituents[j].px(), constituents[j].py(), constituents[j].pz(), constituents[j].E());
+
+      float mini_dR = 0.3;
+      float dR_temp = 0.0; 
+      float deta = 0.0; 
+      float dphi =0.0;
+      TLorentzVector p4_gen_match;
+      for(const auto& Gen : *MCParticlesGen){
+        if (Gen.getGeneratorStatus() != 1) continue;
+        if ( abs(Gen.getPDG())==12 || abs(Gen.getPDG())==14 || abs(Gen.getPDG())==16 ) continue;
+        TLorentzVector p4_gen;
+        p4_gen.SetPxPyPzE(Gen.getMomentum()[0], Gen.getMomentum()[1], Gen.getMomentum()[2], Gen.getEnergy());
+        deta = p4_pfo.Eta() - p4_gen.Eta();
+        dphi = TVector2::Phi_mpi_pi(p4_pfo.Phi() - p4_gen.Phi());
+        dR_temp = TMath::Sqrt(deta*deta + dphi*dphi);
+        if (dR_temp < mini_dR){
+          mini_dR = dR_temp;
+          p4_gen_match = p4_gen;
+        }
+      }
+      Particles_Gen_match_sum += p4_gen_match;
+    }
+  }
+  //info() << "Total energy of constituents: " << constituents_E1tot << " " << constituents_E2tot << endmsg;
+
+
+  double _ymin[20];
+  for(int i=1; i<6;i++){
+    _ymin[i-1] = clust_seq.exclusive_ymerge (i);
+   // info() << " -log10(y" << i << i+1 << ") = " << -log10(_ymin[i-1]) << endmsg;
+  }
+  
+
+  mass = (jets[0] + jets[1]).m();
+
+
+  vector<PseudoJet> input_particles_gen;
+  int NNeutrinoCount = 0;
+  for(const auto& Gen : *MCParticlesGen){
+    //info() << "[[DEBUG]] Gen Particle stable 1 " << _gen_particle_index << " px: " << Gen.getMomentum()[0] << " py: " << Gen.getMomentum()[1] << " pz: " << Gen.getMomentum()[2] << " E: " << Gen.getEnergy() << " PDG ID: " << Gen.getPDG() << " GeneratorStatus: " << Gen.getGeneratorStatus() << endmsg;
+    if ( (abs(Gen.getPDG())==12 || abs(Gen.getPDG())==14 || abs(Gen.getPDG())==16) && Gen.getGeneratorStatus()!=2 ){ 
+      NNeutrinoCount++;
+//cout<<"  Found Neutrino #"<<NNeutrinoCount<<endl;
+      if(NNeutrinoCount > 2) {
+        auto tmpP0 = Gen.getMomentum();
+        TVector3 tmpP = TVector3(tmpP0.x, tmpP0.y, tmpP0.z);
+        GEN_inv_E += tmpP.Mag();
+        GEN_inv_pt += tmpP.Perp();
+//cout<<"    Inv energy "<<GEN_inv_E<<", pt "<<GEN_inv_pt<<endl; 
+      }      
+      _gen_particle_index++;
+      continue;
+    }
+    if (Gen.getGeneratorStatus() != 1) continue;
+    //info() << "[[DEBUG]] Gen Particle stable 1 " << _gen_particle_index << " px: " << Gen.getMomentum()[0] << " py: " << Gen.getMomentum()[1] << " pz: " << Gen.getMomentum()[2] << " E: " << Gen.getEnergy() << " PDG ID: " << Gen.getPDG() << " GeneratorStatus: " << Gen.getGeneratorStatus() << endmsg;
+    input_particles_gen.push_back(PseudoJet(Gen.getMomentum()[0], Gen.getMomentum()[1], Gen.getMomentum()[2], Gen.getEnergy()));
+    if (Gen.getPDG()==22){
+      //GEN_PFO_Energy_gamma[_gen_particle_gamma_index] = Gen.getEnergy();
+      //_gen_particle_gamma_index++;
+      GEN_PFO_Energy_gamma.push_back(Gen.getEnergy());
+      int NParent = Gen.parents_size();
+//cout<<"  Found photon. index "<<_gen_particle_index<<", Nparent = "<<NParent<<endl;
+      if(_gen_particle_index<4 && NParent==0){
+        auto tmpP0 = Gen.getMomentum();
+        TVector3 tmpP = TVector3(tmpP0.x, tmpP0.y, tmpP0.z);        
+        GEN_ISR_E += tmpP.Mag();
+        GEN_ISR_pt += tmpP.Perp();
+//cout<<"  Found ISR photon. E = "<<GEN_ISR_E<<", pt = "<<GEN_ISR_pt<<endl;
+      }
+    }
+    else if (Gen.getPDG()==211 || Gen.getPDG()==-211){
+      //GEN_PFO_Energy_pipm[_gen_particle_pipm_index] = Gen.getEnergy();
+      //_gen_particle_pipm_index++;
+      GEN_PFO_Energy_pipm.push_back(Gen.getEnergy());
+    }
+    else if (Gen.getPDG()==111){
+      //GEN_PFO_Energy_pi0[_gen_particle_pi0_index] = Gen.getEnergy();
+      //_gen_particle_pi0_index++;
+      GEN_PFO_Energy_pi0.push_back(Gen.getEnergy());
+    }
+    else if (Gen.getPDG()==2212 || Gen.getPDG()==-2212){
+      //GEN_PFO_Energy_ppm[_gen_particle_ppm_index] = Gen.getEnergy();
+      //_gen_particle_ppm_index++;
+      GEN_PFO_Energy_ppm.push_back(Gen.getEnergy());
+    }
+    else if (Gen.getPDG()==321 || Gen.getPDG()==-321){
+      //GEN_PFO_Energy_kpm[_gen_particle_kpm_index] = Gen.getEnergy();
+      //_gen_particle_kpm_index++;
+      GEN_PFO_Energy_kpm.push_back(Gen.getEnergy());
+    }
+    else if (Gen.getPDG()==130){
+      //GEN_PFO_Energy_kL[_gen_particle_kL_index] = Gen.getEnergy();
+      //_gen_particle_kL_index++;
+      GEN_PFO_Energy_kL.push_back(Gen.getEnergy());
+    }
+    
+    else if (abs(Gen.getPDG())==2112){
+      //GEN_PFO_Energy_n[_gen_particle_n_index] = Gen.getEnergy();
+      //_gen_particle_n_index++;
+      GEN_PFO_Energy_n.push_back(Gen.getEnergy());
+    }
+    
+    else if (abs(Gen.getPDG())==11){
+      //GEN_PFO_Energy_e[_gen_particle_e_index] = Gen.getEnergy();
+      //_gen_particle_e_index++;
+      GEN_PFO_Energy_e.push_back(Gen.getEnergy());
+    }
+    else if (abs(Gen.getPDG())==13){
+      //GEN_PFO_Energy_e[_gen_particle_e_index] = Gen.getEnergy();
+      //_gen_particle_e_index++;
+      GEN_PFO_Energy_muon.push_back(Gen.getEnergy());
+    }
+    
+    _gen_particle_index++;
+  }
+
+  int Nmc = 0;
+  int Nmc_barrel = 0;
+  int n_status1 = 0;
+  for(const auto& Gen : *MCParticlesGen){
+    if (Gen.getGeneratorStatus() != 1) continue;
+    n_status1++;
+
+    TVector3 part(Gen.getMomentum().x, Gen.getMomentum().y, Gen.getMomentum().z);
+
+    if(n_status1<=4)
+    {
+      // ISR photon should not hit ECAL barrel
+      if(Gen.getPDG()==22 && Gen.getEnergy()>0 && fabs(part.CosTheta())<0.85) Nmc_barrel = 0;
+      continue;
+    }
+    Nmc++;
+    if(fabs(part.CosTheta())<0.85) Nmc_barrel++;
+  }
+
+  barrelRatio = (double)Nmc_barrel/(double)Nmc;
+
+  GEN_particle_gamma_index = _gen_particle_gamma_index;
+  GEN_particle_pipm_index = _gen_particle_pipm_index;
+  GEN_particle_pi0_index = _gen_particle_pi0_index;
+  GEN_particle_ppm_index = _gen_particle_ppm_index;
+  GEN_particle_kpm_index = _gen_particle_kpm_index;
+  GEN_particle_kL_index = _gen_particle_kL_index;
+  GEN_particle_n_index = _gen_particle_n_index;
+  GEN_particle_e_index = _gen_particle_e_index;
+
+  //info() << "[[DEBUG]] Gen Particle stable 1 " << _gen_particle_index << " seperate: " << GEN_particle_gamma_index+GEN_particle_pipm_index+GEN_particle_pi0_index+GEN_particle_ppm_index+GEN_particle_kpm_index+GEN_particle_kL_index+GEN_particle_n_index << endmsg;
+
+  // create a jet definition
+
+  JetDefinition Genjet_def(ee_kt_algorithm);
+  //JetDefinition jet_def(antikt_algorithm, R);
+
+  // run the clustering, extract the jets
+  //std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
+
+  ClusterSequence Genclust_seq(input_particles_gen, Genjet_def);
+  
+  vector<PseudoJet> Genjets = sorted_by_pt(Genclust_seq.exclusive_jets(nJets));
+  
+  //std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+
+  double _ymin_gen[20];
+  for(int i=1; i<6;i++){
+    _ymin_gen[i-1] = Genclust_seq.exclusive_ymerge (i);
+    //info() << " -log10(y" << i << i+1 << ") = " << -log10(_ymin_gen[i-1]) << endmsg;
+  }
+
+  // ############## Jet Gen Match
+  for (unsigned i = 0; i < jets.size(); i++) {
+    float GEN_mini_dR = 999.;
+    int GEN_mini_ID_temp = -99.0;
+    float GEN_dR_temp = -99.0; 
+    float GEN_deta = 0.0; 
+    float GEN_dphi =0.0;
+
+    for (unsigned j = 0; j < Genjets.size(); j++) {
+      GEN_deta = jets[i].eta() - Genjets[j].eta();
+      GEN_dphi = TVector2::Phi_mpi_pi(jets[i].phi() - Genjets[j].phi());
+      GEN_dR_temp = TMath::Sqrt(GEN_deta*GEN_deta + GEN_dphi*GEN_dphi);
+      
+      if (GEN_dR_temp < GEN_mini_dR){
+        GEN_mini_dR = GEN_dR_temp;
+        GEN_mini_ID_temp = j;
+      }
+    }
+    if (i==0) {
+      jet1_GENMatch_id = GEN_mini_ID_temp;
+      jet1_GENMatch_mindR = GEN_mini_dR;
+      }
+    if (i==1) {
+      jet2_GENMatch_id = GEN_mini_ID_temp;
+      jet2_GENMatch_mindR = GEN_mini_dR;
+      }
+  }
+
+
+  
+  //for (unsigned i = 0; i < Genjets.size(); i++) {
+  //  vector<PseudoJet> constituents = Genjets[i].constituents();
+  //  for (unsigned j = 0; j < constituents.size(); j++) {
+
+  //    for(const auto& Gen : *MCParticlesGen){
+  //      if (abs(constituents[j].px()-Gen.getMomentum()[0])<0.00001 && abs(constituents[j].py()-Gen.getMomentum()[1])<0.00001 && abs(constituents[j].pz()-Gen.getMomentum()[2])<0.00001 && abs(constituents[j].E()-Gen.getEnergy()[0])<0.00001 )
+  //       if (i==0) {
+  //        jet1_GENMatch_id = GEN_mini_ID_temp;
+  //        jet1_GENMatch_mindR = GEN_mini_dR;
+  //        }
+  //       if (i==1) {
+  //        jet2_GENMatch_id = GEN_mini_ID_temp;
+  //        jet2_GENMatch_mindR = GEN_mini_dR;
+  //        }
+  //    }
+  //    
+  //  }
+  //}
+    
+  
+
+
+
+  // fill the tree
+  jet1_px = jets[0].px();
+  jet1_py = jets[0].py();
+  jet1_pz = jets[0].pz();
+  jet1_E = jets[0].E();
+  jet1_costheta = jets[0].cos_theta();
+  jet1_phi = jets[0].phi();
+  jet1_pt = jets[0].pt();
+  jet1_nconstituents = jets[0].constituents().size();
+  jet2_px = jets[1].px();
+  jet2_py = jets[1].py();
+  jet2_pz = jets[1].pz();
+  jet2_E = jets[1].E();
+  jet2_costheta = jets[1].cos_theta();
+  jet2_phi = jets[1].phi();
+  jet2_pt = jets[1].pt();
+  jet2_nconstituents = jets[1].constituents().size();
+  for(int i=0; i<6; i++){
+    ymerge[i] = _ymin[i];
+  }
+  for(int i=0; i<6; i++){
+    ymerge_gen[i] = _ymin_gen[i];
+  }
+
+  mass_gen_match = Particles_Gen_match_sum.M();
+  mass_allParticles = input_particles_sum.M();
+  nparticles = _nparticles;
+  GEN_nparticles = _gen_particle_index;
+
+  GEN_mass = (Genjets[0] + Genjets[1]).m();
+  GEN_jet1_px = Genjets[0].px();
+  GEN_jet1_py = Genjets[0].py();
+  GEN_jet1_pz = Genjets[0].pz();
+  GEN_jet1_E = Genjets[0].E();
+  GEN_jet1_costheta = Genjets[0].cos_theta();
+  GEN_jet1_phi = Genjets[0].phi();
+  GEN_jet1_pt = Genjets[0].pt();
+  GEN_jet1_nconstituents = Genjets[0].constituents().size();
+  GEN_jet2_px = Genjets[1].px();
+  GEN_jet2_py = Genjets[1].py();
+  GEN_jet2_pz = Genjets[1].pz();
+  GEN_jet2_E = Genjets[1].E();
+  GEN_jet2_costheta = Genjets[1].cos_theta();
+  GEN_jet2_phi = Genjets[1].phi();
+  GEN_jet2_pt = Genjets[1].pt();
+  GEN_jet2_nconstituents = Genjets[1].constituents().size();
+
+  _tree->Fill();
+
+  _nEvt++;
+  return StatusCode::SUCCESS;
+
+}
+
+//------------------------------------------------------------------------------
+StatusCode GenMatch::finalize(){
+  debug() << "Finalizing..." << endmsg;
+  _file->Write();
+
+  delete _tree;
+  return StatusCode::SUCCESS;
+}
+
+
+void GenMatch::CleanVars(){
+
+  _particle_index = 0;
+  _gen_particle_index = _particle_index_muon = _particle_index_Charge = _particle_index_Neutral = _particle_index_Neutral_singleCluster = 0;
+  particle_index_muon = particle_index_Charge = particle_index_Neutral = particle_index_Neutral_singleCluster = 0;
+  _jet_index = 0;
+  _nparticles = 0;
+  _time = 0;
+
+  jet1_px = jet1_py = jet1_pz = jet1_E = 0;
+  jet2_px = jet2_py = jet2_pz = jet2_E = 0;
+  jet1_costheta = jet1_phi = 0;
+  jet2_costheta = jet2_phi = 0;
+  jet1_pt = jet2_pt = jet1_GENMatch_mindR = jet2_GENMatch_mindR = 0;
+  jet1_nconstituents = jet2_nconstituents = nparticles = jet1_GENMatch_id = jet2_GENMatch_id = 0;
+  constituents_E1tot = constituents_E2tot = 0;
+  _gen_particle_gamma_index = _gen_particle_pipm_index = _gen_particle_pi0_index = _gen_particle_ppm_index = _gen_particle_kpm_index = _gen_particle_kL_index = _gen_particle_n_index = _gen_particle_e_index = 0;
+  GEN_particle_gamma_index = GEN_particle_pipm_index = GEN_particle_pi0_index = GEN_particle_ppm_index = GEN_particle_kpm_index = GEN_particle_kL_index = GEN_particle_n_index = GEN_particle_e_index = 0;
+  for(int i=0; i<6; i++){
+    ymerge[i] = 0;
+  }
+  for(int i=0; i<6; i++){
+    ymerge_gen[i] = 0;
+  }
+
+  PFO_Energy_muon.clear(); PFO_Energy_muon_GENMatch_dR.clear(); PFO_Energy_muon_GENMatch_ID.clear(); PFO_Energy_muon_GENMatch_E.clear(); PFO_Energy_Charge.clear(); PFO_Energy_Charge_Ecal.clear(); PFO_Energy_Charge_Hcal.clear(); PFO_Energy_Charge_GENMatch_dR.clear(); PFO_Energy_Charge_GENMatch_ID.clear(); PFO_Energy_Charge_GENMatch_E.clear(); PFO_Energy_Neutral.clear(); PFO_Energy_Neutral_singleCluster.clear(); PFO_Energy_Neutral_singleCluster_R.clear();
+  GEN_PFO_Energy_muon.clear(); GEN_PFO_Energy_pipm.clear(); GEN_PFO_Energy_pi0.clear(); GEN_PFO_Energy_ppm.clear(); GEN_PFO_Energy_kpm.clear(); GEN_PFO_Energy_kL.clear(); GEN_PFO_Energy_n.clear(); GEN_PFO_Energy_e.clear(); GEN_PFO_Energy_gamma.clear();
+  PFO_Hits_Charge_E.clear(); PFO_Hits_Charge_R.clear(); PFO_Hits_Charge_theta.clear(); PFO_Hits_Charge_phi.clear();
+  PFO_Hits_Neutral_E.clear(); PFO_Hits_Neutral_R.clear(); PFO_Hits_Neutral_theta.clear(); PFO_Hits_Neutral_phi.clear();
+
+  mass = mass_gen_match = GEN_mass = mass_allParticles = 0;
+  barrelRatio = 0;
+  GEN_inv_E = GEN_inv_pt = 0;
+  GEN_ISR_E = GEN_ISR_pt = 0;
+  GEN_jet1_px = GEN_jet1_py = GEN_jet1_pz = GEN_jet1_E = 0;
+  GEN_jet2_px = GEN_jet2_py = GEN_jet2_pz = GEN_jet2_E = 0;
+  GEN_jet1_costheta = GEN_jet1_phi = 0;
+  GEN_jet2_costheta = GEN_jet2_phi = 0;
+  GEN_jet1_pt = GEN_jet2_pt = 0;
+  GEN_jet1_nconstituents = GEN_jet2_nconstituents = GEN_nparticles = 0;
+  GEN_constituents_E1tot = GEN_constituents_E2tot = 0;
+
+}
+
diff --git a/Analysis/GenMatch/src/GenMatch.h b/Analysis/GenMatch/src/GenMatch.h
new file mode 100644
index 00000000..abdab139
--- /dev/null
+++ b/Analysis/GenMatch/src/GenMatch.h
@@ -0,0 +1,103 @@
+#ifndef GenMatch_h
+#define GenMatch_h 1
+
+#include "UTIL/ILDConf.h"
+#include "k4FWCore/DataHandle.h"
+#include "GaudiKernel/Algorithm.h"
+#include <random>
+#include "GaudiKernel/NTuple.h"
+#include "TFile.h"
+#include "TTree.h"
+
+#include "edm4hep/ReconstructedParticleData.h"
+#include "edm4hep/ReconstructedParticleCollection.h"
+#include "edm4hep/ReconstructedParticle.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/MCParticleCollectionData.h"
+
+class GenMatch : public Algorithm {
+ public:
+  // Constructor of this form must be provided
+  GenMatch( const std::string& name, ISvcLocator* pSvcLocator );
+
+  // Three mandatory member functions of any algorithm
+  StatusCode initialize() override;
+  StatusCode execute() override;
+  StatusCode finalize() override;
+
+ private:
+
+  DataHandle<edm4hep::ReconstructedParticleCollection> m_PFOColHdl{"CyberPFO", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCParticleCollection> m_MCParticleGenHdl{"MCParticle", Gaudi::DataHandle::Reader, this};
+  Gaudi::Property<std::string> m_algo{this, "Algorithm", "ee_kt_algorithm"};
+  Gaudi::Property<int> m_nJets{this, "nJets", 2};
+  Gaudi::Property<double> m_R{this, "R", 0.6};
+  Gaudi::Property<std::string> m_outputFile{this, "OutputFile", "GenMatch.root"};
+
+  int _nEvt;
+  int _particle_index;
+  int _jet_index;
+  int _nparticles;
+  int jet1_nparticles;
+  int jet2_nparticles;
+  double _time;
+
+  TFile* _file;
+  TTree* _tree;
+  double jet1_px, jet1_py, jet1_pz, jet1_E;
+  double jet2_px, jet2_py, jet2_pz, jet2_E;
+  double jet1_costheta, jet1_phi;
+  double jet2_costheta, jet2_phi;
+  double jet1_pt, jet2_pt;
+  int jet1_nconstituents, jet2_nconstituents, nparticles, jet1_GENMatch_id, jet2_GENMatch_id;
+  double constituents_E1tot;
+  double constituents_E2tot;
+  double ymerge[6];
+  double mass;
+  double mass_gen_match, jet1_GENMatch_mindR, jet2_GENMatch_mindR;
+  double mass_allParticles;
+  //double PFO_Energy_muon[50];
+  //double PFO_Energy_Charge[50];
+  //double PFO_Energy_Neutral[50];
+  //double PFO_Energy_Neutral_singleCluster[600];
+  //double PFO_Energy_Neutral_singleCluster_R[600];
+  int _particle_index_muon, _particle_index_Charge, _particle_index_Neutral, _particle_index_Neutral_singleCluster;
+  int particle_index_muon, particle_index_Charge, particle_index_Neutral, particle_index_Neutral_singleCluster;
+  //double GEN_PFO_Energy_muon[50];
+  //double GEN_PFO_Energy_pipm[120];
+  //double GEN_PFO_Energy_pi0[120];
+  //double GEN_PFO_Energy_ppm[120];
+  //double GEN_PFO_Energy_kpm[120];
+  //double GEN_PFO_Energy_kL[120];
+  //double GEN_PFO_Energy_n[50];
+  //double GEN_PFO_Energy_e[50];
+  //double GEN_PFO_Energy_gamma[120];
+  std::vector<double> PFO_Energy_muon, PFO_Energy_muon_GENMatch_dR, PFO_Energy_muon_GENMatch_E, PFO_Energy_Charge, PFO_Energy_Charge_Ecal, PFO_Energy_Charge_Hcal, PFO_Energy_Charge_GENMatch_dR, PFO_Energy_Charge_GENMatch_E, PFO_Energy_Neutral, PFO_Energy_Neutral_singleCluster, PFO_Energy_Neutral_singleCluster_R;
+  std::vector<int> PFO_Energy_Charge_GENMatch_ID, PFO_Energy_muon_GENMatch_ID;
+  std::vector<double> GEN_PFO_Energy_muon, GEN_PFO_Energy_pipm, GEN_PFO_Energy_pi0, GEN_PFO_Energy_ppm, GEN_PFO_Energy_kpm, GEN_PFO_Energy_kL, GEN_PFO_Energy_n, GEN_PFO_Energy_e, GEN_PFO_Energy_gamma;
+  std::vector<std::vector<double>> PFO_Hits_Charge_E, PFO_Hits_Charge_R, PFO_Hits_Charge_theta, PFO_Hits_Charge_phi;
+  std::vector<std::vector<double>> PFO_Hits_Neutral_E, PFO_Hits_Neutral_R, PFO_Hits_Neutral_theta, PFO_Hits_Neutral_phi;
+  //double PFO_Energy_muon[500];
+
+  int _gen_particle_index;
+  double barrelRatio;
+  double ymerge_gen[6];
+  double GEN_mass;
+  double GEN_ISR_E, GEN_ISR_pt;
+  double GEN_inv_E, GEN_inv_pt;
+  double GEN_jet1_px, GEN_jet1_py, GEN_jet1_pz, GEN_jet1_E;
+  double GEN_jet2_px, GEN_jet2_py, GEN_jet2_pz, GEN_jet2_E;
+  double GEN_jet1_costheta, GEN_jet1_phi;
+  double GEN_jet2_costheta, GEN_jet2_phi;
+  double GEN_jet1_pt, GEN_jet2_pt;
+  int GEN_jet1_nconstituents, GEN_jet2_nconstituents, GEN_nparticles;
+  double GEN_constituents_E1tot;
+  double GEN_constituents_E2tot;
+  int _gen_particle_gamma_index, _gen_particle_pipm_index, _gen_particle_pi0_index, _gen_particle_ppm_index, _gen_particle_kpm_index, _gen_particle_kL_index, _gen_particle_n_index, _gen_particle_e_index;
+  int GEN_particle_gamma_index, GEN_particle_pipm_index, GEN_particle_pi0_index, GEN_particle_ppm_index, GEN_particle_kpm_index, GEN_particle_kL_index, GEN_particle_n_index, GEN_particle_e_index;
+
+  void CleanVars();
+
+};
+#endif
+
diff --git a/Detector/DetCRD/CMakeLists.txt b/Detector/DetCRD/CMakeLists.txt
index 6f874165..37b2f66d 100644
--- a/Detector/DetCRD/CMakeLists.txt
+++ b/Detector/DetCRD/CMakeLists.txt
@@ -7,6 +7,7 @@ gaudi_add_module(DetCRD
                  SOURCES src/Calorimeter/CRDEcal_v01.cpp
                          src/Calorimeter/LongCrystalBarBarrelCalorimeter32Polygon_v01.cpp
                          src/Calorimeter/LongCrystalBarEndcapCalorimeter_v01.cpp
+                         src/Calorimeter/LongCrystalBarEndcapCalorimeter_v02.cpp
                          src/Calorimeter/CRDEcal_Short_v02.cpp
                          src/Calorimeter/CRDEcal_Endcap_Short_v01.cpp
                          src/Calorimeter/RotatedPolyhedraBarrelCalorimeter_v01_geo.cpp
@@ -75,6 +76,12 @@ add_test(
   WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
   )
 
+add_test(
+  NAME Test_TDR_o1_v01_PFA
+  COMMAND gaudirun.py Detector/DetCRD/scripts/TDR_o1_v01/rec.py
+  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+  )
+
 foreach(detoption TDR_o1_v01)
   add_test(
     NAME Test_${detoption}_Geo
diff --git a/Detector/DetCRD/compact/CRD_common_v01/Ecal_Crystal_Endcap_v01_02.xml b/Detector/DetCRD/compact/CRD_common_v01/Ecal_Crystal_Endcap_v01_02.xml
new file mode 100755
index 00000000..929405c5
--- /dev/null
+++ b/Detector/DetCRD/compact/CRD_common_v01/Ecal_Crystal_Endcap_v01_02.xml
@@ -0,0 +1,61 @@
+<lccdd>
+  <define>
+    <!-- <constant name="Ecal_endcap_inner_radius" value="2.5*mm"/>
+    <constant name="Ecal_endcap_inner_radius" value="2.5*mm"/> -->
+    <constant name="Ecal_endcap_nlayers" value="28"/>
+    <constant name="Ecal_scintillator_thickness" value="10*mm"/>
+    <constant name="Ecal_deadarea_thickness" value="8.5*mm"/>
+  </define>
+
+  <detectors>
+    <detector id="DetID_ECAL_ENDCAP" name="EcalEndcap" type="LongCrystalBarEndcapCalorimeter_v02" readout="EcalEndcapsCollection"  vis="CyanVis" calorimeterType="EMC_ENDCAP">
+      <comment>Electromagnetic Calorimeter Endcap</comment>
+
+      <envelope vis="SeeThrough">
+        <shape type="BooleanShape" operation="Subtraction" material="Air">
+          <shape type="BooleanShape" operation="Subtraction" material="Air">
+            <shape type="Tube" rmin="0.0" rmax="Ecal_endcap_outer_radius - env_safety" dz="Ecal_endcap_zmax"/> <!--there is a thin plane in envolop -->
+            <shape type="Tube" rmin="0.0" rmax="Ecal_endcap_outer_radius + env_safety" dz="Ecal_endcap_zmin"/>
+          </shape>
+        <shape type="Box" dx="Ecal_endcap_inner_radius" dy="Ecal_endcap_inner_radius" dz="Ecal_endcap_zmax + env_safety"/> 
+        </shape>
+        <rotation x="0" y="0" z="0"/>
+      </envelope>
+
+      <type_flags type=" DetType_CALORIMETER + DetType_ENDCAP + DetType_EMC " />
+
+      <material name="CarbonFiber"/> 
+
+      <dimensions numsides="Ecal_x_module" > <!-- 0:cube 1:isosceles trapezoid 2:right trapezoid -->
+        <dimensions id="1"  module_type="0" module_number="3" x_offset="766.5*mm" y_offset="766.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="326*mm" dim_y="326*mm" dim_z="300*mm"/>
+        <dimensions id="2"  module_type="0" module_number="2" x_offset="1067.5*mm" y_offset="1067.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="276*mm" dim_y="276*mm" dim_z="300*mm"/>
+        <dimensions id="3"  module_type="0" module_number="1" x_offset="1304*mm" y_offset="1304*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="197*mm" dim_y="197*mm" dim_z="300*mm"/>
+        <dimensions id="4"  module_type="1" module_number="4" x_offset="570.5*mm" y_offset="0*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x1="574*mm" dim_x2="495*mm" dim_y1="441*mm" dim_y2="441*mm" dim_z="300*mm" />
+        <dimensions id="7"  module_type="4" module_number="4" x_offset="570.5*mm" y_offset="0*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x1="574*mm" dim_x2="495*mm" dim_y1="441*mm" dim_y2="441*mm" dim_z="300*mm" />
+        <dimensions id="5"  module_type="2" module_number="4" x_offset="425.5*mm" y_offset="435*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x1="318*mm" dim_x2="356*mm" dim_y1="356*mm" dim_y2="356*mm" dim_z="300*mm"/>
+        <dimensions id="8"  module_type="5" module_number="4" x_offset="425.5*mm" y_offset="435*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x1="318*mm" dim_x2="356*mm" dim_y1="356*mm" dim_y2="356*mm" dim_z="300*mm"/>
+        <dimensions id="6"  module_type="3" module_number="1" x_offset="425.5*mm" y_offset="425.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="178*mm" dim_y="140*mm" dim_z="300*mm"/>
+        <dimensions id="9"  module_type="6" module_number="1" x_offset="425.5*mm" y_offset="425.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="178*mm" dim_y="140*mm" dim_z="300*mm"/>
+        <dimensions id="10"  module_type="7" module_number="1" x_offset="425.5*mm" y_offset="425.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="178*mm" dim_y="140*mm" dim_z="300*mm"/>
+        <dimensions id="11"  module_type="8" module_number="1" x_offset="425.5*mm" y_offset="425.5*mm" z_offset="Ecal_endcap_zmin+Ecal_endcap_thickness/2" dim_x="178*mm" dim_y="140*mm" dim_z="300*mm"/>
+        <!-- 425.5 -->
+      </dimensions>
+
+      <layer repeat="Ecal_endcap_nlayers" vis="CyanVis" material="G4_BGO" thickness = "Ecal_scintillator_thickness">
+        <slice material="G4_BGO" thickness = "Ecal_scintillator_thickness" sensitive = "yes"   limits="cal_limits"  vis="CyanVis"   />
+      </layer>
+    </detector>
+  </detectors>
+
+  <readouts>
+    <readout name="EcalEndcapsCollection">
+      <segmentation type="NoSegmentation"/>
+      <id>system:5,module:1,part:7,stave:7,type:4,dlayer:4,slayer:1,bar:7</id>
+    </readout>
+  </readouts>
+
+</lccdd>
+
+
+
+
diff --git a/Detector/DetCRD/compact/TDR_o1_v01/TDR_o1_v01.xml b/Detector/DetCRD/compact/TDR_o1_v01/TDR_o1_v01.xml
index 881750ac..1bcac3c8 100644
--- a/Detector/DetCRD/compact/TDR_o1_v01/TDR_o1_v01.xml
+++ b/Detector/DetCRD/compact/TDR_o1_v01/TDR_o1_v01.xml
@@ -42,7 +42,7 @@
   <!--include ref="../CRD_common_v01/OTKEndcap_v01_01.xml"/-->
 
   <include ref="../CRD_common_v01/Ecal_Crystal_Barrel_v01_02.xml"/>
-  <include ref="../CRD_common_v01/Ecal_Crystal_Endcap_v01_01.xml"/>
+  <include ref="../CRD_common_v01/Ecal_Crystal_Endcap_v01_02.xml"/>
   <include ref="../CRD_common_v01/SHcalGlass_Barrel_v05.xml"/>
   <include ref="../CRD_common_v01/SHcalGlass_Endcaps_v01.xml"/>
 
diff --git a/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py b/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py
index 2b48aae4..46e93c7c 100644
--- a/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py
+++ b/Detector/DetCRD/scripts/TDR_o1_v01/calodigi.py
@@ -48,12 +48,14 @@ from Configurables import PodioInput
 podioinput = PodioInput("PodioReader", collections=[
 #    "EventHeader",
     "MCParticle",
-    "EcalBarrelCollection", 
-    "EcalBarrelContributionCollection", 
-    "HcalBarrelCollection", 
-    "HcalBarrelContributionCollection", 
-    "CompleteTracks", 
-    "CompleteTracksParticleAssociation"
+    "EcalBarrelCollection",
+    "EcalBarrelContributionCollection",
+    "EcalEndcapsCollection",
+    "EcalEndcapsContributionCollection",
+    "HcalBarrelCollection",
+    "HcalBarrelContributionCollection",
+    "HcalEndcapsCollection",
+    "HcalEndcapsContributionCollection"
     ])
 
 ########## Digitalization ################
@@ -61,19 +63,46 @@ podioinput = PodioInput("PodioReader", collections=[
 ##ECAL##
 from Configurables import EcalDigiAlg
 EcalDigi = EcalDigiAlg("EcalDigiAlg")
-EcalDigi.ReadOutName = "EcalBarrelCollection"
-EcalDigi.SimCaloHitCollection = "EcalBarrelCollection"
-EcalDigi.CaloHitCollection = "ECALBarrel"
-EcalDigi.CaloAssociationCollection = "ECALBarrelAssoCol"
-EcalDigi.CaloMCPAssociationCollection = "ECALBarrelParticleAssoCol"
+EcalDigi.SimCaloHitCollection = ["EcalBarrelCollection", "EcalEndcapsCollection"]
+EcalDigi.ReadOutName = ["EcalBarrelCollection", "EcalEndcapsCollection"]
+EcalDigi.CaloHitCollection = ["ECALBarrel", "ECALEndcaps"]
+EcalDigi.CaloAssociationCollection = ["ECALBarrelAssoCol", "ECALEndcapsAssoCol"]
+EcalDigi.CaloMCPAssociationCollection = ["ECALBarrelParticleAssoCol", "ECALEndcapsParticleAssoCol"]
 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.TimeResolution = 0.7            # 0.7 ns
+EcalDigi.EcalMIPEnergy = 8.9             # MIP energy 8.9 MeV for 1 cm BGO
+EcalDigi.EcalMIP_Thre = 0.05              # 0.05 mip at each side, 0.1 mip for one bar
+EcalDigi.UseRealisticDigi = 1
+# scintillation
+EcalDigi.UseDigiScint = 1
+EcalDigi.EcalCryIntLY = 8200             #intrinsic LY 8200 [p.e./MIP]
+EcalDigi.EcalCryMipLY = 200              #Detected effective LY 200 [p.e./MIP]
+EcalDigi.AttenuationLength = 1e8         # 8000 mm for 5% non-uniformity
+# SiPM
+EcalDigi.SiPMDigiVerbose = 2             # 0:w/o response, w/o correction; 1:w/ response, w/o correction; 2:w/ response, w/ simple correction; 3:w/ response, w/ full correction
+EcalDigi.EcalSiPMPDE = 0.25              # NDL-EQR06, PDE 0.25
+EcalDigi.EcalSiPMDCR = 0                 # NDL-EQR06, dark count rate 2500000 [Hz]
+EcalDigi.EcalTimeInterval = 0.           # Time interval 0.000002 [s]. DCR*TimeInterval = dark count noise
+EcalDigi.EcalSiPMCT = 0.                 # SiPM crosstalk Probability 12%
+EcalDigi.EcalSiPMGainMean = 50           # 50 [ADC/p.e.]
+EcalDigi.EcalSiPMGainSigma = 0.08        # 0.08
+# ADC
+EcalDigi.ADC = 8192                      # 13-bit, 8192
+EcalDigi.ADCSwitch = 8000                # 8000
+EcalDigi.Pedestal = 50                   # Pedestal 50 ADC
+EcalDigi.GainRatio_12 = 50               # Gain ratio 50
+EcalDigi.GainRatio_23 = 60               # Gain ratio 60
+# temperature control
+EcalDigi.UseCryTemp = 0
+EcalDigi.UseCryTempCor = 0
+EcalDigi.UseSiPMTemp = 0
+EcalDigi.UseSiPMTempCor = 0
+EcalDigi.EcalTempGrad = 3./27            # 3./27 = 3K from 0 to 27 layer
+EcalDigi.EcalBGOTempCoef = -0.0138       # -0.0138 [%/K]
+EcalDigi.EcalSiPMGainTempCoef = -0.03    # -0.03 [%/K]
+EcalDigi.EcalSiPMDCRTempCoef = 3.34/80   # 3.34/80 [10^{k*deltaT}]
 EcalDigi.WriteNtuple = 0
 EcalDigi.OutFileName = "Digi_ECAL.root"
 #########################################
@@ -81,31 +110,41 @@ 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.SimCaloHitCollection = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+HcalDigi.ReadOutName = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+HcalDigi.CaloHitCollection = ["HCALBarrel", "HCALEndcaps"]
+HcalDigi.CaloAssociationCollection = ["HCALBarrelAssoCol", "HCALEndcapsAssoCol"]
+HcalDigi.CaloMCPAssociationCollection = ["HCALBarrelParticleAssoCol", "HCALEndcapsParticleAssoCol"]
 HcalDigi.SkipEvt = 0
 HcalDigi.Seed = 2079
-#Digitalization parameters
-HcalDigi.MIPResponse = 0.007126  # MeV / MIP
-HcalDigi.MIPThreshold = 0.1    # Unit: MIP
 HcalDigi.CalibrHCAL = 1.
-HcalDigi.UseRealisticDigi = 1    # Flag to use digitization model.
-HcalDigi.SiPMPixel = 57600       # 57600 for 6025PE (6*6 mm, 25 um pixel pitch)
+#Digitalization parameters
+HcalDigi.UseRealisticDigi = 0     #---------Flag to use digitization model.
+HcalDigi.MIPResponse = 0.007126   # 0.007.126 GeV / MIP
+HcalDigi.MIPThreshold = 0.1       # ----------Unit: MIP
+HcalDigi.TemperatureVariation = 0 # Temperature variation 1K
+# Scintillation
+HcalDigi.UseTileLYMap = 0
+HcalDigi.MIPLY = 80               # Glass LY
+HcalDigi.LYTempCoef = 0           # Glass LY with temperature
 HcalDigi.TileNonUniformity = 0.0
-HcalDigi.ADCError = 0.0
-HcalDigi.MIPADCMean = 80.*30.0   # Light yield 80 pe/mip
-HcalDigi.PeADCMean = 30.0
-HcalDigi.PeADCSigma = 0.
-HcalDigi.ADCBaselineHG = 0
-HcalDigi.ADCBaselineSigmaHG = 0.
-HcalDigi.ADCBaselineLG = 0
-HcalDigi.ADCBaselineSigmaLG = 0.
-HcalDigi.ADCHLRatio = 1
-HcalDigi.ADCSwitch = 1e7
-HcalDigi.ADCLimit = 1e7
+# SiPM
+HcalDigi.SiPMPixel = 57600           #---------57600 for 6025PE (6*6 mm, 25 um pixel pitch)
+HcalDigi.SiPMDCR = 1600              #---------1600 for 6025PE (6*6 mm, 25 um pixel pitch), 3200 for 6015PS ()
+HcalDigi.SiPMCT = 0.0                #---------SiPM crosstalk Probability 0.12
+HcalDigi.TimeInterval = 0.           #---------Shaping time 2 us
+HcalDigi.SiPMGainTempCoef = 0        #---------Temperature dependence of SiPM gain (-3%/K)
+HcalDigi.SiPMDCRTempCoef = 0         #---------Temperature dependence of SiPM DCR (10^{k*deltaT}, k=3.34/80)
+# ADC
+HcalDigi.ADC = 8192
+HcalDigi.ADCSwitch = 1e7          # Switch at 8000
+HcalDigi.GainRatio_12 = 50
+HcalDigi.GainRatio_23 = 60
+HcalDigi.SiPMGainMean = 20        # SiPM gain: 2 ADC / p.e.
+HcalDigi.SiPMGainSigma = 0.08     # Fluctuation of ADC / p.e.
+HcalDigi.SiPMNoiseSigma = 0       # SiPM noise sigma
+HcalDigi.Pedestal = 50            # Pedestal 50 ADC
+HcalDigi.PedestalSigma = 4        # Sigma of electronic noise (4 ADC)
 HcalDigi.WriteNtuple = 0
 HcalDigi.OutFileName = "Digi_HCAL.root"
 
diff --git a/Detector/DetCRD/scripts/TDR_o1_v01/rec.py b/Detector/DetCRD/scripts/TDR_o1_v01/rec.py
new file mode 100644
index 00000000..362421ef
--- /dev/null
+++ b/Detector/DetCRD/scripts/TDR_o1_v01/rec.py
@@ -0,0 +1,167 @@
+import os, sys
+from Gaudi.Configuration import *
+
+############## GeomSvc #################
+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 DetGeomSvc
+geomsvc = DetGeomSvc("GeomSvc")
+geomsvc.compact = geometry_path
+#######################################
+
+########### k4DataSvc ####################
+from Configurables import k4DataSvc
+podioevent = k4DataSvc("EventDataSvc", input="CaloDigi_TDR_o1_v01_00.root")
+##########################################
+
+########## CEPCSWData ################# 
+cepcswdatatop ="/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest"
+#######################################
+
+########## CrystalEcalEnergyCorrectionSvc ########
+from Configurables import CrystalEcalEnergyCorrectionSvc
+crystalecalcorr = CrystalEcalEnergyCorrectionSvc("CrystalEcalEnergyCorrectionSvc")
+crystalecalcorr.CorrectionFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Service/CrystalEcalSvc/data/CrackRegionEnergyCorrection.root")
+##################################################
+
+########## Podio Input ###################
+from Configurables import PodioInput
+inp = PodioInput("InputReader")
+inp.collections = [ 
+                    "ECALBarrel",
+                    "ECALBarrelParticleAssoCol",
+#                    "ECALEndcaps",
+#                    "ECALEndcapsParticleAssoCol",
+                    "HCALBarrel",
+                    "HCALBarrelParticleAssoCol",
+#                    "HCALEndcaps",
+#                    "HCALEndcapsParticleAssoCol",
+                    "MCParticle", 
+                    "CompleteTracks", 
+                    "CompleteTracksParticleAssociation"]
+##########################################
+
+######### Reconstruction ################
+from Configurables import CyberPFAlg
+CyberPFAlg = CyberPFAlg("CyberPFAlg")
+##----Global parameters----
+CyberPFAlg.Seed = 1024
+CyberPFAlg.BField = 3.
+CyberPFAlg.Debug = 0
+CyberPFAlg.SkipEvt = 0
+CyberPFAlg.WriteAna = 1
+CyberPFAlg.AnaFileName = "RecAnaTuple_TDR_o1_v01.root"
+CyberPFAlg.UseMCPTrack = 0
+CyberPFAlg.UseTruthMatchTrack = 0
+CyberPFAlg.DoCleanTrack = 1
+CyberPFAlg.TrackIDFile = "/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest/CEPCSWData/offline-data/Reconstruction/CyberPFA_trackID/TrkID_BDT_BDTG.weights.xml"
+CyberPFAlg.TrackIDMethod = "BDTG"
+CyberPFAlg.EcalChargedCalib = 1.26
+CyberPFAlg.HcalChargedCalib = 4.0
+CyberPFAlg.EcalNeutralCalib = 1.0
+CyberPFAlg.HcalNeutralCalib = 4.0
+##----Readin collections----
+CyberPFAlg.MCParticleCollection = "MCParticle"
+CyberPFAlg.TrackCollections = ["CompleteTracks"]
+CyberPFAlg.MCRecoTrackParticleAssociationCollection = "CompleteTracksParticleAssociation"
+#CyberPFAlg.ECalCaloHitCollections = ["ECALBarrel","ECALEndcaps"]
+#CyberPFAlg.ECalReadOutNames = ["EcalBarrelCollection","EcalEndcapsCollection"]
+#CyberPFAlg.ECalMCPAssociationName = ["ECALBarrelParticleAssoCol", "ECALEndcapsParticleAssoCol"]
+#CyberPFAlg.HCalCaloHitCollections = ["HCALBarrel", "HCALEndcaps"]
+#CyberPFAlg.HCalReadOutNames = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+#CyberPFAlg.HCalMCPAssociationName = ["HCALBarrelParticleAssoCol", "HCALEndcapsParticleAssoCol"]
+CyberPFAlg.ECalCaloHitCollections = ["ECALBarrel"]
+CyberPFAlg.ECalReadOutNames = ["EcalBarrelCollection"]
+CyberPFAlg.ECalMCPAssociationName = ["ECALBarrelParticleAssoCol"]
+CyberPFAlg.HCalCaloHitCollections = ["HCALBarrel"]
+CyberPFAlg.HCalReadOutNames = ["HcalBarrelCollection"]
+CyberPFAlg.HCalMCPAssociationName = ["HCALBarrelParticleAssoCol"]
+
+##--- Output collections ---
+CyberPFAlg.OutputPFO = "outputPFO";
+CyberPFAlg.RecoPFOCollection = "CyberPFO"
+
+#----Algorithms----
+CyberPFAlg.AlgList = ["GlobalClusteringAlg",      #1
+                            "LocalMaxFindingAlg",       #2
+                            "TrackMatchingAlg",         #3
+                            "HoughClusteringAlg",       #4
+                            "ConeClustering2DAlg",      #5
+                            "AxisMergingAlg",           #6
+                            "EnergySplittingAlg",       #9
+                            "EnergyTimeMatchingAlg",    #11
+                            "HcalClusteringAlg",        #12
+                            "TruthClusteringAlg",       #15
+                            "TrackClusterConnectingAlg",  #16
+                            "PFOReclusteringAlg" ]  #17
+CyberPFAlg.AlgParNames = [ ["InputECALBars","OutputECAL1DClusters","OutputECALHalfClusters"],#1
+                                 ["OutputLocalMaxName"],#2
+                                 ["ReadinLocalMaxName","OutputLongiClusName"],#3
+                                 ["ReadinLocalMaxName","LeftLocalMaxName","OutputLongiClusName"],#4
+                                 ["ReadinLocalMaxName", "OutputLongiClusName"], #5
+                                 ["OutputAxisName"], #6
+                                 ["ReadinAxisName", "OutputClusName", "OutputTowerName"],  #9
+                                 ["ReadinHFClusterName", "ReadinTowerName","OutputClusterName"], #11
+                                 ["InputHCALHits", "OutputHCALClusters"], #12
+                                 ["DoECALClustering","DoHCALClustering","InputHCALHits","OutputHCALClusters"], #15
+                                 ["ReadinECALClusterName", "ReadinHCALClusterName", "OutputCombPFO"],  #16
+                                 ["ECALChargedCalib", "HCALChargedCalib", "ECALNeutralCalib", "HCALNeutralCalib"] ]#17
+CyberPFAlg.AlgParTypes = [ ["string","string","string"],#1
+                                 ["string"],#2
+                                 ["string","string"],#3
+                                 ["string","string","string"],#4
+                                 ["string","string"], #5
+                                 ["string"], #6
+                                 ["string","string","string"],  #9
+                                 ["string","string","string"], #11
+                                 ["string", "string"], #12
+                                 ["bool","bool","string","string"], #15
+                                 ["string","string","string"],  #16
+                                 ["double","double", "double","double"] ]#17
+CyberPFAlg.AlgParValues = [ ["BarCol","Cluster1DCol","HalfClusterCol"],#1
+                                  ["AllLocalMax"],#2
+                                  ["AllLocalMax","TrackAxis"],#3
+                                  ["AllLocalMax","LeftLocalMax","HoughAxis"],#4
+                                  ["LeftLocalMax","ConeAxis"], #5
+                                  ["MergedAxis"], #6
+                                  ["MergedAxis","ESHalfCluster","ESTower"],  #9
+                                  ["ESHalfCluster","ESTower","EcalCluster"], #11
+                                  ["HCALBarrel", "SimpleHCALCluster"], #12
+                                  ["0","1","HCALBarrel","HCALCluster"], #15
+                                  ["EcalCluster", "SimpleHCALCluster", "outputPFO"],  #16
+                                  ["1.26","4.", "1.", "4."]  ]#17
+
+
+from Configurables import GenMatch
+genmatch = GenMatch("GenMatch")
+genmatch.nJets = 2
+genmatch.R = 0.6
+genmatch.OutputFile = "Jets_TDR_o1_v01.root"
+
+##############################################################################
+# POD I/O
+##############################################################################
+from Configurables import PodioOutput
+out = PodioOutput("outputalg")
+out.filename = "Rec_TDR_o1_v01_00.root"
+out.outputCommands = ["keep *"]
+
+########################################
+
+from Configurables import ApplicationMgr
+ApplicationMgr( 
+    TopAlg=[inp, CyberPFAlg, out ],
+    EvtSel="NONE",
+    EvtMax=5,
+    ExtSvc=[podioevent, geomsvc],
+    #OutputLevel=DEBUG
+)
diff --git a/Detector/DetCRD/src/Calorimeter/LongCrystalBarEndcapCalorimeter_v02.cpp b/Detector/DetCRD/src/Calorimeter/LongCrystalBarEndcapCalorimeter_v02.cpp
new file mode 100755
index 00000000..1fadab16
--- /dev/null
+++ b/Detector/DetCRD/src/Calorimeter/LongCrystalBarEndcapCalorimeter_v02.cpp
@@ -0,0 +1,598 @@
+#include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/DetType.h"
+#include "XML/Layering.h"
+#include "XML/Utilities.h"
+#include "DDRec/DetectorData.h"
+#include "DDSegmentation/BitField64.h"
+#include "DDSegmentation/Segmentation.h"
+#include "DDSegmentation/MultiSegmentation.h"
+// #include "LcgeoExceptions.h"
+
+using namespace std;
+
+using dd4hep::BUILD_ENVELOPE;
+using dd4hep::BitField64;
+using dd4hep::Box;
+using dd4hep::Trapezoid;
+using dd4hep::Trap;
+using dd4hep::EightPointSolid;
+using dd4hep::DetElement;
+using dd4hep::DetType;
+using dd4hep::Detector;
+using dd4hep::Layering;
+using dd4hep::Material;
+using dd4hep::PlacedVolume;
+using dd4hep::Position;
+using dd4hep::Readout;
+using dd4hep::Ref_t;
+using dd4hep::RotationX;
+using dd4hep::RotationY;
+using dd4hep::RotationZ;
+using dd4hep::RotationZYX;
+using dd4hep::Segmentation;
+using dd4hep::SensitiveDetector;
+using dd4hep::Transform3D;
+using dd4hep::Translation3D;
+using dd4hep::Volume;
+using dd4hep::_toString;
+
+using dd4hep::rec::LayeredCalorimeterData;
+
+static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
+  xml_det_t   x_det     = element;
+  Layering    layering(x_det);
+//   xml_dim_t   dim         = x_det.dimensions();
+  string      det_name    = x_det.nameStr();
+
+//   Material    air         = theDetector.air();
+  Material    stavesMaterial    = theDetector.material(x_det.materialStr());
+//   int         numSides    = dim.numsides();
+
+  int           det_id    = x_det.id();
+
+  DetElement   sdet(det_name,det_id);
+
+  PlacedVolume pVol;
+
+  // --- create an envelope volume and position it into the world ---------------------
+
+  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
+  
+//   sdet.setTypeFlag( DetType::CALORIMETER |  DetType::ENDCAP  | DetType::HADRONIC ) ;
+
+//   if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
+  //-----------------------------------------------------------------------------------
+  
+  sens.setType("calorimeter");
+  DetElement    stave_det("module0stave0part0",det_id);
+
+  double      EcalEndcap_inner_radius          = theDetector.constant<double>("Ecal_endcap_inner_radius");
+  double      EcalEndcap_outer_radius          = theDetector.constant<double>("Ecal_endcap_outer_radius");
+  double      EcalEndcap_min_z                 = theDetector.constant<double>("Ecal_endcap_zmin");
+  double      EcalEndcap_max_z                 = theDetector.constant<double>("Ecal_endcap_zmax");
+
+  double      EcalEndcap_deadarea_thickness    = theDetector.constant<double>("Ecal_deadarea_thickness");
+  
+
+  std::cout << "module_type: " << std::endl;
+
+  int endcapID = 0;
+
+  double dim_x = 0.001;
+  double dim_x1 = 0.001;
+  double dim_x2 = 0.001;
+  double dim_y = 0.001;
+  double dim_y1 = 0.001;
+  double dim_y2 = 0.001;
+  double dim_z = 0.001;
+  double box_half_x= 0.001;
+  double box_half_y= 0.001;
+  double box_half_z= 0.001;
+  double trap_half_x1= 0.001;
+  double trap_half_x2= 0.001;
+  double trap_half_y1= 0.001;
+  double trap_half_y2= 0.001;
+  double trap_half_z= 0.001;
+  
+  double pos_x = 0;
+  double pos_y = 0;
+  double pos_z = 0;
+  double EndcapModule_center_pos_x = 0;
+  double EndcapModule_center_pos_y = 0;
+  double EndcapModule_center_pos_z = 0;
+
+  
+  int all_module = 0;
+  for(xml_coll_t c(x_det.child(_U(dimensions)),_U(dimensions)); c; ++c) {
+    xml_comp_t l(c);
+    int N_bar = 0;
+    double volume_bar = 0;
+
+    int module_type = l.attr<int>(_Unicode(module_type));
+    int module_tag = l.attr<int>(_Unicode(id)) - 1;
+    int module_number = l.attr<int>(_Unicode(module_number));
+    
+    if(module_type == 0){
+      dim_x = l.attr<double>(_Unicode(dim_x));
+      dim_y = l.attr<double>(_Unicode(dim_y));
+      dim_z = l.attr<double>(_Unicode(dim_z));
+      pos_x = l.attr<double>(_Unicode(x_offset));
+      pos_y = l.attr<double>(_Unicode(y_offset));
+      pos_z = l.attr<double>(_Unicode(z_offset));
+      box_half_x = dim_x/2.0; 
+      box_half_y = dim_y/2.0; 
+      box_half_z = dim_z/2.0; 
+    }
+    else if(module_type == 1 || module_type == 4){
+      dim_x1 = l.attr<double>(_Unicode(dim_x1));
+      dim_x2 = l.attr<double>(_Unicode(dim_x2));
+      dim_y1 = l.attr<double>(_Unicode(dim_y1));
+      dim_y2 = l.attr<double>(_Unicode(dim_y2));
+      dim_z = l.attr<double>(_Unicode(dim_z));
+      pos_x = l.attr<double>(_Unicode(x_offset));
+      pos_y = l.attr<double>(_Unicode(y_offset));
+      pos_z = l.attr<double>(_Unicode(z_offset));
+      trap_half_x1 = dim_x1/2;
+      trap_half_x2 = dim_x2/2;
+      trap_half_y1 = dim_y1/2;
+      trap_half_y2 = dim_y2/2;
+      trap_half_z = dim_z/2; 
+    }
+    else if(module_type == 2 || module_type == 5){
+      dim_x1 = l.attr<double>(_Unicode(dim_x1));
+      dim_x2 = l.attr<double>(_Unicode(dim_x2));
+      dim_x = l.attr<double>(_Unicode(dim_y1));
+      dim_y = l.attr<double>(_Unicode(dim_y1));
+      dim_y1 = l.attr<double>(_Unicode(dim_y1));
+      dim_y2 = l.attr<double>(_Unicode(dim_y2));
+      dim_z = l.attr<double>(_Unicode(dim_z));
+      pos_x = l.attr<double>(_Unicode(x_offset));
+      pos_y = l.attr<double>(_Unicode(y_offset));
+      pos_z = l.attr<double>(_Unicode(z_offset));
+      trap_half_x1 = dim_x1;
+      trap_half_x2 = dim_x2;
+      trap_half_y1 = dim_y1;
+      trap_half_y2 = dim_y2;
+      trap_half_z = dim_z;
+    }
+    else {
+      dim_x = l.attr<double>(_Unicode(dim_x));
+      dim_y = l.attr<double>(_Unicode(dim_y));
+      dim_z = l.attr<double>(_Unicode(dim_z));
+      pos_x = l.attr<double>(_Unicode(x_offset));
+      pos_y = l.attr<double>(_Unicode(y_offset));
+      pos_z = l.attr<double>(_Unicode(z_offset));
+    }
+
+
+    std::cout << "module_type: " << module_type << std::endl;
+    std::cout << "module_number: " << module_number << std::endl;
+    std::cout << "dim_x: " << dim_x << std::endl;
+    std::cout << "dim_x1: " << dim_x1 << std::endl;
+    std::cout << "dim_x2: " << dim_x2 << std::endl;
+    std::cout << "dim_y: " << dim_y << std::endl;
+    std::cout << "dim_y1: " << dim_y1 << std::endl;
+    std::cout << "dim_y2: " << dim_y2 << std::endl;
+    std::cout << "dim_z: " << dim_z << std::endl;
+    std::cout << "pos_x: " << pos_x << std::endl;
+    std::cout << "pos_y: " << pos_y << std::endl;
+    std::cout << "pos_z: " << pos_z << std::endl;
+
+
+    Box EndcapModule(box_half_x,box_half_y,box_half_z);
+    Trapezoid EndcapTrapIso(trap_half_x1, trap_half_x2, trap_half_y1, trap_half_y2, trap_half_z);
+    Trap EndcapTrapRight(trap_half_y1, trap_half_z, trap_half_x1, trap_half_x2);
+    double vertices[] = {-dim_x, -dim_x, -dim_x, dim_y, dim_y, dim_y, dim_y, -dim_x, -dim_x, -dim_x, -dim_x, dim_x, dim_x, dim_x, dim_x, -dim_x};
+    EightPointSolid EndcapPrism(dim_z/2,  vertices);
+
+    string envelopeVol_name   = det_name+_toString(endcapID,"_EndcapModule%d");
+    string envelopeVolTrapIso_name   = det_name+_toString(endcapID,"_EndcapModule%d");
+    string envelopeVolTrapRight_name   = det_name+_toString(endcapID,"_EndcapModule%d");
+    string envelopeVolPrism_name   = det_name+_toString(endcapID,"_EndcapModule%d");
+
+    Volume envelopeVol(envelopeVol_name,EndcapModule,stavesMaterial);
+    Volume envelopeVolTrapIso(envelopeVolTrapIso_name,EndcapTrapIso,stavesMaterial);
+    Volume envelopeVolTrapRight(envelopeVolTrapRight_name,EndcapTrapRight,stavesMaterial);
+    Volume envelopeVolPrism(envelopeVolPrism_name,EndcapPrism,stavesMaterial);
+
+    envelopeVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+    envelopeVolTrapIso.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+    envelopeVolTrapRight.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+    envelopeVolPrism.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+    
+    double layer_pos_z = -dim_z/2;
+    int layer_num = 1;
+    
+    for(xml_coll_t m(x_det,_U(layer)); m; ++m){ 
+      xml_comp_t x_layer = m;
+	    int repeat = x_layer.repeat();
+      double layer_thickness = x_layer.thickness();
+      string layer_name = (module_type == 0) ? envelopeVol_name+_toString(0,"_Layer%d") : (module_type == 1 || module_type == 4) ? envelopeVolTrapIso_name+_toString(1,"_Layer%d") : (module_type == 2 || module_type == 5) ? envelopeVolTrapRight_name+_toString(2,"_Layer%d") : envelopeVolPrism_name+_toString(3,"_Layer%d");
+      DetElement  layer(stave_det, layer_name, det_id);
+      Material layer_material  = theDetector.material(x_layer.materialStr());
+      
+      if(module_type == 0){ // for cube first place bar then place layer
+        double rot_layer = 0;
+        double active_layer_dim_x = box_half_x - EcalEndcap_deadarea_thickness;
+        double active_layer_dim_y = box_half_y - EcalEndcap_deadarea_thickness;
+        double active_layer_dim_z = layer_thickness/2.0;
+        
+        Volume layer_vol(layer_name, Box(active_layer_dim_x, active_layer_dim_y, active_layer_dim_z), layer_material);
+
+        
+        for (int ihardware = 0; ihardware < int(active_layer_dim_y*2/layer_thickness); ihardware++){
+          
+          string   hardware_name      = layer_name + _toString(ihardware,"_hardware%d");
+          Material hardware_material  = layer_material;
+          DetElement hardware(layer, _toString(ihardware,"hardware%d"), det_id);
+          Volume hardware_vol(hardware_name,Box(active_layer_dim_x, layer_thickness / 2.0, layer_thickness/2.0), hardware_material);
+          hardware_vol.setSensitiveDetector(sens);
+          hardware_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
+          PlacedVolume hardware_phv = layer_vol.placeVolume(hardware_vol,Position(0, -active_layer_dim_y + layer_thickness/2 + layer_thickness*ihardware, 0));
+          hardware_phv.addPhysVolID("bar",ihardware);
+          hardware.setPlacement(hardware_phv);
+          
+        }
+
+        layer_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
+        
+        layer_pos_z += layer_thickness / 2.0;
+        
+        for (int j = 0; j < repeat; j++){
+          
+          rot_layer = (j%2==0)? M_PI/2 : 0;
+
+          PlacedVolume layer_phv = envelopeVol.placeVolume(layer_vol, Transform3D(RotationZYX(rot_layer, 0, 0), Position(0,0,layer_pos_z)));
+          if(j%2==0) layer_phv.addPhysVolID("slayer", 0).addPhysVolID("dlayer", layer_num);
+          else{
+            layer_phv.addPhysVolID("slayer", 1).addPhysVolID("dlayer", layer_num);
+            ++layer_num;
+          }
+
+          layer.setPlacement(layer_phv); 
+          layer_pos_z += layer_thickness; 
+        }
+
+        N_bar = N_bar + int(active_layer_dim_y*2/layer_thickness)*repeat;
+        volume_bar = volume_bar + active_layer_dim_x*2*2*active_layer_dim_y*layer_thickness*repeat;
+      }
+      else{ //for trap first place layer then place bar
+        layer_pos_z += layer_thickness / 2.0;
+        double rot_layer = 0;
+        double delta_layer = 0;
+        for (int j = 0; j < repeat; j++){
+          
+          delta_layer = (module_type == 1 || module_type == 4) ? layer_thickness*(trap_half_x1 - trap_half_x2)/dim_z : (module_type == 2 || module_type == 5) ? layer_thickness*(dim_x2 - dim_x1)/dim_z : layer_thickness*(dim_x-dim_y)/dim_z;
+
+          double active_layer_dim_x = (module_type == 1  || module_type == 4) ? trap_half_y1 - EcalEndcap_deadarea_thickness : (module_type == 2 || module_type == 5) ? trap_half_x1/2 - EcalEndcap_deadarea_thickness + j*delta_layer/2 : (dim_x+dim_y)/2 - EcalEndcap_deadarea_thickness + j*delta_layer/2; 
+          double active_layer_dim_y = (module_type == 1  || module_type == 4) ? trap_half_x1 - EcalEndcap_deadarea_thickness - j*delta_layer : (module_type == 2 || module_type == 5) ? layer_thickness/2.0 : (dim_x+dim_y)/2 - EcalEndcap_deadarea_thickness + j*delta_layer/2; 
+          double active_layer_dim_z = (module_type == 1  || module_type == 4) ? layer_thickness/2.0 : (module_type == 2 || module_type == 5) ? trap_half_y1/2 - EcalEndcap_deadarea_thickness : layer_thickness/2.0;
+          
+          Volume layer_vol(layer_name, Box(active_layer_dim_x, active_layer_dim_y, active_layer_dim_z), layer_material);
+          int hardware_num = 0;
+          
+          if(module_type== 1){
+            hardware_num = (j%2==0) ? int(active_layer_dim_x*2/layer_thickness) : int(active_layer_dim_y*2/layer_thickness);
+          }
+          else if(module_type== 2){
+            hardware_num = (j%2==0) ? int(active_layer_dim_z*2/layer_thickness) : int(active_layer_dim_x*2/layer_thickness);
+          }
+          else if(module_type== 4){
+            hardware_num = (j%2==0) ? int(active_layer_dim_y*2/layer_thickness) : int(active_layer_dim_x*2/layer_thickness);
+          }
+          else if(module_type== 5){
+            hardware_num = (j%2==0) ? int(active_layer_dim_x*2/layer_thickness) : int(active_layer_dim_z*2/layer_thickness);
+          }
+          else {
+            hardware_num = (j%2==0) ? int(active_layer_dim_x*2/layer_thickness) : int(active_layer_dim_y*2/layer_thickness);
+          }
+
+          double hardware_x = 0;
+          double hardware_y = 0;
+          double hardware_z = 0;
+          double hardware_x_pos = 0;
+          double hardware_y_pos = 0;
+          double hardware_z_pos = 0;
+
+          for (int ihardware = 0; ihardware < hardware_num; ihardware++){
+            string   hardware_name      = layer_name + _toString(ihardware,"_hardware%d");
+            Material hardware_material  = layer_material;
+            DetElement hardware(layer, _toString(j,"layer%d") + _toString(ihardware,"hardware%d"), det_id);
+            if(module_type== 1){
+              hardware_x = (j%2==0) ? layer_thickness / 2.0 : active_layer_dim_x;
+              hardware_y = (j%2==0) ? active_layer_dim_y : layer_thickness / 2.0;
+              hardware_z = layer_thickness/2.0;
+            }
+            else if(module_type== 2){
+              hardware_x = (j%2==0) ? active_layer_dim_x : layer_thickness / 2.0;
+              hardware_y = layer_thickness / 2.0;
+              hardware_z = (j%2==0) ? layer_thickness / 2.0 : active_layer_dim_z;
+            }
+            else if(module_type== 3 || module_type== 7){
+              hardware_x = (j%2==1) ? layer_thickness / 2.0 : active_layer_dim_x;
+              hardware_y = (j%2==1) ? active_layer_dim_y : layer_thickness / 2.0;
+              hardware_z = layer_thickness / 2.0;
+            }
+            else if(module_type== 4){
+              hardware_x = (j%2==0) ? active_layer_dim_x : layer_thickness / 2.0;
+              hardware_y = (j%2==0) ? layer_thickness / 2.0 : active_layer_dim_y;
+              hardware_z = layer_thickness/2.0;
+            }
+            else if(module_type== 5){
+              hardware_x = (j%2==0) ? layer_thickness / 2.0 : active_layer_dim_x;
+              hardware_y = layer_thickness / 2.0;
+              hardware_z = (j%2==0) ? active_layer_dim_z : layer_thickness / 2.0;
+            }
+            else if(module_type== 6 || module_type== 8){
+              hardware_x = (j%2==1) ? active_layer_dim_x : layer_thickness / 2.0;
+              hardware_y = (j%2==1) ? layer_thickness / 2.0 : active_layer_dim_y;
+              hardware_z = layer_thickness / 2.0;
+            }
+            Volume hardware_vol(hardware_name,Box(hardware_x, hardware_y, hardware_z), hardware_material);
+            hardware_vol.setSensitiveDetector(sens);
+            hardware_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
+
+            volume_bar = volume_bar + hardware_x*2*2*hardware_y*hardware_z*2;
+
+            if(module_type== 1){
+              hardware_x_pos = (j%2==0) ? -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware : 0;
+              hardware_y_pos = (j%2==0) ? 0 : -active_layer_dim_y + layer_thickness/2 + layer_thickness*ihardware;
+              hardware_z_pos = 0;
+            }
+            else if(module_type== 2){
+              hardware_x_pos = (j%2==0) ? 0 : -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware;
+              hardware_y_pos = 0;
+              hardware_z_pos = (j%2==0) ? -active_layer_dim_z + layer_thickness/2 + layer_thickness*ihardware : 0;
+            }
+            else if(module_type== 3 || module_type== 7){
+              hardware_x_pos = (j%2==1) ? -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware : 0;
+              hardware_y_pos = (j%2==1) ? 0 : -active_layer_dim_y + layer_thickness/2 + layer_thickness*ihardware;
+              hardware_z_pos = 0;
+            }
+            else if(module_type== 4){
+              hardware_x_pos = (j%2==0) ? 0 : -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware;
+              hardware_y_pos = (j%2==0) ? -active_layer_dim_y + layer_thickness/2 + layer_thickness*ihardware: 0 ;
+              hardware_z_pos = 0;
+            }
+            else if(module_type== 5){
+              hardware_x_pos = (j%2==0) ? -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware : 0;
+              hardware_y_pos = 0;
+              hardware_z_pos = (j%2==0) ? 0 : -active_layer_dim_z + layer_thickness/2 + layer_thickness*ihardware;
+            }
+            else if(module_type== 6 || module_type== 8){
+              hardware_x_pos = (j%2==1) ? 0 : -active_layer_dim_x + layer_thickness/2 + layer_thickness*ihardware;
+              hardware_y_pos = (j%2==1) ? -active_layer_dim_y + layer_thickness/2 + layer_thickness*ihardware: 0 ;
+              hardware_z_pos = 0;
+            }
+            PlacedVolume hardware_phv = layer_vol.placeVolume(hardware_vol,Position(hardware_x_pos, hardware_y_pos, hardware_z_pos));
+            hardware_phv.addPhysVolID("bar", ihardware);
+            hardware.setPlacement(hardware_phv);
+          }
+
+          layer_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
+          rot_layer = M_PI/2;
+          PlacedVolume layer_phv;
+          layer_phv = (module_type == 1 || module_type == 4) ? envelopeVolTrapIso.placeVolume(layer_vol, Transform3D(RotationZYX(rot_layer, 0, 0), Position(0,0,layer_pos_z))) : (module_type == 2 || module_type == 5) ? envelopeVolTrapRight.placeVolume(layer_vol, Transform3D(RotationZYX( 0, 0, 0), Position( -(dim_x2 - dim_x1)/2  + j*delta_layer/2 + EcalEndcap_deadarea_thickness, layer_pos_z, 0))) : envelopeVolPrism.placeVolume(layer_vol, Position(-dim_x + active_layer_dim_x + EcalEndcap_deadarea_thickness, -dim_x + active_layer_dim_y + EcalEndcap_deadarea_thickness, layer_pos_z));
+          if(j%2==0) layer_phv.addPhysVolID("slayer", 0).addPhysVolID("dlayer", layer_num);
+          else{
+            layer_phv.addPhysVolID("slayer", 1).addPhysVolID("dlayer", layer_num);
+            ++layer_num;
+          }
+          layer.setPlacement(layer_phv); 
+          layer_pos_z += layer_thickness;
+        
+          N_bar = N_bar + hardware_num;
+        }
+      }  
+    }
+
+    std::cout << "N_bar: " << N_bar << std::endl;
+    std::cout << "volume_bar: " << volume_bar << std::endl;
+
+    int sector_sum = 0;
+    if(module_type==1  || module_type==4) sector_sum = module_number;
+    else if(module_type==3  || module_type==6 || module_type==7  || module_type==8) sector_sum = module_number;
+    else sector_sum = module_number*2 + 1;
+
+    for (int sector_num=0;sector_num<sector_sum;sector_num++){
+      if(module_type==2 && sector_num<module_number) continue;
+      if(module_type==5 && sector_num>module_number) continue;
+
+      double EndcapModule_pos_x = 0;
+      double EndcapModule_pos_y = 0;
+      double EndcapModule_pos_z = pos_z;
+      double rot_EM = 0;
+      double rot_ES = 0;
+      double rot_EZ = 0;
+      double rot_EY = 0;
+      double rot_EX = 0;
+
+      if(module_type==0 ){
+        if(sector_num<module_number){
+          EndcapModule_pos_x = pos_x;
+          EndcapModule_pos_y = pos_y + (module_number-sector_num)*dim_y;
+        }
+        else if(sector_num==module_number){
+          EndcapModule_pos_x = pos_x;
+          EndcapModule_pos_y = pos_y;
+        }
+        else{
+          EndcapModule_pos_x = pos_x + (sector_num-module_number)*dim_x;
+          EndcapModule_pos_y = pos_y;
+        }
+      }
+      else if(module_type==1  || module_type==4){
+        EndcapModule_pos_x = pos_x + sector_num*dim_y2;
+        EndcapModule_pos_y = pos_y;
+      }
+      else if(module_type==2 || module_type==5){
+        if(sector_num<module_number){
+          EndcapModule_pos_x = pos_y;
+          EndcapModule_pos_y = pos_x + (module_number-sector_num)*dim_y;
+        }
+        else if(sector_num==module_number){
+          EndcapModule_pos_x = pos_x;
+          EndcapModule_pos_y = pos_y;
+        }
+        else{
+          EndcapModule_pos_x = pos_x + (sector_num-module_number)*dim_x;
+          EndcapModule_pos_y = pos_y;
+        }
+      }
+      else{
+        EndcapModule_pos_x = pos_x;
+        EndcapModule_pos_y = pos_y;
+      }
+
+      
+      for(int stave_num=0;stave_num<4;stave_num++){
+        if(module_type==1 && (stave_num==1 || stave_num==3)) continue;
+        if(module_type==4 && (stave_num==0 || stave_num==2)) continue;
+        if((module_type==3 || module_type==8) && (stave_num==1 || stave_num==3)) continue;
+        if((module_type==6 || module_type==7) && (stave_num==0 || stave_num==2)) continue;
+
+        // Set the ID. The ID is composed of the module number, the stave number, the part number.
+        int stave_id = 0;
+        int part_id = 0;
+        if(module_type == 0){
+          if(stave_num==0 && sector_num<=module_number) { stave_id = 7 + module_tag;  part_id = sector_num; }
+          if(stave_num==0 && sector_num>module_number)  { stave_id = sector_num + 4 + 2*module_tag;  part_id = 3 - module_tag; }
+          if(stave_num==1 && sector_num<=module_number) { stave_id = 3 - module_tag;  part_id = sector_num; }
+          if(stave_num==1 && sector_num>module_number)  { stave_id = 6 - 2*module_tag - sector_num;  part_id = 3 - module_tag; }
+          if(stave_num==2 && sector_num<=module_number) { stave_id = 3 - module_tag;  part_id = 10 - sector_num; }
+          if(stave_num==2 && sector_num>module_number)  { stave_id = 6 - 2*module_tag - sector_num;  part_id = 7 + module_tag; }
+          if(stave_num==3 && sector_num<=module_number) { stave_id = 7 + module_tag;  part_id = 10 - sector_num; }
+          if(stave_num==3 && sector_num>module_number)  { stave_id = sector_num + 4 + 2*module_tag;  part_id = 7 + module_tag; }
+        }
+        else if(module_type == 1 || module_type == 4) {
+          if(stave_num==0) { stave_id = 7 + sector_num;  part_id = 5; }
+          if(stave_num==1) { stave_id = 5;  part_id = 3 - sector_num; }
+          if(stave_num==2) { stave_id = 3 - sector_num;  part_id = 5; }
+          if(stave_num==3) { stave_id = 5;  part_id = 7 + sector_num; }
+        }
+        else if(module_type == 2){
+          if(stave_num==0) { stave_id = 2 + sector_num;  part_id = 4; }
+          if(stave_num==1) { stave_id = 8 - sector_num;  part_id = 4; }
+          if(stave_num==2) { stave_id = 8 - sector_num;  part_id = 6; }
+          if(stave_num==3) { stave_id = 2 + sector_num;  part_id = 6; }
+        }
+        else if(module_type == 5){
+          if(stave_num==0) { stave_id = 6;  part_id = sector_num; }
+          if(stave_num==1) { stave_id = 4;  part_id = sector_num; }
+          if(stave_num==2) { stave_id = 4;  part_id = 10 - sector_num; }
+          if(stave_num==3) { stave_id = 6;  part_id = 10 - sector_num; }
+        }
+        else {
+          if(stave_num==0) { stave_id = 6;  part_id = 4; }
+          if(stave_num==1) { stave_id = 4;  part_id = 4; }
+          if(stave_num==2) { stave_id = 4;  part_id = 6; }
+          if(stave_num==3) { stave_id = 6;  part_id = 6; }
+        }
+
+        
+
+
+
+        double rot_FZ = 0;
+        double rot_FY = 0;
+        double rot_FX = 0;
+
+        if(module_type==0){
+          EndcapModule_center_pos_x = (stave_num == 0) ? EndcapModule_pos_x : (stave_num == 1) ? -EndcapModule_pos_x : (stave_num == 2) ? -EndcapModule_pos_x : EndcapModule_pos_x;
+          EndcapModule_center_pos_y = (stave_num == 0) ? EndcapModule_pos_y : (stave_num == 1) ? EndcapModule_pos_y : (stave_num == 2) ? -EndcapModule_pos_y : -EndcapModule_pos_y;
+        }
+        else if(module_type==1  || module_type==4){
+          EndcapModule_center_pos_x = (stave_num == 0) ? EndcapModule_pos_x : (stave_num == 1) ? EndcapModule_pos_y : (stave_num == 2) ? -EndcapModule_pos_x : EndcapModule_pos_y;
+          EndcapModule_center_pos_y = (stave_num == 0) ? EndcapModule_pos_y : (stave_num == 1) ? EndcapModule_pos_x : (stave_num == 2) ? -EndcapModule_pos_y : -EndcapModule_pos_x;
+        }
+        else{
+          EndcapModule_center_pos_x = (stave_num == 0) ? EndcapModule_pos_x : (stave_num == 1) ? -EndcapModule_pos_x : (stave_num == 2) ? -EndcapModule_pos_x : EndcapModule_pos_x;
+          EndcapModule_center_pos_y = (stave_num == 0) ? EndcapModule_pos_y : (stave_num == 1) ? EndcapModule_pos_y : (stave_num == 2) ? -EndcapModule_pos_y : -EndcapModule_pos_y;
+        }
+
+        rot_ES = (stave_num == 0) ? M_PI/2 : (stave_num == 1) ? 0 : (stave_num == 2) ? M_PI/2 : 0;
+        if(sector_num<=module_number) rot_EX = (stave_num == 0) ? M_PI : (stave_num == 1) ? 0 : (stave_num == 2) ? 0 : M_PI;
+        else rot_EX = (stave_num == 0) ? M_PI+M_PI/2 : (stave_num == 1) ? 0-M_PI/2 : (stave_num == 2) ? 0+M_PI/2 : M_PI-M_PI/2;
+        rot_EZ = (stave_num == 0) ? 0 : (stave_num == 1) ? 0 : (stave_num == 2) ? 0 : 0;
+        
+
+        for(int module_num=0;module_num<2;module_num++) {
+          if(module_num==0 && (module_type==7 || module_type==8)) continue;
+          if(module_num==1 && (module_type==3 || module_type==6)) continue;
+
+          int module_id = (module_num==0)? 0:1;
+          
+          if(module_type==2 || module_type==5){
+            if(sector_num<=module_number) rot_EM = (module_id==0)?M_PI*3/2: M_PI/2;
+            else rot_EM = (module_id==0)?M_PI*3/2: M_PI/2;
+            if(sector_num>module_number) rot_EY = (module_id==0)? rot_EX+M_PI : rot_EX;
+            else rot_EY = rot_EX;
+          } 
+          else rot_EM = (module_id==0)?M_PI:0;
+          
+          EndcapModule_center_pos_z = (module_id==0)? -EndcapModule_pos_z:EndcapModule_pos_z;
+          
+          PlacedVolume env_phv;
+          if(module_type==0){
+            env_phv = envelope.placeVolume(envelopeVol,
+                        Transform3D(RotationX(rot_EM),
+                        Translation3D(EndcapModule_center_pos_x,
+                          EndcapModule_center_pos_y,
+                          EndcapModule_center_pos_z)));
+            env_phv.addPhysVolID("module", module_id).addPhysVolID("type", module_tag).addPhysVolID("part", part_id).addPhysVolID("stave", stave_id);
+            all_module++;
+          }
+          else if(module_type==1  || module_type==4){
+            env_phv = envelope.placeVolume(envelopeVolTrapIso,
+                        Transform3D(RotationZYX(rot_ES, 0, rot_EM),
+                        Position(EndcapModule_center_pos_x,
+                          EndcapModule_center_pos_y,
+                          EndcapModule_center_pos_z)));
+            env_phv.addPhysVolID("module", module_id).addPhysVolID("type", module_tag).addPhysVolID("part", part_id).addPhysVolID("stave", stave_id);
+            all_module++;
+          }
+          else if(module_type==2 || module_type==5){
+            if(sector_num==module_number){
+              continue;
+            }
+            else{
+              env_phv = envelope.placeVolume(envelopeVolTrapRight,
+                        Transform3D(RotationZYX(rot_EZ, rot_EY, rot_EM),
+                        Position(EndcapModule_center_pos_x,
+                          EndcapModule_center_pos_y,
+                          EndcapModule_center_pos_z)));
+              env_phv.addPhysVolID("module", module_id).addPhysVolID("type", module_tag).addPhysVolID("part", part_id).addPhysVolID("stave", stave_id);
+              all_module++;
+            }
+          }
+          else{
+            if(module_id==0){
+              rot_FZ = (stave_num == 0) ? M_PI/2 : (stave_num == 1) ? 0: (stave_num == 2) ? -M_PI/2 : M_PI;  
+            } 
+            else{
+              rot_FZ = (stave_num == 0) ? M_PI : (stave_num == 1) ? -M_PI/2 : (stave_num == 2) ? 0 : M_PI/2;
+            }
+            rot_FY = (stave_num == 0) ? 0 : (stave_num == 1) ? 0 : (stave_num == 2) ? 0 : 0;
+            rot_FX = (module_id==0)?M_PI:0;
+            
+            env_phv = envelope.placeVolume(envelopeVolPrism,
+                        Transform3D(RotationZYX(rot_FZ, rot_FY, rot_FX),
+                        Position(EndcapModule_center_pos_x,
+                          EndcapModule_center_pos_y,
+                          EndcapModule_center_pos_z)));
+            env_phv.addPhysVolID("module", module_id).addPhysVolID("type", module_tag).addPhysVolID("part", part_id).addPhysVolID("stave", stave_id);
+            all_module++;
+          }
+          
+          DetElement sd = (module_id==0&&part_id==0&&stave_id==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d")+_toString(part_id,"part%d"));	  
+	        sd.setPlacement(env_phv);
+        }
+      }
+    }
+    endcapID++;
+  }
+  cout<<"EndcapModule: "<<all_module<<endl;
+  return sdet;
+}
+
+DECLARE_DETELEMENT(LongCrystalBarEndcapCalorimeter_v02, create_detector)
\ No newline at end of file
diff --git a/Digitization/DigiCalo/CMakeLists.txt b/Digitization/DigiCalo/CMakeLists.txt
index c3b4182c..79f1d1d9 100644
--- a/Digitization/DigiCalo/CMakeLists.txt
+++ b/Digitization/DigiCalo/CMakeLists.txt
@@ -1,6 +1,7 @@
 # Modules
 gaudi_add_module(CaloDigi
                  SOURCES src/EcalDigiAlg.cpp
+                 SOURCES src/EcalDigiAlgShort.cpp
                  SOURCES src/HcalDigiAlg.cpp
                  LINK k4FWCore::k4FWCore
                       GearSvc
diff --git a/Digitization/DigiCalo/src/CaloBar.h b/Digitization/DigiCalo/src/CaloBar.h
index 57d226bb..cff95a9d 100644
--- a/Digitization/DigiCalo/src/CaloBar.h
+++ b/Digitization/DigiCalo/src/CaloBar.h
@@ -18,9 +18,11 @@ public:
   int getSystem() const { return system; }
   int getModule() const { return module; }
   int getStave()  const { return stave;  }
+  int getPart()   const { return part;   }
   int getDlayer() const { return dlayer; }
   int getSlayer() const { return slayer; }
   int getBar()    const { return bar;    }
+  double getLength() const { return length; }
   double getQ1()  const { return Q1;     }
   double getQ2()  const { return Q2;     }
   double getT1()  const { return T1;     }
@@ -30,19 +32,22 @@ public:
   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 setcellID(int _system, int _module, int _stave, int _part, int _dlayer, int _slayer, int _bar) { system=_system; module=_module; stave=_stave; part=_part; 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; }
+  void setLength(double _length) { length = _length; }
 
 private:
 	unsigned long long cellID;
 	int system;
 	int module;
 	int stave;
+  int part;
 	int dlayer;
 	int slayer;
 	int bar;
+  double length;
 	TVector3 position;
 	double Q1;      // Q in left readout
 	double Q2;      // Q in right readout;
diff --git a/Digitization/DigiCalo/src/CaloCrystalShort.h b/Digitization/DigiCalo/src/CaloCrystalShort.h
new file mode 100644
index 00000000..2ed3da2c
--- /dev/null
+++ b/Digitization/DigiCalo/src/CaloCrystalShort.h
@@ -0,0 +1,89 @@
+#ifndef _CRD_CALOCRYSTALSHORT_
+#define _CRD_CALOCRYSTALSHORT_
+
+#include <DD4hep/Objects.h>
+#include "TVector3.h"
+
+class CaloCrystalShort
+{
+public:
+    CaloCrystalShort(unsigned long long _cellID, int _system, int _module, int _stave, int _layer, int _phi_x, int _z_y, TVector3 _pos, double _Q, double _T)
+            : cellID(_cellID), system(_system), module(_module), stave(_stave), layer(_layer), phi_x(_phi_x), z_y(_z_y), position(_pos), Q(_Q), T(_T) {};
+    /*
+    CaloCrystalShort(unsigned long long _cellID, int _system, int _module, int _stave, int _layer, int _x, int _y, TVector3 _pos, double _Q, double _T)
+            : cellID(_cellID), system(_system), module(_module), stave(_stave), layer(_layer), x(_x), y(_y), position(_pos), Q(_Q), T(_T) {};
+    */
+
+    CaloCrystalShort() {};
+
+    inline bool operator==(const CaloCrystalShort& 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 getPhiX() const { return phi_x; }
+
+    int getZY() const { return z_y; }
+
+    double getQ() const { return Q; }
+
+    double getT() const { return T; }
+
+    TVector3 getPosition() const { return position; }
+
+    double getEnergy() const { return Q; }
+
+    void setcellID(unsigned long long _cellid) { cellID = _cellid; }
+
+    void setcellID(int _system, int _module, int _stave, int _layer, int _phi_x, int _z_y)
+    {
+        system = _system;
+        module = _module;
+        stave = _stave;
+        layer = _layer;
+        phi_x = _phi_x;
+        z_y = _z_y;
+    }
+
+    /*
+    void setcellID(int _system, int _module, int _stave, int _layer, int _x, int _y)
+    {
+        system = _system;
+        module = _module;
+        stave = _stave;
+        layer = _layer;
+        x = _x;
+        y = _y;
+    }
+     */
+
+    void setPosition(TVector3 posv3) { position.SetXYZ(posv3.x(), posv3.y(), posv3.z()); }
+
+    void setQ(double _q) { Q = _q; }
+
+    void setT(double _t) { T = _t; }
+
+private:
+    unsigned long long cellID;
+    int system;
+    int module;
+    int stave;
+    int layer;
+    int phi_x;
+    int z_y;
+    TVector3 position;
+    double Q;    // Charge in readout
+    double T;    // Time in readout;
+};
+
+#endif
diff --git a/Digitization/DigiCalo/src/EcalDigiAlg.cpp b/Digitization/DigiCalo/src/EcalDigiAlg.cpp
index 504a8288..f901df32 100644
--- a/Digitization/DigiCalo/src/EcalDigiAlg.cpp
+++ b/Digitization/DigiCalo/src/EcalDigiAlg.cpp
@@ -40,17 +40,59 @@ EcalDigiAlg::EcalDigiAlg(const std::string& name, ISvcLocator* svcLoc)
 {
   
 	// Input collections
-	declareProperty("SimCaloHitCollection", r_SimCaloCol, "Handle of the Input SimCaloHit collection");
+	//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");
+	//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()
 {
+  // --- Initialize input and output collections
+  for(auto& simhit : name_SimCaloHit){
+    if(!simhit.empty())
+     _inputSimHitCollection.push_back( new SimCaloType(simhit, Gaudi::DataHandle::Reader, this) );
+  }
+  
+  // --- Geometry service, cellID decoder
+  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);
+
+  for(unsigned int i=0; i<name_Readout.size(); i++){
+    if(name_Readout[i].empty()) continue;
+    dd4hep::DDSegmentation::BitFieldCoder* tmp_decoder = m_geosvc->getDecoder(name_Readout[i]);
+    if (!tmp_decoder) {
+      error() << "Failed to get the decoder for: " << name_Readout[i] << endmsg;
+      return StatusCode::FAILURE;
+    }
+    map_readout_decoder[name_SimCaloHit[i]] = tmp_decoder;
+  }
+  
+  m_volumeManager = m_dd4hep->volumeManager();
+
+  // --- Output collection
+  for(auto& digihit : name_CaloHit){
+    if(!digihit.empty())
+      _outputHitCollection.push_back( new CaloType(digihit, Gaudi::DataHandle::Writer, this) );
+  }
+
+  for(auto& link : name_CaloAsso){
+    if(!link.empty())
+      _outputCaloSimAssoCol.push_back( new CaloSimAssoType(link, Gaudi::DataHandle::Writer, this) );
+  }
+
+  for(auto& link : name_CaloMCPAsso){
+    if(!link.empty())
+      _outputCaloMCPAssoCol.push_back( new CaloParticleAssoType(link, Gaudi::DataHandle::Writer, this) );
+  }
+
+  // --- Ntuple 
 	if(_writeNtuple){
 		std::string s_outfile = _filename;
 		m_wfile = new TFile(s_outfile.c_str(), "recreate");
@@ -68,35 +110,102 @@ StatusCode EcalDigiAlg::initialize()
 		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("mean_CT", &mean_CT);
+		t_SimBar->Branch("ECALTemp", &ECALTemp);
 		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_E_Truth", &m_simBar_E_Truth);
+		t_SimBar->Branch("simBar_ChannelTemp", &m_simBar_ChannelTemp);
+		t_SimBar->Branch("simBar_CryTID", &m_simBar_CryTID);
+		t_SimBar->Branch("simBar_SiPMNIEL", &m_simBar_SiPMNIEL);
+		t_SimBar->Branch("simBar_CryIntLY", &m_simBar_CryIntLY);
+		t_SimBar->Branch("simBar_SiPMGain", &m_simBar_SiPMGain);
+		t_SimBar->Branch("simBar_SiPMDCR", &m_simBar_SiPMDCR);
+		t_SimBar->Branch("simBar_ScinGen", &m_simBar_Scint);
+		t_SimBar->Branch("simBar_LO1", &m_simBar_LO1 );
+		t_SimBar->Branch("simBar_NDC1", &m_simBar_NDC1 );
+		t_SimBar->Branch("simBar_NDetPE1", &m_simBar_NDetPE1 );
+		t_SimBar->Branch("simBar_Pedestal1", &m_simBar_Pedestal1 );
+		t_SimBar->Branch("simBar_ADC1", &m_simBar_ADC1 );
+		t_SimBar->Branch("simBar_ADCGain1", &m_simBar_ADCGain1 );
+		t_SimBar->Branch("simBar_LO2", &m_simBar_LO2 );
+		t_SimBar->Branch("simBar_NDC2", &m_simBar_NDC2 );
+		t_SimBar->Branch("simBar_NDetPE2", &m_simBar_NDetPE2 );
+		t_SimBar->Branch("simBar_Pedestal2", &m_simBar_Pedestal2 );
+		t_SimBar->Branch("simBar_ADC2", &m_simBar_ADC2 );
+		t_SimBar->Branch("simBar_ADCGain2", &m_simBar_ADCGain2 );
+		t_SimBar->Branch("simBar_Q1_Att", &m_simBar_Q1_Att);
+		t_SimBar->Branch("simBar_Q2_Att", &m_simBar_Q2_Att);
 		t_SimBar->Branch("simBar_Q1_Digi", &m_simBar_Q1_Digi);
 		t_SimBar->Branch("simBar_Q2_Digi", &m_simBar_Q2_Digi);
+		t_SimBar->Branch("simBar_length", &m_simBar_length);
+		t_SimBar->Branch("simBar_system", &m_simBar_system);
 		t_SimBar->Branch("simBar_module", &m_simBar_module);
 		t_SimBar->Branch("simBar_stave", &m_simBar_stave);
+		t_SimBar->Branch("simBar_part", &m_simBar_part);
 		t_SimBar->Branch("simBar_dlayer", &m_simBar_dlayer);
 		t_SimBar->Branch("simBar_slayer", &m_simBar_slayer);
+		t_SimBar->Branch("simBar_bar", &m_simBar_bar);
 		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;
+  std::cout<<"Set Random seed: "<<_seed<<endl;
+	rndm.SetSeed(_seed);
+
+	// SiPM response function
+  f_SiPMResponse = new TF1("f_SiPMResponse", "((1-[1])*[0]*(1-exp(-x/[0]))+[1]*x)*([2]+1)/( [2]+x / ([0]*(1-exp(-x/[0]))) )*(1+[3]*exp(-x/[0]))", 0, 1e+9);
+  f_SiPMResponse->SetParameters(6.19783e+06, 5.08847e-01, 1.27705e+01, fEcalSiPMCT);
+  f_SiPMSigmaDet = new TF1("f_SiPMSigmaDet", "8.336e-01*sqrt(x+0.2379)", 0, 1e+9);
+  f_SiPMSigmaRecp = new TF1("f_SiPMSigmaRecp", "f_SiPMResponse+f_SiPMSigmaDet", 0, 1e+9);
+  f_SiPMSigmaRecm = new TF1("f_SiPMSigmaRecm", "f_SiPMResponse-f_SiPMSigmaDet", 0, 1e+9);
+  f_AsymGauss = new TF1("AsymGauss", [](double *x, double *par) -> double 
+  {
+      double val = x[0];
+      double mean = par[0];
+      double sigma_left = par[1];
+      double sigma_right = par[2];
+
+      if (val < mean) {
+          return exp(-0.5 * pow((val - mean) / sigma_left, 2));
+      } else {
+          return exp(-0.5 * pow((val - mean) / sigma_right, 2));
+      }
+  }, -10, 10, 3);
+
+	// SiPM noise model: Borel distribution
+	f_DarkNoise = new TF1("f_DarkNoise", "pow([0]*x, x-1) * exp(-[0]*x) / TMath::Factorial(x)");
+	f_DarkNoise->SetParameter(0, fEcalSiPMCT);
+
+	g_CryLYRatio_vs_TID = new TGraph();
+	float TID [8] = {50, 230.043, 731.681, 3448.96, 118953, 1.01164e+7, 1.02341e+8, 2.04907e+8};
+	float CryLYRatio_TID[8] = {0.99, 0.774091, 0.689545, 0.633636, 0.588636, 0.549091, 0.401818, 0.374545};
+	for (int i = 0; i < 8; i++) {
+		g_CryLYRatio_vs_TID->SetPoint(i, TID[i], CryLYRatio_TID[i]);
+	} 
+
+	g_SiPMDCR_vs_NIEL = new TGraph();
+	float NIEL[24] = { 9.9e+6,
+		1.00000e+7, 2.49756e+7, 5.25408e+7, 1.10530e+8, 2.11374e+8,
+		4.04227e+8, 6.63661e+8, 1.02902e+9, 1.68944e+9, 2.77373e+9,
+		4.38351e+9, 6.41879e+9, 9.22154e+9, 1.40281e+10, 2.01534e+10,
+		3.12481e+10, 4.48925e+10, 7.09466e+10, 1.33114e+11, 1.91238e+11,
+		3.13975e+11, 4.51070e+11, 6.48029e+11
+	};
+	float DCR_NIEL[24] = { 1e+5,
+		105925, 145378, 230409, 354813, 595662,
+		1.09018e+6, 1.72783e+6, 2.58523e+6, 4.21697e+6, 6.68344e+6,
+		1.02920e+7, 1.58489e+7, 2.44062e+7, 3.98107e+7, 5.95662e+7,
+		9.44061e+7, 1.37246e+8, 2.17520e+8, 3.65174e+8, 5.01187e+8,
+		7.28618e+8, 9.44061e+8, 1.18850e+9
+	};
+	for (int i = 0; i < 24; i++) {
+		DCR_NIEL[i] = DCR_NIEL[i] / 1e+5; // unit: MHz/cm^2
+		g_SiPMDCR_vs_NIEL->SetPoint(i, NIEL[i], DCR_NIEL[i]);
 	}
 
-	rndm.SetSeed(_seed);
 	std::cout<<"EcalDigiAlg::initialize"<<std::endl;
 	return GaudiAlgorithm::initialize();
 }
@@ -112,311 +221,434 @@ StatusCode EcalDigiAlg::execute()
 
 	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; 
-    if(fUseDigiScint)
-      ScinGen = std::round(gRandom->Poisson((totQ1_Truth+totQ2_Truth)*1000 / fEcalMIPEnergy * sEcalCryMipLY));
-    else ScinGen = (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);
+  for(int icol=0; icol<_inputSimHitCollection.size(); icol++){
+    try{
+      SimCaloType* r_SimCaloCol = _inputSimHitCollection[icol];
+      CaloType* w_DigiCaloCol = _outputHitCollection[icol];
+      CaloSimAssoType* w_CaloAssociationCol = _outputCaloSimAssoCol[icol];
+      CaloParticleAssoType* w_MCPCaloAssociationCol = _outputCaloMCPAssoCol[icol];
+
+      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;
+      mean_CT = 0;
+      for (int i = 1; i < 10; i++)
+      {
+      	mean_CT += (i-1)*f_DarkNoise->Eval(i);
+      }
+      float sEcalTempRef = rndm.Uniform(fEcalTempRef - fEcalTempFluc, fEcalTempRef + fEcalTempFluc);
+      ECALTemp = sEcalTempRef;
+      
+      //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;
+      
+      //Loop in SimHit, digitalize SimHit to DigiBar
+      for(int i=0;i<m_simhitCol.size();i++)
+      {
+      	auto SimHit = m_simhitCol.at(i);
+      	if(!SimHit.isAvailable()) {cout<<"Sim hit is not available"<<endl; continue;}
+      	if(SimHit.getEnergy()==0) {cout<<"Sim hit energy is 0"<<endl; continue;}
+      
+      	totE_Truth += SimHit.getEnergy();
+      	unsigned long long id = SimHit.getCellID();
+      	CaloBar hitbar;
+      	hitbar.setcellID( id);
+        int id_part = -1; 
+        int id_system = map_readout_decoder[name_Readout[icol]]->get(id, "system");
+        if(id_system==29) id_part = map_readout_decoder[name_Readout[icol]]->get(id, "part"); //ECAL endcap
+      	hitbar.setcellID(	map_readout_decoder[name_Readout[icol]]->get(id, "system"), 
+      										map_readout_decoder[name_Readout[icol]]->get(id, "module"), 
+      										map_readout_decoder[name_Readout[icol]]->get(id, "stave"), 
+                          id_part, 
+      										map_readout_decoder[name_Readout[icol]]->get(id, "dlayer"), 
+      										map_readout_decoder[name_Readout[icol]]->get(id, "slayer"),
+      										map_readout_decoder[name_Readout[icol]]->get(id, "bar"));
+      	// double Lbar = GetBarLength(hitbar);  //NOTE: Is fixed with geometry LongCrystalBarBarrelCalorimeter32Polygon_v01.
+      	double Lbar = GetBarLengthFromGeo(id);
+        hitbar.setLength(Lbar);
+
+      	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 totQ1_Att = 0;
+      	double totQ2_Att = 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;
+      		totQ1_Truth += en;
+      
+      		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(id_system == 20){ //ECAL barrel
+        		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());
+      		  }
+          }
+          else if(id_system == 29){ //ECAL endcaps
+            sign = rpos.x()==0 ? 1 : rpos.x()/fabs(rpos.x());
+          }
+      		if(!fabs(sign)) {std::cout<<"ERROR: Wrong bar direction/position!"<<std::endl; continue;}
+      
+      		// ####### For Charge Digitization #######
+      		// non-uniformity = 0
+      		// 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;
+      
+      		// non-uniformity != 0
+      		double Ratio_left = exp(-(Lbar/2 + sign*sqrt(rpos.Mag2()))/Latt) / (2 * exp(-(Lbar/2)/Latt));
+      		double Ratio_right = exp(-(Lbar/2 - sign*sqrt(rpos.Mag2()))/Latt) / (2 * exp(-(Lbar/2)/Latt));
+      		totQ1_Att += en*Ratio_left;
+      		totQ2_Att += 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;
+      		}
+      	}
+      
+      	int ScinGen; 
+      	int outLO1, outNDC1, outNDetPE1, outLO2, outNDC2, outNDetPE2;
+      	float outADC1, outADCGain1, outPedestal1, outPedestal2, outADC2, outADCGain2;
+      	float ChannelTemp, CryTID, SiPMNIEL, CryIntLY, SiPMGain, SiPMDCR;
+      	if(_UseRelDigi){
+      		// #############################################
+      		// ####### Realistic Charge Digitization #######
+      		// #############################################
+      
+      		//TODO: fEcalMIPEnergy should depends on crystal size. 
+          //TODO: Barrel and endcap should use different temperature map. 
+      		int layer = (hitbar.getDlayer() - 1) * 2 + hitbar.getSlayer();
+      		float temp_dif = (27 - layer) * fEcalTempGrad + sEcalTempRef - fEcalTempRef;// compared with fEcalTempRef
+      		ChannelTemp = temp_dif + fEcalTempRef;
+      		CryTID = fEcalCryTID;
+      		SiPMNIEL = fEcalSiPMNIEL;
+      		// float sEcalCryIntLY = rndm.Gaus(fEcalCryIntLY, fEcalCryIntLYFlu * fEcalCryIntLY);
+      		float sEcalCryIntLY = fEcalCryIntLY;
+      		float sEcalSiPMGainMean = fEcalSiPMGainMean;
+      		float sEcalSiPMDCR = fEcalSiPMDCR;
+      
+      		// Effects on crystal 
+      		if(fUseCryTID && fEcalCryTID >= 50){
+      			sEcalCryIntLY = sEcalCryIntLY * g_CryLYRatio_vs_TID->Eval(fEcalCryTID);
+      		}
+      		if(fUseCryTemp) {
+      			sEcalCryIntLY = sEcalCryIntLY * (1 + temp_dif * fEcalBGOTempCoef);
+      		}
+      		CryIntLY = sEcalCryIntLY;
+      		if(fUseDigiScint){
+      			ScinGen = std::round(rndm.Poisson((totQ1_Att+totQ2_Att) * 1000 * sEcalCryIntLY));
+      		}
+      		else{
+      			ScinGen = (totQ1_Att+totQ2_Att) * 1000 * sEcalCryIntLY;
+      		}
+      //cout<<endl;
+      //cout<<"In Hit #"<<i<<": truth energy "<<totQ1_Att+totQ2_Att<<", used intrinsic LY "<<sEcalCryIntLY<<", ph "<<ScinGen;
+      
+      		// Remove corrections
+      		if(fUseCryTemp && !fUseCryTempCor) {
+      			sEcalCryIntLY = sEcalCryIntLY / (1 + temp_dif * fEcalBGOTempCoef);
+      		}
+      		if((fUseCryTID && fEcalCryTID >= 50) && !fUseCryTIDCor) {
+      			sEcalCryIntLY = sEcalCryIntLY / g_CryLYRatio_vs_TID->Eval(fEcalCryTID);
+      		}
+      
+      		// Effects on SiPM
+      		if(fUseSiPMNIEL && fEcalSiPMNIEL >= 1e+7) {
+      			sEcalSiPMDCR = sEcalSiPMDCR * g_SiPMDCR_vs_NIEL->Eval(fEcalSiPMNIEL);
+      		}
+      		if(fUseSiPMTemp) {
+      			sEcalSiPMGainMean = sEcalSiPMGainMean * (1 + temp_dif * fEcalSiPMGainTempCoef);
+      			sEcalSiPMDCR = sEcalSiPMDCR * pow(10, fEcalSiPMDCRTempCoef * temp_dif);
+      		}
+      		SiPMGain = sEcalSiPMGainMean;
+      		SiPMDCR = sEcalSiPMDCR;
+      		// Remove corrections
+      		if(fUseSiPMTemp && ! fUseSiPMTempCor) {
+      			sEcalSiPMGainMean = sEcalSiPMGainMean / (1 + temp_dif * fEcalSiPMGainTempCoef);
+      		}
+      		// if((fUseSiPMNIEL && fEcalSiPMNIEL >= 1e+7) && !fUseSiPMNIELCor) {
+      		// }
+      //cout<<", SiPM gain "<<sEcalSiPMGainMean<<endl;
+      
+      		totQ1_Digi = EnergyDigi(ScinGen*totQ1_Att/(totQ1_Att+totQ2_Att), sEcalCryIntLY, sEcalSiPMGainMean, sEcalSiPMDCR, 
+      								f_SiPMResponse, f_SiPMSigmaDet, f_SiPMSigmaRecp, f_SiPMSigmaRecm, f_AsymGauss, f_DarkNoise,
+      								outLO1, outNDC1, outNDetPE1, outPedestal1, outADC1, outADCGain1)/1000;
+      		totQ2_Digi = EnergyDigi(ScinGen*totQ2_Att/(totQ1_Att+totQ2_Att), sEcalCryIntLY, sEcalSiPMGainMean, sEcalSiPMDCR, 
+      								f_SiPMResponse, f_SiPMSigmaDet, f_SiPMSigmaRecp, f_SiPMSigmaRecm, f_AsymGauss, f_DarkNoise,
+      								outLO2, outNDC2, outNDetPE2, outPedestal2, outADC2, outADCGain2)/1000;
+      	}
+      	else{
+      		if( (totQ1_Att+totQ2_Att)!=0 ){
+      			totQ1_Digi = totQ1_Att;
+      			totQ2_Digi = totQ2_Att;
+      		}
+      		if( totQ1_Digi*1000./fEcalMIPEnergy < fEcalMIP_Thre ) totQ1_Digi = 0;
+      		if( totQ2_Digi*1000./fEcalMIPEnergy < fEcalMIP_Thre ) totQ2_Digi = 0;
+      	}
+      
+      	// cout<<"bar truth Q1: "<<totQ1_Att*1000<<",\t bar digi  Q1: "<<totQ1_Digi*1000<<endl;
+      	if(totQ1_Digi==0 && totQ2_Digi==0) continue;
+      
+      	hitbar.setQ(totQ1_Digi, totQ2_Digi);
+      	hitbar.setT(thT1, thT2);
+      	// cout<<"bar thT1: "<<thT1<<",\t bar thT2: "<<thT2<<endl;
+      
+      	// ##################################
+      	// ####### 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_Att>(fEcalMIPEnergy*fEcalMIP_Thre/1000.) && totQ2_Att>(fEcalMIPEnergy*fEcalMIP_Thre/1000.)){
+      	//  // cout<<"Truth Energy:"<<totQ1_Att<<"   "<<totQ2_Att<<endl;
+      	//  totE_Truth+=(totQ1_Att+totQ2_Att);
+      	//}
+      
+      
+      	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_E_Truth.push_back(totQ1_Truth);
+      		m_simBar_Scint.push_back(ScinGen);
+      		m_simBar_ChannelTemp.push_back(ChannelTemp);
+      		m_simBar_CryTID.push_back(CryTID);
+      		m_simBar_SiPMNIEL.push_back(SiPMNIEL);
+      		m_simBar_CryIntLY.push_back(CryIntLY);
+      		m_simBar_SiPMGain.push_back(SiPMGain);
+      		m_simBar_SiPMDCR.push_back(SiPMDCR);
+      		m_simBar_LO1.push_back(outLO1);
+      		m_simBar_LO2.push_back(outLO2);
+      		m_simBar_NDC1.push_back(outNDC1);
+      		m_simBar_NDC2.push_back(outNDC2);
+      		m_simBar_NDetPE1.push_back(outNDetPE1);
+      		m_simBar_NDetPE2.push_back(outNDetPE2);
+      		m_simBar_Pedestal1.push_back(outPedestal1);
+      		m_simBar_Pedestal2.push_back(outPedestal2);
+      		m_simBar_ADC1.push_back(outADC1);
+      		m_simBar_ADC2.push_back(outADC2);
+      		m_simBar_ADCGain1.push_back(outADCGain1);
+      		m_simBar_ADCGain2.push_back(outADCGain2);
+      		m_simBar_Q1_Att.push_back(totQ1_Att);
+      		m_simBar_Q2_Att.push_back(totQ2_Att);
+      		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_length.push_back(hitbar.getLength());
+          m_simBar_system.push_back(hitbar.getSystem());
+      		m_simBar_module.push_back(hitbar.getModule());
+      		m_simBar_stave.push_back(hitbar.getStave());
+      		m_simBar_part.push_back(hitbar.getPart());
+      		m_simBar_dlayer.push_back(hitbar.getDlayer());
+      		m_simBar_slayer.push_back(hitbar.getSlayer());
+          m_simBar_bar.push_back(hitbar.getBar());
+      		m_simBar_cellID.push_back(hitbar.getcellID());
+      	}
       }
-      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());
-		}
-	}
+  	  m_simhitCol.clear();
+    }catch(GaudiException &e){
+      info()<<"SimCaloHit collection "<<name_SimCaloHit[icol]<<" is not available "<<endmsg;
+    }
+  }
 
 	if(_writeNtuple){
-		t_SimCont->Fill();
+		// 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;
+	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;
@@ -427,7 +659,6 @@ StatusCode EcalDigiAlg::execute()
 
   	_nEvt ++ ;
   	//delete SimHitCol, caloVec, caloAssoVec; 
-  	m_simhitCol.clear();
 	return StatusCode::SUCCESS;
 }
 
@@ -435,76 +666,219 @@ StatusCode EcalDigiAlg::finalize()
 {
 	if(_writeNtuple){
   		m_wfile->cd();
-	  	t_SimCont->Write();
+	  	//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;
+  map_readout_decoder.clear();
+	delete m_cellIDConverter, m_geosvc;
+	delete f_SiPMResponse, f_SiPMSigmaDet, f_SiPMSigmaRecp, f_SiPMSigmaRecm, f_AsymGauss, f_DarkNoise, g_SiPMDCR_vs_NIEL, g_CryLYRatio_vs_TID;
 	return GaudiAlgorithm::finalize();
 }
 
-double EcalDigiAlg::EnergyDigi(double ScinGen, double sEcalCryMipLY){
+float EcalDigiAlg::EnergyDigi(float ScinGen, float sEcalCryIntLY, float sEcalSiPMGainMean, float sEcalSiPMDCR, 
+								TF1* f_SiPMResponse, TF1* f_SiPMSigmaDet, TF1* f_SiPMSigmaRecp, TF1* f_SiPMSigmaRecm, TF1* f_AsymGauss, TF1* f_DarkNoise,
+								int& outLO, int& outNDC, int& outNDetPE, float& outPedestal, float& outADC, float& outADCGain)
+{
+	// float sEcalSiPMPDE = rndm.Gaus(fEcalSiPMPDE, fEcalSiPMPDEFlu * fEcalSiPMPDE);
+	float sEcalSiPMPDE = fEcalSiPMPDE;
+  float fEcalCryAtt = fEcalCryMipLY/(fEcalCryIntLY*fEcalSiPMPDE*fEcalMIPEnergy);
+	int sEcalCryAttLO = std::round(ScinGen * fEcalCryAtt * sEcalSiPMPDE);
+	if (sEcalCryAttLO < 0) sEcalCryAttLO = 0;
+	float sEcalCaliMIPLY = sEcalCryIntLY * fEcalCryAtt * sEcalSiPMPDE * fEcalMIPEnergy;
+	// sEcalCaliMIPLY = rndm.Gaus(sEcalCaliMIPLY, fEcalCryLYUn * sEcalCaliMIPLY);
+	outLO = sEcalCryAttLO;
+//cout<<"  Real Digi: output Light "<<sEcalCryAttLO<<" = round ("<<ScinGen<<" * "<<fEcalCryAtt<<" * "<<sEcalSiPMPDE<<")";	
+
+	int sNLin = sEcalCryAttLO;
+	int sNDet = 0;
+	float sNDetMean = 0;
+	float sNDetSigma = 0;
+	if(fSiPMDigiVerbose==0 || sNLin<100)
+	{
+		sNDetMean = sNLin;
+		//sNDetSigma = f_SiPMSigmaDet->Eval(sNDetMean);
+    sNDetSigma = 0;
+		sNDet = std::round(rndm.Gaus(sNDetMean, sNDetSigma));
+	}
+	else
+	{
+		sNDetMean = f_SiPMResponse->Eval(sNLin);
+		sNDetSigma = f_SiPMSigmaDet->Eval(sNDetMean);
+		sNDet = std::round(rndm.Gaus(sNDetMean, sNDetSigma));
+	}
+	//SiPM dark noise: dark counts and acossiated crosstalks, the crossstalk follows the Borel distribution
+	int darkcounts_mean = rndm.Poisson(sEcalSiPMDCR * fEcalTimeInterval);
+	int darkcounts_CT = 0;
+	for(int i=0;i<darkcounts_mean;i++)
+	{
+		double darkcounts_rdm = rndm.Uniform(0, 1);
+		int sum_darkcounts = 1;
+		if(! (darkcounts_rdm <= f_DarkNoise->Eval(sum_darkcounts)))
+		{
+			float prob = f_DarkNoise->Eval(sum_darkcounts);
+			while(darkcounts_rdm > prob)
+			{
+				sum_darkcounts++;
+				prob += f_DarkNoise->Eval(sum_darkcounts);
+			}
+		}
+		darkcounts_CT += sum_darkcounts;
+	}
+	outNDC = darkcounts_CT;
+	sNDet += darkcounts_CT;
+	if (sNDet < 0) sNDet = 0;
+	outNDetPE = sNDet;
+
+//cout<<", SiPM pixel "<<sNDet<<", dark count + Xtalk "<<darkcounts_CT;
+
+	Bool_t Use_G1 = kFALSE;
+	Bool_t Use_G2 = kFALSE;
+	Bool_t Use_G3 = kFALSE;
+	// sEcalSiPMGainMean = rndm.Gaus(sEcalSiPMGainMean, sEcalSiPMGainMean * fEcalSiPMGainMeanFlu);
+	float sEcalSiPMGainSigma = sEcalSiPMGainMean * fEcalSiPMGainSigma;
+	float sPedestal = fPedestal;
+	float sEcalFEENoiseSigma = fEcalFEENoiseSigma;
+	float sEcalASICNoiseSigma = fEcalASICNoiseSigma;
+	float sADCMean = sNDet * sEcalSiPMGainMean + sPedestal;
+	float sADCSigma = std::sqrt(sNDet * sEcalSiPMGainSigma * sEcalSiPMGainSigma + sEcalFEENoiseSigma * sEcalFEENoiseSigma + fEcalASICNoiseSigma * fEcalASICNoiseSigma);
+	float sADC = -1;
+	sADC = std::round(rndm.Gaus(sADCMean, sADCSigma));
+	if(sADC < 0) sADC = 0;
+	outPedestal = sPedestal;
+	outADC = sADC;
+
+//cout<<", raw ADC "<<sADC<<" = Gaus ( "<<sADCMean<<" +- "<<sADCSigma<<" )"<<endl;
+//cout<<"    ADC mean = "<<sNDet<<" * "<<sEcalSiPMGainMean<<" + "<<sPedestal;
+//cout<<", ADC sigma = sqrt("<<sNDet<<" * "<<sEcalSiPMGainSigma<<"^2 + "<<sEcalFEENoiseSigma<<"^2 + "<<fEcalASICNoiseSigma.value()<<"^2 )"<<endl;
+	
+	if(sADC <= fADCSwitch)
+	{
+		Use_G1 = kTRUE;
+
+		if(fSiPMDigiVerbose==2 && sNDet>=100)
+		{
+			float sNRecMean = f_SiPMResponse->GetX((sADC-sPedestal)/sEcalSiPMGainMean);
+			float sNRecSigma = sNDetSigma;
+			float NRec = rndm.Gaus(sNRecMean, sNRecSigma);
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		else if(fSiPMDigiVerbose==3 && sNDet>=100)
+		{
+			float sNADCDet = (sADC - sPedestal) / sEcalSiPMGainMean;
+			float sNRecMean = f_SiPMResponse->GetX(sNADCDet);
+			float sNRecSigmap = sNRecMean - f_SiPMSigmaRecp->GetX(sNADCDet);
+			float sNRecSigmam = f_SiPMSigmaRecm->GetX(sNADCDet) - sNRecMean;
+			f_AsymGauss->SetRange(sNRecMean-3*sNRecSigmap, sNRecMean+3*sNRecSigmam);
+			f_AsymGauss->SetParameters(sNRecMean, sNRecSigmap, sNRecSigmam);
+			float NRec = f_AsymGauss->GetRandom();
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		outPedestal = sPedestal;
+		outADCGain = sADC;
+		sPedestal = fPedestal + sEcalSiPMDCR * fEcalTimeInterval * (1 + mean_CT) * sEcalSiPMGainMean;
+
+        // float sEcalCaliGainMean = rndm.Gaus(sEcalSiPMGainMean, fEcalSiPMGainUn * sEcalSiPMGainMean);
+		// float sMIP = (sADC - sPedestal) / sEcalCaliGainMean / sEcalCaliMIPLY;
+		float sMIP = (sADC - sPedestal) / sEcalSiPMGainMean / sEcalCaliMIPLY;
 
-    Int_t sPix; 
+//cout<<", after gain "<<sADC<<", Nmip "<<sMIP<<" = ("<<sADC<<" - "<<sPedestal<<") / "<<sEcalSiPMGainMean<<" / "<<sEcalCaliMIPLY<<endl;
 
-  // ####### SiPM Saturation  #######
-    if(fUseDigiSaturation)
-      sPix = std::round(fEcalSiPMPixels * (1 - TMath::Exp(-sPix / fEcalSiPMPixels)));
-    else sPix = int(ScinGen);
+		if(sMIP < fEcalMIP_Thre) return 0;
+		return sMIP * fEcalMIPEnergy;
+	}
+	else if(sADC > fADCSwitch && int(sADC/fGainRatio_12) <= fADCSwitch)
+	{
+		Use_G2 = kTRUE;
+		sEcalSiPMGainMean = sEcalSiPMGainMean / fGainRatio_12;
+		sPedestal = fPedestal;
+		sEcalSiPMGainSigma = sEcalSiPMGainMean * fEcalSiPMGainSigma;
+		sEcalFEENoiseSigma = fEcalFEENoiseSigma / fGainRatio_12;
+
+		sADCMean = sNDet * sEcalSiPMGainMean + sPedestal;
+		sADCSigma = std::sqrt(sNDet * sEcalSiPMGainSigma * sEcalSiPMGainSigma + fEcalASICNoiseSigma * fEcalASICNoiseSigma + sEcalFEENoiseSigma * sEcalFEENoiseSigma);
+		sADC = std::round(rndm.Gaus(sADCMean, sADCSigma));
+		if(sADC < 0) sADC = 0;
+
+		if(fSiPMDigiVerbose==2)
+		{
+			float sNRecMean = f_SiPMResponse->GetX((sADC-sPedestal)/sEcalSiPMGainMean);
+			float sNRecSigma = sNDetSigma;
+			float NRec = rndm.Gaus(sNRecMean, sNRecSigma);
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		else if(fSiPMDigiVerbose==3)
+		{
+			float sNADCDet = (sADC - sPedestal) / sEcalSiPMGainMean;
+			float sNRecMean = f_SiPMResponse->GetX(sNADCDet);
+			float sNRecSigmap = sNRecMean - f_SiPMSigmaRecp->GetX(sNADCDet);
+			float sNRecSigmam = f_SiPMSigmaRecm->GetX(sNADCDet) - sNRecMean;
+			f_AsymGauss->SetRange(sNRecMean-3*sNRecSigmap, sNRecMean+3*sNRecSigmam);
+			f_AsymGauss->SetParameters(sNRecMean, sNRecSigmap, sNRecSigmam);
+			float NRec = f_AsymGauss->GetRandom();
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		outPedestal = sPedestal;
+		outADCGain = sADC;
+		sPedestal = fPedestal + sEcalSiPMDCR * fEcalTimeInterval * (1 + mean_CT) * sEcalSiPMGainMean;
 
-	
-	// ################################
-	// ####### 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;
-    if(fUseDigiADC){
-        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;
-      }
+        // float sEcalCaliGainMean = rndm.Gaus(sEcalSiPMGainMean, fEcalSiPMGainUn * sEcalSiPMGainMean);
+		// float sMIP = (sADC - sPedestal) / sEcalCaliGainMean / sEcalCaliMIPLY;
+		float sMIP = (sADC - sPedestal) / sEcalSiPMGainMean / sEcalCaliMIPLY;
+//cout<<", after gain "<<sADC<<", Nmip "<<sMIP<<endl;
 
-    }
-    else{
-      sADC = sADCMean; 
-      Double_t sMIP = sADC / fEcalChargeADCMean / sEcalCryMipLY;
-      if(sMIP < fEcalMIP_Thre) return 0;
-      return sMIP * fEcalMIPEnergy;
-    }
+		if(sMIP < fEcalMIP_Thre) return 0;
+		return sMIP * fEcalMIPEnergy;
+	}
+	else if(int(sADC/fGainRatio_12) > fADCSwitch)
+	{
+		Use_G3 = kTRUE;
+		sEcalSiPMGainMean = sEcalSiPMGainMean / fGainRatio_12 / fGainRatio_23;
+		sPedestal = fPedestal;
+		sEcalSiPMGainSigma = sEcalSiPMGainMean * fEcalSiPMGainSigma;
+		sEcalFEENoiseSigma = fEcalFEENoiseSigma / fGainRatio_12 / fGainRatio_23;
+
+		sADCMean = sNDet * sEcalSiPMGainMean + sPedestal;
+		sADCSigma = std::sqrt(sNDet * sEcalSiPMGainSigma * sEcalSiPMGainSigma + fEcalASICNoiseSigma * fEcalASICNoiseSigma + sEcalFEENoiseSigma * sEcalFEENoiseSigma);
+		sADC = std::round(rndm.Gaus(sADCMean, sADCSigma));
+		if(sADC < 0) sADC = 0;
+
+		if (sADC > fADC-1)
+		{
+			sADC = fADC-1;
+		}
+
+		if(fSiPMDigiVerbose==2)
+		{
+			float sNRecMean = f_SiPMResponse->GetX((sADC-sPedestal)/sEcalSiPMGainMean);
+			float sNRecSigma = sNDetSigma;
+			float NRec = rndm.Gaus(sNRecMean, sNRecSigma);
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		else if(fSiPMDigiVerbose==3)
+		{
+			float sNADCDet = (sADC - sPedestal) / sEcalSiPMGainMean;
+			float sNRecMean = f_SiPMResponse->GetX(sNADCDet);
+			float sNRecSigmap = sNRecMean - f_SiPMSigmaRecp->GetX(sNADCDet);
+			float sNRecSigmam = f_SiPMSigmaRecm->GetX(sNADCDet) - sNRecMean;
+			f_AsymGauss->SetRange(sNRecMean-3*sNRecSigmap, sNRecMean+3*sNRecSigmam);
+			f_AsymGauss->SetParameters(sNRecMean, sNRecSigmap, sNRecSigmam);
+			float NRec = f_AsymGauss->GetRandom();
+			sADC = NRec * sEcalSiPMGainMean + sPedestal;
+		}
+		outPedestal = sPedestal;
+		outADCGain = sADC;
+		sPedestal = fPedestal + sEcalSiPMDCR * fEcalTimeInterval * (1 + mean_CT) * sEcalSiPMGainMean;
+
+        // float sEcalCaliGainMean = rndm.Gaus(sEcalSiPMGainMean, fEcalSiPMGainUn * sEcalSiPMGainMean);
+		// float sMIP = (sADC - sPedestal) / sEcalCaliGainMean / sEcalCaliMIPLY;
+		float sMIP = (sADC - sPedestal) / sEcalSiPMGainMean / sEcalCaliMIPLY;
+//cout<<", after gain "<<sADC<<", Nmip "<<sMIP<<endl;
+		if(sMIP < fEcalMIP_Thre) return 0;
+		return sMIP * fEcalMIPEnergy;
+	}
 }
 
 StatusCode EcalDigiAlg::MergeHits( const edm4hep::SimCalorimeterHitCollection& m_col, std::vector<edm4hep::SimCalorimeterHit>& m_hits ){
@@ -524,7 +898,7 @@ StatusCode EcalDigiAlg::MergeHits( const edm4hep::SimCalorimeterHitCollection& m
 		edm4hep::MutableCaloHitContribution conb;
 		conb.setEnergy(m_step.getEnergy());
 		conb.setStepPosition(m_step.getPosition());
-    conb.setParticle( m_step.getContributions(0).getParticle() );
+		conb.setParticle( m_step.getContributions(0).getParticle() );
 		conb.setTime(m_step.getContributions(0).getTime());
 
 		edm4hep::MutableSimCalorimeterHit m_hit = find(m_mergedhit, cellid);
@@ -558,6 +932,17 @@ double EcalDigiAlg::GetBarLength(CaloBar& bar){
     }
 }
 
+double EcalDigiAlg::GetBarLengthFromGeo(unsigned long long id){
+
+	dd4hep::PlacedVolume ipv = m_volumeManager.lookupVolumePlacement(id);
+	dd4hep::Volume ivol = ipv.volume();
+	std::vector< double > iVolParam = ivol.solid().dimensions();
+	// cout<<"iVolParam: "<<iVolParam.size()<<" "<<iVolParam[0]<<" "<<iVolParam[1]<<" "<<iVolParam[2]<<endl;
+	auto maxElement = std::max_element(iVolParam.begin(), iVolParam.end());
+	// std::cout << "bar length: " << *maxElement * 20 << std::endl; 
+	iVolParam.clear();
+	return *maxElement * 20; // mm
+}
 
 /*
 dd4hep::Position EcalDigiAlg::GetCellPos(dd4hep::Position& pos, CaloBar& bar){
@@ -609,6 +994,8 @@ edm4hep::MutableSimCalorimeterHit EcalDigiAlg::find(const std::vector<edm4hep::M
 void EcalDigiAlg::Clear(){
   	totE_Truth = -99;
 	totE_Digi = -99;
+	mean_CT = -99;
+	ECALTemp = -99;
 	m_step_x.clear();
 	m_step_y.clear();
 	m_step_z.clear();
@@ -624,13 +1011,37 @@ void EcalDigiAlg::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_E_Truth.clear();
+	m_simBar_Scint.clear();
+	m_simBar_ChannelTemp.clear();
+	m_simBar_CryTID.clear();
+	m_simBar_SiPMNIEL.clear();
+	m_simBar_CryIntLY.clear();
+	m_simBar_SiPMGain.clear();
+	m_simBar_SiPMDCR.clear();
+	m_simBar_LO1.clear();
+	m_simBar_LO2.clear();
+	m_simBar_NDC1.clear();
+	m_simBar_NDC2.clear();
+	m_simBar_NDetPE1.clear();
+	m_simBar_NDetPE2.clear();
+	m_simBar_Pedestal1.clear();
+	m_simBar_Pedestal2.clear();
+	m_simBar_ADC1.clear();
+	m_simBar_ADC2.clear();
+	m_simBar_ADCGain1.clear();
+	m_simBar_ADCGain2.clear();
+	m_simBar_Q1_Att.clear();
+	m_simBar_Q2_Att.clear();
 	m_simBar_Q1_Digi.clear();
 	m_simBar_Q2_Digi.clear();
+	m_simBar_length.clear();
+	m_simBar_system.clear();
 	m_simBar_module.clear();
 	m_simBar_stave.clear();
+	m_simBar_part.clear();
 	m_simBar_dlayer.clear();
 	m_simBar_slayer.clear();
-  	m_simBar_cellID.clear();
+	m_simBar_bar.clear();
+  m_simBar_cellID.clear();
 }
diff --git a/Digitization/DigiCalo/src/EcalDigiAlg.h b/Digitization/DigiCalo/src/EcalDigiAlg.h
index 684ad726..6977e799 100644
--- a/Digitization/DigiCalo/src/EcalDigiAlg.h
+++ b/Digitization/DigiCalo/src/EcalDigiAlg.h
@@ -24,6 +24,8 @@
 #include "TString.h"
 #include "TH3.h"
 #include "TH1.h"
+#include "TF1.h"
+#include "TGraph.h"
 
 #include <cstdlib>
 #include "time.h"
@@ -57,9 +59,12 @@ public:
   StatusCode MergeHits(const edm4hep::SimCalorimeterHitCollection& m_col, std::vector<edm4hep::SimCalorimeterHit>& m_hits);  
 
 	double GetBarLength(CaloBar& bar); //TODO: should read from geom file! 
+  double GetBarLengthFromGeo(unsigned long long id); 
 	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);
+  float EnergyDigi(float ScinGen, float sEcalCryMipLY, float sEcalSiPMGainMean, float sEcalSiPMDCR, 
+                    TF1* f_SiPMResponse, TF1* f_SiPMSigmaDet, TF1* f_SiPMSigmaRecp, TF1* f_SiPMSigmaRecm, TF1* f_AsymGauss, TF1* f_DarkNoise,
+                    int& outLO, int& outNDC, int& outNDetPE, float& outPedestal, float& outADC, float& outADCGain);
 
 	void Clear();
 
@@ -75,23 +80,58 @@ protected:
 	TFile* m_wfile;
 	TTree* t_SimCont;
 	TTree* t_SimBar;
-	
+
   double totE_Truth, totE_Digi;
+  double mean_CT, ECALTemp;
   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;
+	FloatVec m_simBar_x, m_simBar_y, m_simBar_z, 
+            m_simBar_E_Truth, m_simBar_Scint, 
+            m_simBar_ChannelTemp, m_simBar_CryTID, m_simBar_SiPMNIEL, m_simBar_CryIntLY, m_simBar_SiPMGain, m_simBar_SiPMDCR,
+            m_simBar_LO1, m_simBar_LO2, m_simBar_NDC1, m_simBar_NDC2, m_simBar_NDetPE1, m_simBar_NDetPE2, 
+            m_simBar_Pedestal1, m_simBar_Pedestal2, m_simBar_ADC1, m_simBar_ADC2, m_simBar_ADCGain1, m_simBar_ADCGain2,
+            m_simBar_T1, m_simBar_T2, 
+            m_simBar_Q1_Att, m_simBar_Q2_Att, m_simBar_Q1_Digi, m_simBar_Q2_Digi, 
+            m_simBar_length,
+            m_simBar_bar, m_simBar_dlayer, m_simBar_slayer, m_simBar_stave, m_simBar_part, m_simBar_module, m_simBar_system;
   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"};
+	dd4hep::rec::CellIDPositionConverter* m_cellIDConverter;
+	//dd4hep::DDSegmentation::BitFieldCoder* m_decoder;
+  std::map<std::string, dd4hep::DDSegmentation::BitFieldCoder*> map_readout_decoder;
+  dd4hep::VolumeManager m_volumeManager;
+
+	TF1* f_SiPMResponse = nullptr;
+  TF1* f_SiPMSigmaDet = nullptr;
+  TF1* f_SiPMSigmaRecp = nullptr;
+  TF1* f_SiPMSigmaRecm = nullptr;
+  TF1* f_AsymGauss = nullptr;
+  TF1* f_DarkNoise = nullptr;
+  TGraph* g_SiPMDCR_vs_NIEL = nullptr;
+  TGraph* g_CryLYRatio_vs_TID = nullptr;
+
+  // Input and collections
+  typedef DataHandle<edm4hep::SimCalorimeterHitCollection>              SimCaloType;
+  typedef DataHandle<edm4hep::CalorimeterHitCollection>                 CaloType;
+  typedef DataHandle<edm4hep::MCRecoCaloAssociationCollection>          CaloSimAssoType;      //Calorimeter - SimCalorimeter
+  typedef DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>  CaloParticleAssoType; //Calorimeter - MCParticle
+
+  Gaudi::Property< std::vector<std::string> > name_SimCaloHit{ this, "SimCaloHitCollection", {"EcalBarrelCollection"} };
+  Gaudi::Property< std::vector<std::string> > name_Readout{ this, "ReadOutName", {"EcalBarrelCollection"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloHit{ this, "CaloHitCollection", {"ECALBarrel"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloAsso{ this, "CaloAssociationCollection", {"ECALBarrelAssoCol"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloMCPAsso{ this, "CaloMCPAssociationCollection", {"ECALBarrelParticleAssoCol"} };
+
+  std::vector<SimCaloType*> _inputSimHitCollection;
+  std::vector<CaloType*> _outputHitCollection;
+  std::vector<CaloSimAssoType*> _outputCaloSimAssoCol;
+  std::vector<CaloParticleAssoType*> _outputCaloMCPAssoCol;
+
+  //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"};
 
@@ -100,37 +140,66 @@ protected:
   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> Latt{this, 	"AttenuationLength", 8000, "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> fUseDigiScint{this, "UseDigiScint", 1, "Add scintillation effect in digitization"};
-  mutable Gaudi::Property<int> fUseDigiSaturation{this, "UseDigiSaturation", 0, "Add SiPM saturation effect in digitization"};
-  mutable Gaudi::Property<int> fUseDigiADC{this, "UseDigiADC", 1, "Add ADC precision effect in digitization"};
-
-  mutable Gaudi::Property<int> fADC{this, 	"ADC", 4096, "Total ADC conuts"};
+  mutable Gaudi::Property<int> fUseCryTemp{this, "UseCryTemp", 1, "Add crystal temperature effect in digitization"};
+  mutable Gaudi::Property<int> fUseCryTempCor{this, "UseCryTempCor", 1, "Add correction on crystal temperature effect in digitization"};
+  mutable Gaudi::Property<int> fUseSiPMTemp{this, "UseSiPMTemp", 1, "Add SiPM temperature effect in digitization"};
+  mutable Gaudi::Property<int> fUseSiPMTempCor{this, "UseSiPMTempCor", 1, "Add correction on SiPM temperature effect in digitization"};
+  mutable Gaudi::Property<int> fUseCryTID{this, "UseCryTID", 0, "Add TID effect on crystal"};
+  mutable Gaudi::Property<int> fUseCryTIDCor{this, "UseCryTIDCor", 0, "Add correction on TID effect on crystal"};
+  mutable Gaudi::Property<int> fUseSiPMNIEL{this, "UseSiPMNIEL", 1, "Add NIEL effect on SiPM"};
+  mutable Gaudi::Property<int> fUseSiPMNIELCor{this, "UseSiPMNIELCor", 0, "Add NIEL effect on SiPM"};
+
+  mutable Gaudi::Property<int> fADC{this, 	"ADC", 8192, "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)"};
+  mutable Gaudi::Property<int> fADCSwitch{this, 	"ADCSwitch", 8000, "switching point of different gain mode"};
+  mutable Gaudi::Property<float> fPedestal{this, 	"Pedestal", 50, "ADC value of pedestal"};
+  mutable Gaudi::Property<int> fSiPMDigiVerbose{this, 	"SiPMDigiVerbose", 1, "SiPM Digitization verbose. 0:w/o response, w/o correction; 1:w/ response, w/o correction; 2:w/ response, w/ simple correction; 3:w/ response, w/ full correction;"};
+  mutable Gaudi::Property<float> fGainRatio_12{this, 	"GainRatio_12", 50, "Gain-1 over Gain-2"};
+  mutable Gaudi::Property<float> fGainRatio_23{this, 	"GainRatio_23", 60, "Gain-2 over Gain-3"};
+  mutable Gaudi::Property<float> fEcalMIPEnergy{this, 	"EcalMIPEnergy", 8.9, "MIP energy deposit in 1cm BGO (MeV/MIP)"};
+  mutable Gaudi::Property<float> fEcalCryMipLY{this, 	"EcalCryMipLY", 200, "Detected light yield (p.e./MIP)"};
+  mutable Gaudi::Property<float> fEcalCryIntLY{this, 	"EcalCryIntLY", 8200, "Intrinsic light yield (ph/MeV)"};
+  mutable Gaudi::Property<float> fEcalSiPMPDE{this, 	"EcalSiPMPDE", 0.25, "SiPM PDE"};
+  mutable Gaudi::Property<float> fEcalSiPMDCR{this, 	"EcalSiPMDCR", 2500000, "SiPM Dark Count Rate (Hz)"};
+  mutable Gaudi::Property<float> fEcalSiPMCT{this, 	"EcalSiPMCT", 0.12, "SiPM crosstalk Probability"};
+  mutable Gaudi::Property<float> fEcalTimeInterval{this, 	"EcalTimeInterval", 0.00000015, "Time interval for one readout (s)"};
+  //mutable Gaudi::Property<float> fEcalCryAtt{this, 	"EcalCryAtt", fEcalCryMipLY/(fEcalCryIntLY*fEcalSiPMPDE*fEcalMIPEnergy), "Ratio of light attenuation, changed with SiPM PDE to achieve the assigned MIP light yield"};
+  
+  mutable Gaudi::Property<float> fEcalSiPMGainMean{this, 	"EcalSiPMGainMean", 50, "SiPM gain: ADC per p.e. for Gain-1 (ADC)"};
+  mutable Gaudi::Property<float> fEcalSiPMGainSigma{this, 	"EcalSiPMGainSigma", 0.08, "Fluctuation of single photoelctron ADC around the mean value for single device (%)"};
+  mutable Gaudi::Property<float> fEcalASICNoiseSigma{this, 	"EcalASICNoiseSigma", 4, "Sigma of ASIC noise (ADC), which does not depend on gain"};
+  mutable Gaudi::Property<float> fEcalFEENoiseSigma{this, 	"EcalFEENoiseSigma", 0, "Sigma of front-end-electronics noise (ADC), which depends on gain"};
+  mutable Gaudi::Property<float> fEcalMIP_Thre{this, 	"EcalMIP_Thre", 0.05, "Energy threshold for single readout channel (MIP)"};
+
+  mutable Gaudi::Property<float> fEcalTempRef{this, 	"EcalTempRef", 298.15, "Reference temperature, top layer (K)"};
+  mutable Gaudi::Property<float> fEcalTempFluc{this, 	"EcalTempFluc", 3, "ECAL temperature fluctuation around 25 degrees (K)"};
+  mutable Gaudi::Property<float> fEcalTempGrad{this, 	"EcalTempGrad", 3./27, "The radial temperature gradient in the ECAL (K/crystal)"};
+  mutable Gaudi::Property<float> fEcalBGOTempCoef{this, 	"EcalBGOTempCoef", -0.0138, "Temperature dependence of BGO light yield (%/K)"}; // doi:10.1007/s11433-014-5548-4
+  mutable Gaudi::Property<float> fEcalSiPMGainTempCoef{this, 	"EcalSiPMGainTempCoef", -0.03, "Temperature dependence of SiPM gain (%/K)"}; // doi:10.1016/j.nima.2016.09.053
+  mutable Gaudi::Property<float> fEcalSiPMDCRTempCoef{this, 	"EcalSiPMDCRTempCoef", 3.34/80, "Temperature dependence of SiPM DCR (10^{k*deltaT})"}; // doi:10.1016/j.nima.2016.09.053
+
+  mutable Gaudi::Property<float> fEcalCryTID{this, 	"EcalCryTID", 10, "Total ionizing dose in crystal (rad})"};
+  mutable Gaudi::Property<float> fEcalSiPMNIEL{this, 	"EcalSiPMNIEL", 10, "Non-ionizing energy loss in SiPM, expressed as the equivalent 1 MeV neutron flux (cm-2s-1})"};
+
+  // mutable Gaudi::Property<float> fEcalCryIntLYFlu{this, 	"EcalCryIntLYFlu", 0.1, "Fluctuation of crystal intrinsic light yield"};
+  // mutable Gaudi::Property<float> fEcalSiPMPDEFlu{this, 	"EcalSiPMPDEFlu", 0.10, "Fluctuation of SiPM PDE"};
+  // mutable Gaudi::Property<float> fEcalCryLYUn{this, 	"EcalCryLYUn", 0.00, "Uncertainty of light yield calibration"};
+  // mutable Gaudi::Property<float> fEcalSiPMGainUn{this, 	"EcalSiPMGainUn", 0.00, "Uncertainty of SiPM gain calibration"};
+  // mutable Gaudi::Property<float> fEcalSiPMGainMeanFlu{this, 	"EcalSiPMGainMeanFlu", 0.15, "Fluctuation of SiPM gain"};
+  // mutable Gaudi::Property<float> fEcalADCError{this, 	"EcalADCError", 0.0, "ADC precision"};
+
 
   // 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};
+  //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/Digitization/DigiCalo/src/EcalDigiAlgShort.cpp b/Digitization/DigiCalo/src/EcalDigiAlgShort.cpp
new file mode 100644
index 00000000..d112d369
--- /dev/null
+++ b/Digitization/DigiCalo/src/EcalDigiAlgShort.cpp
@@ -0,0 +1,535 @@
+// Units by default: mm, ns.
+// NOTE: This digitisation highly matches detector geometry CRDEcal_Short.
+// TODO: read geometry information automatically.  
+#include "EcalDigiAlgShort.h"
+
+using namespace std;
+using namespace dd4hep;
+
+DECLARE_COMPONENT( EcalDigiAlgShort )
+
+EcalDigiAlgShort::EcalDigiAlgShort(const 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");
+
+    algname = name;
+    transform(algname.begin(), algname.end(), algname.begin(), ::tolower);
+}
+
+StatusCode EcalDigiAlgShort::initialize()
+{
+    if (algname.find("barrel") != string::npos)
+        dettype = 1;
+    else if (algname.find("endcap") != string::npos)
+        dettype = 2;
+    else
+        throw "Incorrect detector type! Make sure that the name of the instance contains 'barrel' or 'endcap'!";
+
+    if (_writeNtuple)
+    {
+        string s_outfile = _filename;
+        m_wfile = new TFile(s_outfile.c_str(), "recreate");
+        t_SimCont = new TTree("SimStep", "SimStep");
+        t_SimHit = new TTree("SimHit", "SimHit");
+        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);
+        t_SimCont->Branch("stepHit_x", &m_stepHit_x);
+        t_SimCont->Branch("stepHit_y", &m_stepHit_y);
+        t_SimCont->Branch("stepHit_z", &m_stepHit_z);
+        t_SimCont->Branch("step_E", &m_step_E);
+        t_SimCont->Branch("step_T", &m_step_T);
+        t_SimHit->Branch("totE_Truth", &totE_Truth);
+        t_SimHit->Branch("totE_Digi", &totE_Digi);
+        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_T", &m_simHit_T);
+        t_SimHit->Branch("simHit_Q_Truth", &m_simHit_Q_Truth);
+        t_SimHit->Branch("simHit_Q_Digi", &m_simHit_Q_Digi);
+        t_SimHit->Branch("simHit_module", &m_simHit_module);
+        t_SimHit->Branch("simHit_stave", &m_simHit_stave);
+        t_SimHit->Branch("simHit_layer", &m_simHit_layer);
+        if (dettype == 1)
+        {
+            t_SimHit->Branch("simHit_phi", &m_simHit_phi_x);
+            t_SimHit->Branch("simHit_iz", &m_simHit_z_y);
+        }
+        else if (dettype == 2)
+        {
+            t_SimHit->Branch("simHit_ix", &m_simHit_phi_x);
+            t_SimHit->Branch("simHit_iy", &m_simHit_z_y);
+        }
+        t_SimHit->Branch("simHit_cellID", &m_simHit_cellID);
+    }
+
+    cout << "EcalDigiAlgShort::m_scale=" << m_scale << endl;
+    m_geosvc = service<IGeomSvc>("GeomSvc");
+
+    if (!m_geosvc)
+        throw "EcalDigiAlgShort: Failed to find GeomSvc ...";
+
+    m_dd4hep = m_geosvc->lcdd();
+
+    if (!m_dd4hep)
+        throw "EcalDigiAlgShort: Failed to get dd4hep::Detector ...";
+
+    m_cellIDConverter = new 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);
+    cout << "EcalDigiAlgShort::initialize" << endl;
+    return GaudiAlgorithm::initialize();
+}
+
+StatusCode EcalDigiAlgShort::execute()
+{
+    if (_nEvt == 0)
+        cout << "EcalDigiAlgShort::execute begins..." << endl;
+
+    if (dettype == 1)
+        cout << "Barrel, processing event " << _nEvt << endl;
+    else if (dettype == 2)
+        cout << "End-cap, processing event " << _nEvt << 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();
+    vector<edm4hep::SimCalorimeterHit> m_simhitCol;
+    m_simhitCol.clear();
+    vector<CaloCrystalShort> m_hitCol;
+    m_hitCol.clear();
+
+    if (SimHitCol == 0)
+    {
+        cout << "SimCalorimeterHitCollection not found" << endl;
+        return StatusCode::SUCCESS;
+    }
+
+    if (_Debug >= 1)
+        cout << "Digitisation, input sim hit size = " << SimHitCol->size() << endl;
+
+    totE_Truth = 0;
+    totE_Digi = 0;
+
+    // Merge input simhit (steps) to real simhit (crystal).
+    MergeHits(*SimHitCol, m_simhitCol);
+    if (_Debug >= 1)
+        cout << "Hit merging finished, Nhit = " << m_simhitCol.size() << endl;
+
+    // Loop in SimHit, digitise SimHit to DigiHit
+    for (int i = 0; i < m_simhitCol.size(); ++i)
+    {
+        auto SimHit = m_simhitCol.at(i);
+
+        const unsigned long long id = SimHit.getCellID();
+        CaloCrystalShort hitcrystal;
+        hitcrystal.setcellID(id);
+        if (dettype == 1)
+            hitcrystal.setcellID(m_decoder->get(id, "system"),
+                                 m_decoder->get(id, "module"),
+                                 m_decoder->get(id, "stave"),
+                                 m_decoder->get(id, "layer"),
+                                 m_decoder->get(id, "phi"),
+                                 m_decoder->get(id, "z"));
+        else if (dettype == 2)
+            hitcrystal.setcellID(m_decoder->get(id, "system"),
+                                 m_decoder->get(id, "module"),
+                                 m_decoder->get(id, "stave"),
+                                 m_decoder->get(id, "layer"),
+                                 m_decoder->get(id, "x"),
+                                 m_decoder->get(id, "y"));
+
+        Position hitpos = m_cellIDConverter->position(id);
+        TVector3 pos(10 * hitpos.x(), 10 * hitpos.y(), 10 * hitpos.z());    // cm to mm.
+        hitcrystal.setPosition(pos);
+        const double distcrystal = pos.Mag();
+
+        MCParticleToEnergyWeightMap MCPEnMap;
+        MCPEnMap.clear();
+        vector<HitStep> Digivec;
+        Digivec.clear();
+        double totQ_Truth = 0;
+        double totQ_Digi = 0;
+        double totQ = 0;
+
+        // Loop in all SimHitContribution (G4Step).
+        for (int iCont = 0; iCont < SimHit.contributions_size(); ++iCont)
+        {
+            auto conb = SimHit.getContributions(iCont);
+            if (!conb.isAvailable())
+            {
+                cout << "EcalDigiAlgShort cannot get SimHitContribution: " << iCont << endl;
+                continue;
+            }
+
+            const 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 - hitcrystal.getPosition();
+            const double disthit = steppos.Mag();
+            const float step_time = conb.getTime();
+
+            m_step_x.emplace_back(steppos.x());
+            m_step_y.emplace_back(steppos.y());
+            m_step_z.emplace_back(steppos.z());
+            m_step_t.emplace_back(step_time);
+            m_step_E.emplace_back(en);
+            m_stepHit_x.emplace_back(hitcrystal.getPosition().x());
+            m_stepHit_y.emplace_back(hitcrystal.getPosition().y());
+            m_stepHit_z.emplace_back(hitcrystal.getPosition().z());
+
+            if (_Debug >= 3)
+            {
+                cout << "Cell: " << hitcrystal.getModule() << "  " << hitcrystal.getStave() << "  " << hitcrystal.getLayer() << "  " << hitcrystal.getPhiX() << "  " << hitcrystal.getZY() << endl;
+                cout << "Cell position: " << hitcrystal.getPosition().x() << '\t' << hitcrystal.getPosition().y() << '\t' << hitcrystal.getPosition().z() << endl;
+                cout << "Step position: " << steppos.x() << '\t' << steppos.y() << '\t' << steppos.z() << endl;
+                cout << "Relative position: " << rpos.x() << '\t' << rpos.y() << '\t' << rpos.z() << endl;
+            }
+
+            // ####### For Charge Digitisation #######
+            const int sign = (distcrystal >= disthit) ? 1 : -1;
+            const double Ratio = exp(-(0.5 * fEcalCryLen + sign * rpos.Mag()) / Latt);
+            const double Qi = en * Ratio;
+
+            if (_Debug >= 3)
+            {
+                cout << Qi << endl;
+                cout << sign * rpos.Mag() << endl;
+            }
+
+            totQ_Truth += Qi;
+
+            // ####### For Time Digitisation #######
+            double Ti = -1;
+            int looptime = 0;
+            while (Ti < 0)
+            {
+                Ti = Tinit + rndm.Gaus(nMat * (0.5 * fEcalCryLen + sign * rpos.Mag()) / C, Tres) + step_time;
+                ++looptime;
+                if (looptime > 500)
+                {
+                    cout << "ERROR: Time for step " << iCont << " is not positive!" << endl;
+                    break;
+                }
+            }
+            if (looptime > 500)
+                continue;
+
+            m_step_T.emplace_back(Ti);
+            totQ += Qi;
+
+            HitStep stepout;
+            stepout.setQ(Qi);
+            stepout.setT(Ti);
+            Digivec.emplace_back(stepout);
+        }
+
+        // #######################################
+        // ####### Ideal Time Digitisation #######
+        // #######################################
+
+        sort(Digivec.begin(), Digivec.end());
+        double thQ = 0;
+        double thT;
+        for (int iCont = 0; iCont < Digivec.size(); ++iCont)
+        {
+            thQ += Digivec[iCont].getQ();
+            if (thQ > totQ * _Qthfrac)
+            {
+                thT = Digivec[iCont].getT();
+                if (_Debug >= 3)
+                    cout << "T at index " << iCont << ": " << thT << endl;
+                break;
+            }
+        }
+
+        if (_UseRelDigi)
+        {
+            // #############################################
+            // ####### Realistic Charge Digitisation #######
+            // #############################################
+
+//            const double sEcalCryMipLY = rndm.Gaus(fEcalCryMipLY, 0.1 * fEcalCryMipLY);
+            const double sEcalCryMipLY = fEcalCryMipLY;
+
+            // TODO: fEcalMIPEnergy should depend on crystal size.
+            const int ScinGen = round(rndm.Poisson(totQ_Truth * 1000 / fEcalMIPEnergy * sEcalCryMipLY));
+
+            totQ_Digi = 0.001 * EnergyDigi(ScinGen, sEcalCryMipLY);
+        }
+        else
+        {
+            if (totQ_Truth != 0)
+                totQ_Digi = totQ_Truth;
+            if (totQ_Digi / fEcalMIPEnergy < fEcalMIP_Thre)
+                totQ_Digi = 0;
+        }
+
+        if (totQ_Digi == 0)
+            continue;
+
+        hitcrystal.setQ(totQ_Digi);
+        hitcrystal.setT(thT);
+
+        // ##################################
+        // ####### Some associations  #######
+        // ##################################
+
+        // 2 hits with double-readout time.
+        edm4hep::Vector3f m_pos(hitcrystal.getPosition().X(), hitcrystal.getPosition().Y(), hitcrystal.getPosition().Z());
+        auto digiHit = caloVec->create();
+        digiHit.setCellID(hitcrystal.getcellID());
+        digiHit.setEnergy(hitcrystal.getQ());
+        digiHit.setTime(hitcrystal.getT());
+        digiHit.setPosition(m_pos);
+
+        // SimHit - CaloHit association
+        auto rel = caloAssoVec->create();
+        rel.setRec(digiHit);
+        rel.setSim(SimHit);
+        rel.setWeight(1.0);
+
+        // 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_MCP = caloMCPAssoVec->create();
+            rel_MCP.setRec(digiHit);
+            rel_MCP.setSim(iter.first);
+            rel_MCP.setWeight(iter.second / SimHit.getEnergy());
+        }
+
+//        if (selMCP.isAvailable())
+//        {
+//            auto rel_MCP = caloMCPAssoVec->create();
+//            rel_MCP.setRec(digiHit);
+//            rel_MCP.setSim(selMCP);
+//            rel_MCP.setWeight(1.0);
+//        }
+
+        // ##################################
+        // ####### Writing into trees #######
+        // ##################################
+
+        m_hitCol.emplace_back(hitcrystal);
+        if (hitcrystal.getQ() > 0)
+            totE_Digi += hitcrystal.getQ();
+        if (totQ_Truth > 0.001 * fEcalMIPEnergy * fEcalMIP_Thre)
+            totE_Truth += totQ_Truth;
+
+        if (_writeNtuple)
+        {
+            m_simHit_x.emplace_back(hitcrystal.getPosition().x());
+            m_simHit_y.emplace_back(hitcrystal.getPosition().y());
+            m_simHit_z.emplace_back(hitcrystal.getPosition().z());
+            m_simHit_Q_Truth.emplace_back(totQ_Truth);
+            m_simHit_Q_Digi.emplace_back(hitcrystal.getQ());
+            m_simHit_T.emplace_back(hitcrystal.getT());
+            m_simHit_module.emplace_back(hitcrystal.getModule());
+            m_simHit_stave.emplace_back(hitcrystal.getStave());
+            m_simHit_layer.emplace_back(hitcrystal.getLayer());
+            m_simHit_phi_x.emplace_back(hitcrystal.getPhiX());
+            m_simHit_z_y.emplace_back(hitcrystal.getZY());
+            m_simHit_cellID.emplace_back(hitcrystal.getcellID());
+        }
+    }
+
+    if (_writeNtuple)
+    {
+        t_SimCont->Fill();
+        t_SimHit->Fill();
+    }
+
+    if (_Debug >= 1)
+        cout << "End Loop: Hit Digitisation" << endl;
+
+    cout << "Total Truth Energy: " << totE_Truth << endl;
+    cout << "Total Digitised Energy: " << totE_Digi << endl;
+
+    ++_nEvt;
+    m_simhitCol.clear();
+    return StatusCode::SUCCESS;
+}
+
+StatusCode EcalDigiAlgShort::finalize()
+{
+    if (_writeNtuple)
+    {
+        m_wfile->cd();
+        t_SimCont->Write();
+        t_SimHit->Write();
+        m_wfile->Close();
+        delete m_wfile;
+    }
+
+    info() << "Processed " << _nEvt << " events " << endmsg;
+    delete m_cellIDConverter;
+    return GaudiAlgorithm::finalize();
+}
+
+StatusCode EcalDigiAlgShort::MergeHits(const edm4hep::SimCalorimeterHitCollection& m_col, vector<edm4hep::SimCalorimeterHit>& m_hits)
+{
+    m_hits.clear();
+    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();
+        Position hitpos = m_cellIDConverter->position(cellid);
+        edm4hep::Vector3f pos(10 * hitpos.x(), 10 * hitpos.y(), 10 * hitpos.z());
+
+        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.emplace_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.emplace_back(constsimhit);
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+const double EcalDigiAlgShort::EnergyDigi(const double& ScinGen, const double& sEcalCryMipLY)
+{
+    const Int_t sPix = int(ScinGen);
+
+//    if (sPix / sEcalCryMipLY < fEcalMIP_Thre)
+//        return 0;
+//    return sPix / sEcalCryMipLY * fEcalMIPEnergy;
+
+    // ####### SiPM Saturation  #######
+//    sPix = round(fEcalSiPMPixels * (1 - TMath::Exp(-sPix / fEcalSiPMPixels)));
+
+    // ################################
+    // ####### ADC Digitisation #######
+    // ################################
+
+    Double_t sADCMean = sPix * fEcalChargeADCMean;
+    Double_t sADCSigma = TMath::Sqrt(sPix * fEcalChargeADCSigma * fEcalChargeADCSigma + fEcalNoiseADCSigma * fEcalNoiseADCSigma);
+    Int_t sADC = round(rndm.Gaus(sADCMean, sADCSigma));
+    Double_t sMIP;
+
+    if (sADC <= fADCSwitch)
+    {
+        sADC = round(rndm.Gaus(sADC, fEcalADCError * sADC));
+        sMIP = sADC / fEcalChargeADCMean / sEcalCryMipLY;
+    }
+    else if (sADC > fADCSwitch && int(sADC / fGainRatio_12) <= fADCSwitch)
+    {
+        sADCMean = sPix * fEcalChargeADCMean / fGainRatio_12;
+        sADCSigma = TMath::Sqrt(sPix * fEcalChargeADCSigma / fGainRatio_12 * fEcalChargeADCSigma / fGainRatio_12 + fEcalNoiseADCSigma * fEcalNoiseADCSigma);
+        sADC = round(rndm.Gaus(sADCMean, sADCSigma));
+        sADC = round(rndm.Gaus(sADC, fEcalADCError * sADC));
+        sMIP = sADC / fEcalChargeADCMean * fGainRatio_12 / sEcalCryMipLY;
+    }
+    else
+    {
+        sADCMean = sPix * fEcalChargeADCMean / fGainRatio_12 / fGainRatio_23;
+        sADCSigma = TMath::Sqrt(sPix * fEcalChargeADCSigma / fGainRatio_12 / fGainRatio_23 * fEcalChargeADCSigma / fGainRatio_12 / fGainRatio_23 + fEcalNoiseADCSigma * fEcalNoiseADCSigma);
+        sADC = round(rndm.Gaus(sADCMean, sADCSigma));
+        sADC = round(rndm.Gaus(sADC, fEcalADCError * sADC));
+        if (sADC > fADC - 1)
+            sADC = fADC - 1;
+        sMIP = sADC / fEcalChargeADCMean * fGainRatio_12 * fGainRatio_23 / sEcalCryMipLY;
+    }
+
+    return (sMIP < fEcalMIP_Thre) ? 0 : sMIP * fEcalMIPEnergy;
+}
+
+edm4hep::MutableSimCalorimeterHit EcalDigiAlgShort::find(const 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 EcalDigiAlgShort::Clear()
+{
+    totE_Truth = -99;
+    totE_Digi = -99;
+    m_step_x.clear();
+    m_step_y.clear();
+    m_step_z.clear();
+    m_step_t.clear();
+    m_step_E.clear();
+    m_stepHit_x.clear();
+    m_stepHit_y.clear();
+    m_stepHit_z.clear();
+    m_step_T.clear();
+    m_simHit_x.clear();
+    m_simHit_y.clear();
+    m_simHit_z.clear();
+    m_simHit_T.clear();
+    m_simHit_Q_Truth.clear();
+    m_simHit_Q_Digi.clear();
+    m_simHit_module.clear();
+    m_simHit_stave.clear();
+    m_simHit_layer.clear();
+    m_simHit_phi_x.clear();
+    m_simHit_z_y.clear();
+    m_simHit_cellID.clear();
+}
diff --git a/Digitization/DigiCalo/src/EcalDigiAlgShort.h b/Digitization/DigiCalo/src/EcalDigiAlgShort.h
new file mode 100644
index 00000000..8e4effd5
--- /dev/null
+++ b/Digitization/DigiCalo/src/EcalDigiAlgShort.h
@@ -0,0 +1,137 @@
+#ifndef _ECAL_DIGI_ALG_SHORT_H
+#define _ECAL_DIGI_ALG_SHORT_H
+
+#include "k4FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "edm4hep/MutableCaloHitContribution.h"
+#include "edm4hep/MutableSimCalorimeterHit.h"
+#include "edm4hep/CalorimeterHit.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/Cluster.h"
+#include "edm4hep/SimCalorimeterHit.h"
+#include "edm4hep/SimCalorimeterHitCollection.h"
+#include "edm4hep/MCRecoCaloAssociationCollection.h"
+#include "edm4hep/MCRecoCaloParticleAssociationCollection.h"
+#include "edm4hep/Vector3f.h"
+
+#include <DDRec/DetectorData.h>
+#include <DDRec/CellIDPositionConverter.h>
+#include <DD4hep/Detector.h>
+#include <DD4hep/Objects.h>
+#include <DD4hep/Segmentations.h>
+#include "DetInterface/IGeomSvc.h"
+
+#include "TVector3.h"
+#include "TRandom3.h"
+#include "TFile.h"
+#include "TTree.h"
+#include "TString.h"
+#include "TMath.h"
+#include "TH3.h"
+#include "TH1.h"
+
+#include <iostream>
+#include <algorithm>
+#include <map>
+#include <random>
+#include <math.h>
+#include <cmath>
+#include <cstdlib>
+#include <TTimeStamp.h>
+#include <ctime>
+#include "time.h"
+
+#include "HitStep.h"
+#include "CaloCrystalShort.h"
+
+const double C = 299.79;    // In mm/ns
+const double PI = 3.141592653;
+
+class EcalDigiAlgShort : public GaudiAlgorithm
+{
+public:
+    EcalDigiAlgShort(const std::string& name, ISvcLocator* svcLoc);
+
+    virtual StatusCode initialize();
+
+    virtual StatusCode execute();
+
+    virtual StatusCode finalize();
+
+    StatusCode MergeHits(const edm4hep::SimCalorimeterHitCollection& m_col, std::vector<edm4hep::SimCalorimeterHit>& m_hits);
+
+    edm4hep::MutableSimCalorimeterHit find(const std::vector<edm4hep::MutableSimCalorimeterHit>& m_col, unsigned long long& cellid) const;
+
+    const double EnergyDigi(const double& ScinGen, const double& sEcalCryMipLY);
+
+    void Clear();
+
+protected:
+    std::string algname;
+    int dettype;    // 1 for barrel, 2 for end-cap.
+    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_SimHit;
+
+    double totE_Truth, totE_Digi;
+    FloatVec m_step_t;
+    FloatVec m_step_x, m_step_y, m_step_z, m_step_E, m_step_T, m_stepHit_x, m_stepHit_y, m_stepHit_z;
+    FloatVec m_simHit_x, m_simHit_y, m_simHit_z, m_simHit_T, m_simHit_Q_Truth, m_simHit_Q_Digi, m_simHit_module, m_simHit_stave, m_simHit_layer;
+    FloatVec m_simHit_phi_x, m_simHit_z_y;    // Phi and z for barrel, x and y for end-cap
+    std::vector<unsigned long long> m_simHit_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<int> _seed{this, "Seed", 2024, "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 counts"};
+    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> fEcalCryLen{this, "EcalCryLen", 41, "Crystal length (mm)"};
+    mutable Gaudi::Property<float> fEcalCryMipLY{this, "EcalCryMipLY", 200, "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 pe for Gain-1 (ADC)"};
+    mutable Gaudi::Property<float> fEcalChargeADCSigma{this, "EcalChargeADCSigma", 2.5, "Sigma of ADC per pe 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/Digitization/DigiCalo/src/HcalDigiAlg.cpp b/Digitization/DigiCalo/src/HcalDigiAlg.cpp
index d0d65cac..4650ebe5 100644
--- a/Digitization/DigiCalo/src/HcalDigiAlg.cpp
+++ b/Digitization/DigiCalo/src/HcalDigiAlg.cpp
@@ -35,23 +35,68 @@ HcalDigiAlg::HcalDigiAlg(const std::string& name, ISvcLocator* svcLoc)
 {
   
 	// Input collections
-	declareProperty("SimCaloHitCollection", r_SimCaloCol, "Handle of the Input SimCaloHit collection");
+  declareProperty("MCParticle",  m_MCParticleCol, "MCParticle collection (input)");
+	//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"); 
+	//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()
 {
+  // --- Initialize input and output collections
+  for(auto& simhit : name_SimCaloHit){
+    if(!simhit.empty())
+     _inputSimHitCollection.push_back( new SimCaloType(simhit, Gaudi::DataHandle::Reader, this) );
+  }
+
+  // --- Geometry service, cellID decoder
+  m_geosvc = service<IGeomSvc>("GeomSvc");
+  if ( !m_geosvc )  throw "HcalDigiAlg :Failed to find GeomSvc ...";
+  m_dd4hep = m_geosvc->lcdd();
+  if ( !m_dd4hep )  throw "HcalDigiAlg :Failed to get dd4hep::Detector ...";
+  m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep);
+
+  for(unsigned int i=0; i<name_Readout.size(); i++){
+    if(name_Readout[i].empty()) continue;
+    dd4hep::DDSegmentation::BitFieldCoder* tmp_decoder = m_geosvc->getDecoder(name_Readout[i]);
+    if (!tmp_decoder) {
+      error() << "Failed to get the decoder for: " << name_Readout[i] << endmsg;
+      return StatusCode::FAILURE;
+    }
+    map_readout_decoder[name_SimCaloHit[i]] = tmp_decoder;
+  }
+
+  // --- Output collection
+  for(auto& digihit : name_CaloHit){
+    if(!digihit.empty())
+      _outputHitCollection.push_back( new CaloType(digihit, Gaudi::DataHandle::Writer, this) );
+  }
+
+  for(auto& link : name_CaloAsso){
+    if(!link.empty())
+      _outputCaloSimAssoCol.push_back( new CaloSimAssoType(link, Gaudi::DataHandle::Writer, this) );
+  }
+
+  for(auto& link : name_CaloMCPAsso){
+    if(!link.empty())
+      _outputCaloMCPAssoCol.push_back( new CaloParticleAssoType(link, Gaudi::DataHandle::Writer, this) );
+  }  
+
+
   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("MC_EPx", &m_MC_EPx);
+    t_simHit->Branch("MC_EPy", &m_MC_EPy);
+    t_simHit->Branch("MC_EPz", &m_MC_EPz);
     t_simHit->Branch("totE", &m_totE);
+    t_simHit->Branch("totE_truth", &m_totE_truth);
     t_simHit->Branch("simHit_x", &m_simHit_x);
     t_simHit->Branch("simHit_y", &m_simHit_y);
     t_simHit->Branch("simHit_z", &m_simHit_z);
@@ -64,26 +109,44 @@ StatusCode HcalDigiAlg::initialize()
     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("step_x", &m_step_x);
+    t_simHit->Branch("step_y", &m_step_y);
+    t_simHit->Branch("step_LY", &m_step_LY);
     
-    t_simHit->Branch("simHit_module", &m_simHit_module);
+    t_simHit->Branch("simHit_system", &m_simHit_system);
     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_tile", &m_simHit_tile);
+    t_simHit->Branch("simHit_idx", &m_simHit_idx);
+    t_simHit->Branch("simHit_idy", &m_simHit_idy);
+    t_simHit->Branch("simHit_row", &m_simHit_row);
+    t_simHit->Branch("simHit_phi", &m_simHit_phi);
     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;
-	}
 
+  //Glass tile non-uniformity map (due to attenuation length)
+  TFile* map_file = new TFile(_TileLYMapFile.value().c_str(), "read");
+  TString s_hitmap = TString("hitmap_") + TString(_EffAttenLength.value().c_str());
+  GSTileResMap = (TH2D*)map_file->Get(s_hitmap);
+  if(!GSTileResMap || !_UseTileLYMap ){
+    error() << "HcalDigiAlg: Failed to get the GS tile response map. Create a uniform one" << endmsg;
+    GSTileResMap = new TH2D("hitmap", "", 80, -20, 20, 80, -20, 20);
+    for(int i=0; i<80; i++){
+      for(int j=0; j<80; j++){
+        GSTileResMap->SetBinContent(i+1, j+1, _MIPLY );
+    }}
+  }
+  else{
+    //Scale map to light yield
+    TString s_h_Npe = TString("h_Npe_") + TString(_EffAttenLength.value().c_str());
+    TH1D *h_Npe = (TH1D*)map_file->Get(s_h_Npe);
+    h_Npe->Fit("landau","Q");
+    GSTileResMap->Scale( _MIPLY / h_Npe->GetFunction("landau")->GetParameter(1) );
+  }
+
+  //SiPM dark noise cross talk model: Borel distribution.
+  f_DarkNoise = new TF1("f_DarkNoise", "pow([0]*x, x-1) * exp(-[0]*x) / TMath::Factorial(x)");
+  f_DarkNoise->SetParameter(0, _SiPMXTalk);
 
 	rndm.SetSeed(_seed);
 	std::cout<<"HcalDigiAlg::initialize"<<std::endl;
@@ -101,147 +164,287 @@ StatusCode HcalDigiAlg::execute()
 
 	Clear();
   m_totE = 0.;
- 	const edm4hep::SimCalorimeterHitCollection* SimHitCol =  r_SimCaloCol.get();
-  std::vector<edm4hep::SimCalorimeterHit> m_simhitCol; m_simhitCol.clear();
-
-	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;
-
-  MergeHits(*SimHitCol, m_simhitCol);
-
-  for(int isim=0; isim<m_simhitCol.size(); isim++){
-
-    auto simhit = m_simhitCol.at(isim);
-    if(!simhit.isAvailable()) continue;
-    if(simhit.getEnergy()==0) continue;
-
-    unsigned long long id = simhit.getCellID();
-    edm4hep::Vector3f hitpos = simhit.getPosition();
-    TVector3 tilepos(hitpos.x, hitpos.y, hitpos.z); //cm to mm.    
-
-    //Loop G4 steps to get the attenuated light yield.
-    double Ehit_truth = 0.;
-    double Ehit = 0.;
-    for(int iCont=0; iCont < simhit.contributions_size(); ++iCont){
-      auto conb = simhit.getContributions(iCont);
-      if( !conb.isAvailable() ) { std::cout<<" Can not get SimHitContribution: "<<iCont<<std::endl; continue;}
-      TVector3 steppos(conb.getStepPosition().x, conb.getStepPosition().y, conb.getStepPosition().z);
-
-      double _distance = (tilepos-steppos).Mag(); //Simplified: use R(step-center) not R(step-SiPM) as distance. 
-      Ehit_truth += conb.getEnergy();
-      Ehit += conb.getEnergy()*exp(-1.*_distance/_EffAttenLength);
-    }
-    double Ehit_att = Ehit;
-
-    double sChargeOut = 0;
-    double sChargeOutHG = 0;
-    double sChargeOutLG = 0;
-    double Npe_scint = 0;
-    double Npe_SiPM = 0;
-    //Digitization
-    if(_UseRelDigi){
-      // -- Scintillation (Energy -> MIP -> Np.e.)
-      int sPix = gRandom->Poisson(Ehit / _MIPCali * (_MIPADC / _PeADCMean));
-      Npe_scint = sPix;
-      // -- 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)));
-      Npe_SiPM = sPix;
-      // -- ADC response (Npixel -> ADC)
-      double sChargeMean = sPix * _PeADCMean;
-      double sChargeSigma = sqrt(sPix * _PeADCSigma * _PeADCSigma);
-      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)
+  m_totE_truth = 0.;
+  for(int icol=0; icol<_inputSimHitCollection.size(); icol++){
+    try{
+      SimCaloType* r_SimCaloCol = _inputSimHitCollection[icol];
+      CaloType* w_DigiCaloCol = _outputHitCollection[icol];
+      CaloSimAssoType* w_CaloAssociationCol = _outputCaloSimAssoCol[icol];
+      CaloParticleAssoType* w_MCPCaloAssociationCol = _outputCaloMCPAssoCol[icol];
+
+      const edm4hep::MCParticleCollection* const_MCPCol = m_MCParticleCol.get();
+      const edm4hep::SimCalorimeterHitCollection* SimHitCol =  r_SimCaloCol->get();
+      std::vector<edm4hep::SimCalorimeterHit> m_simhitCol; m_simhitCol.clear();
+      
+      edm4hep::CalorimeterHitCollection* caloVec = w_DigiCaloCol->createAndPut();
+      edm4hep::MCRecoCaloAssociationCollection* caloAssoVec = w_CaloAssociationCol->createAndPut();
+      edm4hep::MCRecoCaloParticleAssociationCollection* caloMCPAssoVec = w_MCPCaloAssociationCol->createAndPut(); 
+      
+      if(const_MCPCol){
+        int N_MCP = const_MCPCol->size();
+        if(N_MCP==1){
+          m_MC_EPx = const_MCPCol->at(0).getEndpoint().x;
+          m_MC_EPy = const_MCPCol->at(0).getEndpoint().y;
+          m_MC_EPz = const_MCPCol->at(0).getEndpoint().z;
+        }
+      }
+      
+      
+      if(SimHitCol == 0) 
       {
-          sMIP = (sChargeOutLG - _BaselineLG) * _HLRatio / _MIPADC;
-          sChargeOutHG = _ADCSwitch;
+      	std::cout<<"not found SimCalorimeterHitCollection"<< std::endl;
+      	return StatusCode::SUCCESS;
       }
-      else
+      
+      //Mean cross talk probability in this event
+      double mean_CT = 0;
+      for (int i = 1; i < 10; i++)
       {
-          sMIP = (sChargeOutHG - _BaselineHG) / _MIPADC;
+        mean_CT += (i-1)*f_DarkNoise->Eval(i);
       }
-      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_Etruth.push_back(Ehit_truth);
-      m_simHit_Eatt.push_back(Ehit_att);
-      m_simHit_rawQ.push_back(sChargeOut);
-      m_simHit_HG.push_back(sChargeOutHG);
-      m_simHit_LG.push_back(sChargeOutLG);
-      m_simHit_Npe_scint.push_back(Npe_scint);
-      m_simHit_Npe_sipm.push_back(Npe_SiPM);
-      m_simHit_steps.push_back(simhit.contributions_size());
-      //m_simHit_module.push_back(m_decoder->get(id, "stave"));
-      //m_simHit_stave.push_back(m_decoder->get(id, "layer"));
-      //m_simHit_layer.push_back(m_decoder->get(id, "tile"));
-      //m_simHit_slice.push_back(m_decoder->get(id, "x"));
-      //m_simHit_tower.push_back(m_decoder->get(id, "y"));
-      m_simHit_cellID.push_back(id);
+      MergeHits(*SimHitCol, m_simhitCol);
+//cout<<"Merged simhit size: "<<m_simhitCol.size()<<endl;      
+      for(int isim=0; isim<m_simhitCol.size(); isim++){
+      
+        auto simhit = m_simhitCol.at(isim);
+        if(!simhit.isAvailable()) {cout<<"Sim hit is not available"<<endl; continue;}
+        if(simhit.getEnergy()==0) {cout<<"Sim hit energy is 0"<<endl; continue;}
+        m_totE_truth += simhit.getEnergy();
+      
+        unsigned long long id = simhit.getCellID();
+        int hit_system =  map_readout_decoder[name_Readout[icol]]->get(id, "system");
+        edm4hep::Vector3f hitpos = simhit.getPosition();
+        TVector3 tilepos(hitpos.x, hitpos.y, hitpos.z); //cm to mm.    
+        double rotPhi = 0;
+        if(hit_system==22){
+          int hit_stave = map_readout_decoder[name_Readout[icol]]->get(id, "stave");
+          rotPhi = (hit_stave-5)*TMath::TwoPi()/16.;
+          if(rotPhi<0) rotPhi += TMath::TwoPi();
+        }
+//cout<<"  Sim hit #"<<isim<<": system "<<hit_system<<", energy "<<simhit.getEnergy();      
+        //printf("Hit #%d: stave %d, pos (%.2f, %.2f, %.2f), Energy %.2f, step size %d \n", isim, hit_stave, hitpos.x, hitpos.y, hitpos.z, simhit.getEnergy(), simhit.contributions_size());
+        //Loop G4 steps to get the attenuated light yield.
+        double Ehit = 0;
+        double Ehit_truth = 0.;
+        double Npe_att = 0;
+        float tempVar = gRandom->Gaus(0, _TempVariation);
+        float fLY_tempScale = (1 + tempVar * _TempCoef);
+        for(int iCont=0; iCont < simhit.contributions_size(); ++iCont){
+          auto conb = simhit.getContributions(iCont);
+          if( !conb.isAvailable() ) { std::cout<<" Can not get SimHitContribution: "<<iCont<<std::endl; continue;}
+          Ehit_truth += conb.getEnergy();
+          TVector3 steppos(conb.getStepPosition().x, conb.getStepPosition().y, conb.getStepPosition().z);
+      
+          //double _distance = (tilepos-steppos).Mag(); //Simplified: use R(step-center) not R(step-SiPM) as distance. 
+          //m_step_R.push_back(_distance);
+          int ibinx = 0;
+          int ibiny = 0;
+          if(hit_system==22){
+            TVector3 rot_tilepos = tilepos; rot_tilepos.RotateZ(rotPhi);
+            TVector3 rot_steppos = steppos; rot_steppos.RotateZ(rotPhi);
+            ibinx = ((rot_steppos-rot_tilepos).z()+20.)*2;
+            ibiny = ((rot_steppos-rot_tilepos).y()+20.)*2;
+            if(ibinx<0) ibinx = 0;
+            if(ibiny<0) ibiny = 0;
+            if(ibinx>79) ibinx = 79;
+            if(ibiny>79) ibiny = 79;
+            m_step_x.push_back((rot_steppos-rot_tilepos).z());
+            m_step_y.push_back((rot_steppos-rot_tilepos).y());
+          }
+          else if(hit_system==30){
+            if(ibinx<0) ibinx = 0;
+            if(ibiny<0) ibiny = 0;
+            if(ibinx>79) ibinx = 79;
+            if(ibiny>79) ibiny = 79;
+            ibinx = ((steppos-tilepos).x()+20.)*2;
+            ibiny = ((steppos-tilepos).y()+20.)*2;
+            m_step_x.push_back((steppos-tilepos).x());
+            m_step_y.push_back((steppos-tilepos).y());
+          }
+          else error() << "Wrong cellID system: " << hit_system << endmsg;
+      //printf("  Step #%d: En %.2f, rotate angle %.2f, tile pos after rotation (%.2f, %.2f, %.2f), ", iCont, conb.getEnergy(), rotPhi, rot_tilepos.x(), rot_tilepos.y(), rot_tilepos.z());
+      //printf("rel pos after rotation (%.2f, %.2f, %.2f) \n", (rot_steppos-rot_tilepos).x(), (rot_steppos-rot_tilepos).y(), (rot_steppos-rot_tilepos).z());
+      //printf("  Project to bin (%d, %d), LY %.3f \n", ibinx, ibiny, GSTileResMap->GetBinContent( ibinx, ibiny ));
+      
+          m_step_LY.push_back(GSTileResMap->GetBinContent( ibinx, ibiny ));
+        }
+        Ehit = Npe_att / _MIPLY / fLY_tempScale * _MIPCali;
+
+        double sChargeOut = 0;
+        double sChargeOutHG = 0;
+        double sChargeOutLG = 0;
+        double Npe_scint = 0;
+        double Npe_SiPM = 0;
+        //Digitization
+        if(_UseRelDigi){
+          // -- Scintillation (Energy -> MIP -> Np.e.)
+          float fSiPMGainMean = _SiPMGainMean * (1 + tempVar * _SiPMGainTempCoef);
+          float fSiPMDCR = _SiPMDCR * pow(10, _SiPMDCRTempCoef * tempVar);
+
+          // -- Scintillation (Energy -> MIP -> Np.e.)
+          int sPix = gRandom->Poisson(Npe_att);
+          Npe_scint = sPix;      
+          // -- SiPM dark noise and cross talk
+          int darkcounts_mean = gRandom->Poisson(_SiPMDCR * _TimeInterval);
+          int darkcounts_CT = 0;
+          for(int i=0;i<darkcounts_mean;i++)
+          {
+            double darkcounts_rdm = gRandom->Uniform(0, 1);
+            int sum_darkcounts = 1;
+            if(! (darkcounts_rdm <= f_DarkNoise->Eval(sum_darkcounts)))
+            {
+              float prob = f_DarkNoise->Eval(sum_darkcounts);
+              while(darkcounts_rdm > prob)
+              {
+                sum_darkcounts++;
+                prob += f_DarkNoise->Eval(sum_darkcounts);
+              }
+            }
+            darkcounts_CT += sum_darkcounts;
+          }
+          sPix += darkcounts_CT;      
+      
+          // -- SiPM Saturation (Np.e. -> Npixel)
+          sPix = std::round(_Pixel * (1.0 - TMath::Exp(-sPix * 1.0 / _Pixel)));
+          Npe_SiPM = sPix;
+          // -- ADC response (Npixel -> ADC)
+          float sSiPMGainMean = fSiPMGainMean;
+          float sSiPMGainSigma = sSiPMGainMean * _SiPMGainSigma;
+          float sSiPMNoiseSigma = _SiPMNoiseSigma;
+
+          float sADCMean = sPix * sSiPMGainMean + _Pedestal;
+          float sADCSigma = std::sqrt(sPix * sSiPMGainSigma * sSiPMGainSigma + sSiPMNoiseSigma * sSiPMNoiseSigma + _PedestalNoiseSigma * _PedestalNoiseSigma);
+          float sADC = -1;
+          sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma));
+          if(sADC < 0) sADC = 0;
+          sChargeOut = sADC;
+          if(sADC <= _ADCSwitch) //Gain 1
+          {
+
+            float sMIP = (sADC - _Pedestal) / _SiPMGainMean / _MIPLY / fLY_tempScale;
+            if(sMIP < _Eth_Mip) Ehit = 0;
+            Ehit = sMIP * _MIPCali;
+          }
+          else if(sADC > _ADCSwitch && int(sADC/_GainRatio_12) <= _ADCSwitch)
+          {
+            //Use_G2 = kTRUE;
+            sSiPMGainMean = fSiPMGainMean / _GainRatio_12;
+            sSiPMGainSigma = sSiPMGainMean * _SiPMGainSigma;
+            sSiPMNoiseSigma = _SiPMNoiseSigma / _GainRatio_12;
+
+            sADCMean = sPix * sSiPMGainMean + _Pedestal;
+            sADCSigma = std::sqrt(sPix * sSiPMGainSigma * sSiPMGainSigma + sSiPMNoiseSigma * sSiPMNoiseSigma + _PedestalNoiseSigma * _PedestalNoiseSigma);
+            sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma));
+            if(sADC < 0) sADC = 0;
+            sChargeOutHG = sADC;
+
+            // float sCaliGainMean = gRandom->Gaus(_SiPMGainMean, fSiPMGainUn * _SiPMGainMean);
+            // float sMIP = (sADC - _Pedestal) / sCaliGainMean / _MIPLY;
+            float sMIP = (sADC - _Pedestal) / _SiPMGainMean / _MIPLY / fLY_tempScale * _GainRatio_12;
+            if(sMIP < _Eth_Mip) Ehit = 0;
+            else Ehit = sMIP * _MIPCali;
+          }
+          else if(int(sADC/_GainRatio_12) > _ADCSwitch)
+          {
+            sSiPMGainMean = fSiPMGainMean / _GainRatio_12 / _GainRatio_23;
+            sSiPMGainSigma = sSiPMGainMean * _SiPMGainSigma;
+            sSiPMNoiseSigma = _SiPMNoiseSigma / _GainRatio_12 / _GainRatio_23;
+
+            sADCMean = sPix * sSiPMGainMean + _Pedestal;
+            sADCSigma = std::sqrt(sPix * sSiPMGainSigma * sSiPMGainSigma + sSiPMNoiseSigma * sSiPMNoiseSigma + _PedestalNoiseSigma * _PedestalNoiseSigma);
+            sADC = std::round(gRandom->Gaus(sADCMean, sADCSigma));
+            if(sADC < 0) sADC = 0;
+            sChargeOutLG = sADC;
+
+            // float sCaliGainMean = gRandom->Gaus(_SiPMGainMean, fSiPMGainUn * _SiPMGainMean);
+            // float sMIP = (sADC - _Pedestal) / sCaliGainMean / _MIPLY;
+            float sMIP = (sADC - _Pedestal) / _SiPMGainMean / _MIPLY / fLY_tempScale * _GainRatio_12 * _GainRatio_23;
+            if(sMIP < _Eth_Mip) Ehit = 0;
+            else 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_Etruth.push_back(Ehit_truth);
+          m_simHit_Eatt.push_back(Npe_att);
+          m_simHit_rawQ.push_back(sChargeOut);
+          m_simHit_HG.push_back(sChargeOutHG);
+          m_simHit_LG.push_back(sChargeOutLG);
+          m_simHit_Npe_scint.push_back(Npe_scint);
+          m_simHit_Npe_sipm.push_back(Npe_SiPM);
+          m_simHit_steps.push_back(simhit.contributions_size());
+          m_simHit_system.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "system"));
+          m_simHit_stave.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "stave"));
+          m_simHit_layer.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "layer"));
+          if(hit_system==22){
+            m_simHit_tile.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "tile"));
+            m_simHit_idx.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "x"));
+            m_simHit_idy.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "y"));
+            m_simHit_row.push_back(-1);
+            m_simHit_phi.push_back(-1);
+          }
+          if(hit_system==30){
+            m_simHit_tile.push_back(-1);
+            m_simHit_idx.push_back(-1);
+            m_simHit_idy.push_back(-1);
+            m_simHit_row.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "row"));
+            m_simHit_phi.push_back(map_readout_decoder[name_Readout[icol]]->get(id, "phi"));
+          }
+          m_simHit_cellID.push_back(id);
+        }
+      }
+      m_simhitCol.clear();
+    }catch(GaudiException &e){
+      info()<<"SimCaloHit collection "<<name_SimCaloHit[icol]<<" is not available "<<endmsg;
     }
   }
 
@@ -261,7 +464,9 @@ StatusCode HcalDigiAlg::finalize()
   }
 
 	info() << "Processed " << _nEvt << " events " << endmsg;
-	delete m_cellIDConverter, m_decoder, m_geosvc;
+  map_readout_decoder.clear();
+	delete m_cellIDConverter, m_geosvc;
+  delete f_DarkNoise, GSTileResMap;
 	return GaudiAlgorithm::finalize();
 }
 
@@ -317,7 +522,11 @@ edm4hep::MutableSimCalorimeterHit HcalDigiAlg::find(const std::vector<edm4hep::M
 }
 
 void HcalDigiAlg::Clear(){
+  m_MC_EPx = 0;
+  m_MC_EPy = 0;
+  m_MC_EPz = 0;
   m_totE = -99;
+  m_totE_truth = -99;
   m_simHit_x.clear();
   m_simHit_y.clear();
   m_simHit_z.clear();
@@ -330,11 +539,17 @@ void HcalDigiAlg::Clear(){
   m_simHit_Npe_scint.clear();
   m_simHit_Npe_sipm.clear();
   m_simHit_steps.clear();
-  m_simHit_module.clear();
+  m_simHit_system.clear();
   m_simHit_stave.clear();
   m_simHit_layer.clear();
-  m_simHit_slice.clear();
-  m_simHit_tower.clear();
+  m_simHit_tile.clear();
+  m_simHit_idx.clear();
+  m_simHit_idy.clear();
+  m_simHit_row.clear();
+  m_simHit_phi.clear();
   m_simHit_cellID.clear();
+  m_step_x.clear();
+  m_step_y.clear();
+  m_step_LY.clear();
 }
 
diff --git a/Digitization/DigiCalo/src/HcalDigiAlg.h b/Digitization/DigiCalo/src/HcalDigiAlg.h
index 5043488e..4acc9a39 100644
--- a/Digitization/DigiCalo/src/HcalDigiAlg.h
+++ b/Digitization/DigiCalo/src/HcalDigiAlg.h
@@ -3,6 +3,7 @@
 
 #include "k4FWCore/DataHandle.h"
 #include "GaudiAlg/GaudiAlgorithm.h"
+#include "edm4hep/MCParticleCollection.h"
 #include "edm4hep/MutableCaloHitContribution.h"
 #include "edm4hep/MutableSimCalorimeterHit.h"
 #include "edm4hep/SimCalorimeterHit.h"
@@ -22,7 +23,9 @@
 #include "TFile.h"
 #include "TString.h"
 #include "TH3.h"
+#include "TH2.h"
 #include "TH1.h"
+#include "TF1.h"
 
 #include <cstdlib>
 #include "time.h"
@@ -67,53 +70,91 @@ protected:
 	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_Etruth, m_simHit_Eatt, m_simHit_slice, m_simHit_layer, m_simHit_tower, m_simHit_stave, m_simHit_module, m_simHit_HG, m_simHit_LG, m_simHit_rawQ, m_simHit_Npe_scint, m_simHit_Npe_sipm;
+  TH2D* GSTileResMap; 
+
+  double m_totE, m_totE_truth;
+  double m_MC_EPx, m_MC_EPy, m_MC_EPz;
+	FloatVec m_simHit_x, m_simHit_y, m_simHit_z, m_simHit_E, m_simHit_Etruth, m_simHit_Eatt, 
+           m_simHit_system, m_simHit_stave, m_simHit_layer, m_simHit_tile, m_simHit_idx, m_simHit_idy, m_simHit_row, m_simHit_phi, 
+           m_simHit_HG, m_simHit_LG, m_simHit_rawQ, m_simHit_Npe_scint, m_simHit_Npe_sipm;
+  FloatVec m_step_x, m_step_y, m_step_LY;
   std::vector<unsigned long long> m_simHit_cellID;
   std::vector<int> m_simHit_steps;
 
-
+  dd4hep::Detector* m_dd4hep;
 	dd4hep::rec::CellIDPositionConverter* m_cellIDConverter;
-	dd4hep::DDSegmentation::BitFieldCoder* m_decoder;
+	//dd4hep::DDSegmentation::BitFieldCoder* m_decoder;
+  std::map<std::string, dd4hep::DDSegmentation::BitFieldCoder*> map_readout_decoder;
+
+  TF1* f_DarkNoise = nullptr;
 
 	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"};
+  typedef DataHandle<edm4hep::SimCalorimeterHitCollection>              SimCaloType;
+  typedef DataHandle<edm4hep::CalorimeterHitCollection>                 CaloType;
+  typedef DataHandle<edm4hep::MCRecoCaloAssociationCollection>          CaloSimAssoType;      //Calorimeter - SimCalorimeter
+  typedef DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>  CaloParticleAssoType; //Calorimeter - MCParticle
+
+  Gaudi::Property< std::vector<std::string> > name_SimCaloHit{ this, "SimCaloHitCollection", {"HcalBarrelCollection"} };
+  Gaudi::Property< std::vector<std::string> > name_Readout{ this, "ReadOutName", {"HcalBarrelCollection"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloHit{ this, "CaloHitCollection", {"HCALBarrel"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloAsso{ this, "CaloAssociationCollection", {"HCALBarrelAssoCol"} };
+  Gaudi::Property< std::vector<std::string> > name_CaloMCPAsso{ this, "CaloMCPAssociationCollection", {"HCALBarrelParticleAssoCol"} };
+
+  std::vector<SimCaloType*> _inputSimHitCollection;
+  std::vector<CaloType*> _outputHitCollection;
+  std::vector<CaloSimAssoType*> _outputCaloSimAssoCol;
+  std::vector<CaloParticleAssoType*> _outputCaloMCPAssoCol;
+
+  DataHandle<edm4hep::MCParticleCollection> m_MCParticleCol{"MCParticle", Gaudi::DataHandle::Reader, this};
   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> _EffAttenLength{this,   "EffAttenLength",  20., "Effictive attenuation length (mm)"};
-  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)"};
+  //Scintillation and general
+  mutable Gaudi::Property<float> _MIPCali{this,   "MIPResponse",  0.007126, "MIP response (/GeV)"};
+  mutable Gaudi::Property<float> _MIPLY{this,   "MIPLY",  80, "Detected light yield (p.e./MIP)"};
+  mutable Gaudi::Property<float> _Eth_Mip{this,   "MIPThreshold", 0.1, "Energy Threshold (/MIP)"};
+  mutable Gaudi::Property<float> _TileRes{this,   "TileNonUniformity",  0., "Non-uniformity level of one tile response"};
+
+  mutable Gaudi::Property<int> _UseTileLYMap{this,   "UseTileLYMap",  1., "Use the tile light yield map"};
+  mutable Gaudi::Property<std::string> _TileLYMapFile{this,   "TileLYMapFile",  "", "Use the tile light yield map"};
+  mutable Gaudi::Property<std::string> _EffAttenLength{this,   "EffAttenLength",  "23mm", "Effictive attenuation length (mm)"};
+  mutable Gaudi::Property<float> _TempCoef{this,   "LYTempCoef",  0, "Temperature dependence of light yield (%/K)"};
+
+  //Temperature
+  mutable Gaudi::Property<float> _TempVariation{this,   "TemperatureVariation",  1., "Temperature control variation (K)"};
+
+  //SiPM
+  mutable Gaudi::Property<int>   _Pixel{this,   "SiPMPixel",  57600, "number of SiPM pixels"};
+  mutable Gaudi::Property<float> _SiPMDCR{this,   "SiPMDCR", 1600, "SiPM Dark Count Rate (Hz)"};
+  mutable Gaudi::Property<float> _SiPMXTalk{this,  "SiPMCT", 0.12, "SiPM crosstalk Probability"};
+  mutable Gaudi::Property<float> _TimeInterval{this,  "TimeInterval", 0.000002, "Time interval for one readout (s)"};
+  mutable Gaudi::Property<float> _SiPMGainTempCoef{this,   "SiPMGainTempCoef", -0.03, "Temperature dependence of SiPM gain (%/K)"}; // doi:10.1016/j.nima.2016.09.053
+  mutable Gaudi::Property<float> _SiPMDCRTempCoef{this,   "SiPMDCRTempCoef", 3.34/80, "Temperature dependence of SiPM DCR (10^{k*deltaT})"}; // doi:10.1016/j.nima.2016.09.053
+
+  //ADC
+  mutable Gaudi::Property<int> _ADC{this,   "ADC", 8192, "Total ADC conuts"};
+  mutable Gaudi::Property<int> _ADCSwitch{this,   "ADCSwitch", 8000, "switching point of different gain mode"};
+  mutable Gaudi::Property<float> _GainRatio_12{this,  "GainRatio_12", 50, "Gain-1 over Gain-2"};
+  mutable Gaudi::Property<float> _GainRatio_23{this,  "GainRatio_23", 60, "Gain-2 over Gain-3"};
+  mutable Gaudi::Property<float> _SiPMGainMean{this,    "SiPMGainMean", 2, "SiPM gain: ADC per p.e. for HG (ADC)"};
+  mutable Gaudi::Property<float> _SiPMGainSigma{this,   "SiPMGainSigma", 0.08, "Fluctuation of single photoelctron ADC around the mean value for single device (%)"};
+  mutable Gaudi::Property<float> _SiPMNoiseSigma{this,  "SiPMNoiseSigma", 0, "Sigma of SiPM noise (ADC)"};
+  mutable Gaudi::Property<float> _Pedestal{this,  "Pedestal", 50, "ADC value of pedestal"};
+  mutable Gaudi::Property<float> _PedestalNoiseSigma{this,  "PedestalSigma", 4, "Sigma of electronic noise (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};
+  //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/Reconstruction/RecPFACyber/CMakeLists.txt b/Reconstruction/RecPFACyber/CMakeLists.txt
index 47a099e9..e448bd16 100644
--- a/Reconstruction/RecPFACyber/CMakeLists.txt
+++ b/Reconstruction/RecPFACyber/CMakeLists.txt
@@ -11,6 +11,7 @@ gaudi_add_library(CrystalCaloRecLib
                           src/Objects/HoughObject.cc
                           src/Objects/PFObject.cc
                   LINK    k4FWCore::k4FWCore
+                          ROOT::TMVA
                           GearSvc
                           CrystalEcalSvcLib
                           DetInterface
@@ -21,6 +22,7 @@ gaudi_add_library(CrystalCaloRecLib
                           ${GSL_LIBRARIES}
                           ${LCIO_LIBRARIES}
                           ${ROOT_LIBRARIES}
+                          ${TMVA_LIBRARIES}
                           EDM4HEP::edm4hep EDM4HEP::edm4hepDict
 
 )
diff --git a/Reconstruction/RecPFACyber/include/CyberPFAlg.h b/Reconstruction/RecPFACyber/include/CyberPFAlg.h
index 4406f848..83f1c256 100644
--- a/Reconstruction/RecPFACyber/include/CyberPFAlg.h
+++ b/Reconstruction/RecPFACyber/include/CyberPFAlg.h
@@ -83,6 +83,9 @@ protected:
   SmartIF<IGeomSvc> m_geosvc;
   SmartIF<ICrystalEcalSvc> m_energycorsvc;
   std::map<std::string, dd4hep::DDSegmentation::BitFieldCoder*> map_readout_decoder;
+  dd4hep::Detector* m_dd4hep;
+  dd4hep::rec::CellIDPositionConverter* m_cellIDConverter;
+  dd4hep::VolumeManager m_volumeManager;
 
   //DataCollection: moved into execute() to ensure everything can be cleand after one event. 
   //CyberDataCol     m_DataCol; 
@@ -138,9 +141,15 @@ protected:
   Gaudi::Property<int>    m_Debug{this,   "Debug", 0, "Debug level"};
   Gaudi::Property<int>    m_Nskip{this,   "SkipEvt", 0, "Skip event"};
   Gaudi::Property<std::string>   m_EcalType{this, "EcalType", "BarEcal", "ECAL type"};
-  Gaudi::Property<bool>   m_useTruthTrk{this,   "UseTruthTrack", 1, "Use truth track or reconstructed track"};
-  Gaudi::Property<float>  m_EcalCalib{this,  "EcalGlobalCalib", 1.02, "ECAL global calibration"};
-  Gaudi::Property<float>  m_HcalCalib{this,  "HcalGlobalCalib", 65.,  "HCAL global calibration"};
+  Gaudi::Property<bool>   m_useMCPTrk{this,  "UseMCPTrack", 1, "Use track from MCParticle extrapolation"};
+  Gaudi::Property<bool>   m_useTruthMatchTrk{this,  "UseTruthMatchTrack", 1, "Use track from MCParticle extrapolation"};
+  Gaudi::Property<bool>   m_doCleanTrack{this,  "DoCleanTrack", 1, "Do clean tracks"};
+  Gaudi::Property<std::string>   m_trackIDFile{this,  "TrackIDFile", "", "BDT weight file for track ID"};
+  Gaudi::Property<std::string>   m_trackIDMethod{this,  "TrackIDMethod", "BDTG", "BDT weight file for track ID"};
+  Gaudi::Property<float>  m_EcalChargedCalib{this,  "EcalChargedCalib", 1.26, "ECAL global calibration"};
+  Gaudi::Property<float>  m_HcalChargedCalib{this,  "HcalChargedCalib", 4.,  "HCAL global calibration"};
+  Gaudi::Property<float>  m_EcalNeutralCalib{this,  "EcalNeutralCalib", 1., "ECAL global calibration"};
+  Gaudi::Property<float>  m_HcalNeutralCalib{this,  "HcalNeutralCalib", 4.,  "HCAL global calibration"};
   
   //Algorithms: 
   typedef std::vector<std::string> StringVector;
@@ -176,7 +185,8 @@ protected:
   TTree *t_MCParticle;
   int m_Nmc;
   IntVec m_mcPdgid, m_mcStatus;
-  FloatVec m_mcPx, m_mcPy, m_mcPz, m_mcEn, m_mcMass, m_mcCharge, m_mcEPx, m_mcEPy, m_mcEPz, m_depEn_ecal, m_depEn_hcal;
+  FloatVec m_mcPx, m_mcPy, m_mcPz, m_mcEn, m_mcMass, m_mcCharge;
+  FloatVec m_mcVTXx, m_mcVTXy, m_mcVTXz, m_mcEPx, m_mcEPy, m_mcEPz, m_depEn_ecal, m_depEn_hcal;
 
   //Raw bars and hits
   TTree* t_SimBar;
@@ -290,7 +300,7 @@ protected:
   int m_Ntrk; 
   FloatVec m_trkstate_d0, m_trkstate_z0, m_trkstate_phi, m_trkstate_tanL, m_trkstate_omega, m_trkstate_kappa;
   FloatVec m_trkstate_refx, m_trkstate_refy, m_trkstate_refz; 
-  IntVec m_trkstate_tag, m_trkstate_location, m_type;
+  IntVec m_trkstate_tag, m_trkstate_location, m_type, m_Nhit;
   FloatVec m_trkstate_x_ECAL, m_trkstate_y_ECAL, m_trkstate_z_ECAL,  m_trkstate_x_HCAL, m_trkstate_y_HCAL, m_trkstate_z_HCAL;
   IntVec m_trkstate_tag_ECAL, m_trkstate_tag_HCAL;
 
diff --git a/Reconstruction/RecPFACyber/include/Objects/Calo2DCluster.h b/Reconstruction/RecPFACyber/include/Objects/Calo2DCluster.h
index 796bb274..e73719e1 100644
--- a/Reconstruction/RecPFACyber/include/Objects/Calo2DCluster.h
+++ b/Reconstruction/RecPFACyber/include/Objects/Calo2DCluster.h
@@ -10,7 +10,7 @@ namespace Cyber {
   class CaloHit;
   class Calo2DCluster {
   public: 
-    Calo2DCluster() {};
+    Calo2DCluster() { pos.SetXYZ(0., 0., 0.); };
     ~Calo2DCluster() { Clear(); };
 
     void Clear();
@@ -49,10 +49,13 @@ namespace Cyber {
     void addTowerID(int _m, int _p, int _s) { std::vector<int> id(3); id[0] = _m; id[1] = _p; id[2] = _s; towerID.push_back(id); }
     void addTowerID(std::vector<int> id) { towerID.push_back(id); }
     void setTowerID(std::vector<int> id) { towerID.clear(); towerID.push_back(id); }
+    void setPos( TVector3 _vec ) { pos = _vec; }
+    void setPos( double _x, double _y, double _z ) { pos.SetXYZ(_x, _y, _z); }
 
   private:
     std::vector< std::vector<int> > towerID; //[module, stave]
 
+    TVector3 pos = TVector3(0.,0.,0.);
     std::vector<const CaloHit*> hits; 
     std::vector<const CaloUnit*> barUCol;  //slayer == 0.
     std::vector<const CaloUnit*> barVCol;  //slayer == 1.
diff --git a/Reconstruction/RecPFACyber/include/Objects/Calo3DCluster.h b/Reconstruction/RecPFACyber/include/Objects/Calo3DCluster.h
index 57483abc..98443e2b 100644
--- a/Reconstruction/RecPFACyber/include/Objects/Calo3DCluster.h
+++ b/Reconstruction/RecPFACyber/include/Objects/Calo3DCluster.h
@@ -56,6 +56,7 @@ namespace Cyber {
     int getEndDlayer() const;
     double getDepthToECALSurface() const;
     int getType() const { return type; }
+    double getEnergyScale() const { return Escale; }
 
     void setCaloHits( std::vector<const Cyber::CaloHit*> _hits ) { hits = _hits; }
     void setCaloHitsFrom2DCluster(); 
@@ -69,6 +70,7 @@ namespace Cyber {
     { map_localMaxU[name1]=_colU; map_localMaxV[name2]=_colV; }
     void setClusters(std::vector<const Calo2DCluster*> _2dcol) { m_2dclusters = _2dcol; }
     void setType(int _type) { type = _type; }
+    void setEnergyScale(double _scale) { Escale = _scale; }
 
     void addTowerID(int _m, int _p, int _s) { std::vector<int> id(3); id[0] = _m; id[1] = _p; id[2] = _s; towerID.push_back(id); }
     void addTowerID( std::vector<int> id ) { towerID.push_back(id); }
@@ -103,6 +105,7 @@ namespace Cyber {
     std::vector< std::pair<edm4hep::MCParticle, float> > MCParticleWeight;
 
     std::vector< std::vector<int> > towerID; //[module, part, stave]
+    double Escale = 1.;
     TVector3 axis;
     double chi2;
     double alpha;
diff --git a/Reconstruction/RecPFACyber/include/Objects/CaloUnit.h b/Reconstruction/RecPFACyber/include/Objects/CaloUnit.h
index 0ed6d775..0530e65a 100644
--- a/Reconstruction/RecPFACyber/include/Objects/CaloUnit.h
+++ b/Reconstruction/RecPFACyber/include/Objects/CaloUnit.h
@@ -62,7 +62,7 @@ namespace Cyber{
     void addLinkedMCP( std::pair<edm4hep::MCParticle, float> _pair ) { MCParticleWeight.push_back(_pair); }
     void setLinkedMCP( std::vector<std::pair<edm4hep::MCParticle, float>> _pairVec ) { MCParticleWeight.clear(); MCParticleWeight = _pairVec; }
     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 setcellID(int _system, int _module, int _stave, int _part, int _dlayer, int _slayer, int _bar) { system=_system; module=_module; stave=_stave; part=_part; 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; }
@@ -82,6 +82,7 @@ namespace Cyber{
 		unsigned long long cellID;
 		int system;
 		int module;
+    int part;
 		int stave;
 		int dlayer;
 		int slayer;
diff --git a/Reconstruction/RecPFACyber/include/Objects/HoughObject.h b/Reconstruction/RecPFACyber/include/Objects/HoughObject.h
index dba958db..ea56a814 100644
--- a/Reconstruction/RecPFACyber/include/Objects/HoughObject.h
+++ b/Reconstruction/RecPFACyber/include/Objects/HoughObject.h
@@ -16,8 +16,8 @@ namespace Cyber {
 
 
     TVector2 getCenterPoint() const { return m_center_point; }
-    TVector2 getUpperPoint() const { return m_center_point + TVector2( m_cell_size*cos(m_center_point.Phi() + TMath::PiOver2()), m_cell_size*sin(m_center_point.Phi() + TMath::PiOver2()) ); }
-    TVector2 getLowerPoint() const { return m_center_point + TVector2( m_cell_size*cos(m_center_point.Phi() + 3*TMath::PiOver2()), m_cell_size*sin(m_center_point.Phi() + 3*TMath::PiOver2()) ); }
+    TVector2 getUpperPoint() const { return m_center_point + TVector2( 0.7*m_cell_size*cos(m_center_point.Phi() + TMath::PiOver2()), 0.7*m_cell_size*sin(m_center_point.Phi() + TMath::PiOver2()) ); }
+    TVector2 getLowerPoint() const { return m_center_point + TVector2( 0.7*m_cell_size*cos(m_center_point.Phi() + 3*TMath::PiOver2()), 0.7*m_cell_size*sin(m_center_point.Phi() + 3*TMath::PiOver2()) ); }
     //TVector2 getPointU()  const { return m_center_point + TVector2(0,  m_cell_size/TMath::Sqrt(2)); }
     //TVector2 getPointD()  const { return m_center_point + TVector2(0, -m_cell_size/TMath::Sqrt(2)); }
     //TVector2 getPointL()  const { return m_center_point + TVector2(-m_cell_size/TMath::Sqrt(2), 0); }
diff --git a/Reconstruction/RecPFACyber/include/Tools/CaloHitsCreator.h b/Reconstruction/RecPFACyber/include/Tools/CaloHitsCreator.h
index 6069aa5c..ea07735f 100644
--- a/Reconstruction/RecPFACyber/include/Tools/CaloHitsCreator.h
+++ b/Reconstruction/RecPFACyber/include/Tools/CaloHitsCreator.h
@@ -20,7 +20,8 @@ namespace Cyber{
     StatusCode CreateCaloHits( CyberDataCol& m_DataCol,
                                std::vector<DataHandle<edm4hep::CalorimeterHitCollection>*>& r_CaloHitCols, 
                                std::map<std::string, dd4hep::DDSegmentation::BitFieldCoder*>& map_decoder, 
-                               std::map<std::string, DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>*>& map_CaloParticleAssoCol ); 
+                               std::map<std::string, DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>*>& map_CaloParticleAssoCol,
+                               const dd4hep::VolumeManager& m_volumeManager ); 
 
     //StatusCode CreateMCParticleCaloHitsAsso( std::vector<DataHandle<edm4hep::CalorimeterHitCollection>*>& r_CaloHitCols, 
     //                                         DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>* r_MCParticleRecoCaloCol );
diff --git a/Reconstruction/RecPFACyber/include/Tools/TrackCreator.h b/Reconstruction/RecPFACyber/include/Tools/TrackCreator.h
index 16c48c81..b4f46841 100644
--- a/Reconstruction/RecPFACyber/include/Tools/TrackCreator.h
+++ b/Reconstruction/RecPFACyber/include/Tools/TrackCreator.h
@@ -6,6 +6,11 @@
 #include "Algorithm/TrackExtrapolatingAlg.h"
 #include "TVector3.h"
 
+#include "TMVA/Tools.h"
+#include "TMVA/Reader.h"
+
+#include <fstream>
+
 namespace Cyber{
   class TrackCreator{
 
@@ -40,6 +45,8 @@ namespace Cyber{
       return trk1->getMomentum() > trk2->getMomentum();
     }
 
+    TMVA::Reader *mva_rdr = new TMVA::Reader("Silent");  
+
   };
 };
 #endif
diff --git a/Reconstruction/RecPFACyber/script/ana.py b/Reconstruction/RecPFACyber/script/ana.py
new file mode 100644
index 00000000..e5706e97
--- /dev/null
+++ b/Reconstruction/RecPFACyber/script/ana.py
@@ -0,0 +1,43 @@
+import os, sys
+from Gaudi.Configuration import *
+
+########### k4DataSvc ####################
+from Configurables import k4DataSvc
+podioevent = k4DataSvc("EventDataSvc", input="Rec_TDR_o1_v01.root")
+##########################################
+
+########## CEPCSWData ################# 
+cepcswdatatop ="/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest"
+#######################################
+
+
+########## Podio Input ###################
+from Configurables import PodioInput
+inp = PodioInput("InputReader")
+inp.collections = [ "CyberPFO", "MCParticle" ]
+##########################################
+
+
+
+from Configurables import GenMatch
+genmatch = GenMatch("GenMatch")
+genmatch.nJets = 2
+genmatch.R = 0.6
+genmatch.OutputFile = "Jets_TDR_o1_v01.root"
+#genmatch.OutputFile = "./FullSim_samples/RecJets_TDR_o1_v01_E240_nnh_gg_CalHits.root"
+
+##############################################################################
+# POD I/O
+##############################################################################
+
+
+########################################
+
+from Configurables import ApplicationMgr
+ApplicationMgr( 
+    TopAlg=[inp, genmatch ],
+    EvtSel="NONE",
+    EvtMax=10,
+    ExtSvc=[podioevent],
+    #OutputLevel=DEBUG
+)
diff --git a/Reconstruction/RecPFACyber/script/digi.py b/Reconstruction/RecPFACyber/script/digi.py
index c3ea459f..c8ab8e68 100644
--- a/Reconstruction/RecPFACyber/script/digi.py
+++ b/Reconstruction/RecPFACyber/script/digi.py
@@ -49,9 +49,13 @@ podioinput = PodioInput("PodioReader", collections=[
 #    "EventHeader",
     "MCParticle",
     "EcalBarrelCollection", 
-    "EcalBarrelContributionCollection", 
+    "EcalBarrelContributionCollection",
+    "EcalEndcapsCollection",
+    "EcalEndcapsContributionCollection", 
     "HcalBarrelCollection", 
     "HcalBarrelContributionCollection", 
+    "HcalEndcapsCollection",
+    "HcalEndcapsContributionCollection"
     ])
 
 ########## Digitalization ################
@@ -59,55 +63,90 @@ podioinput = PodioInput("PodioReader", collections=[
 ##ECAL##
 from Configurables import EcalDigiAlg
 EcalDigi = EcalDigiAlg("EcalDigiAlg")
-EcalDigi.ReadOutName = "EcalBarrelCollection"
-EcalDigi.SimCaloHitCollection = "EcalBarrelCollection"
-EcalDigi.CaloHitCollection = "ECALBarrel"
-EcalDigi.CaloAssociationCollection = "ECALBarrelAssoCol"
-EcalDigi.CaloMCPAssociationCollection = "ECALBarrelParticleAssoCol"
+EcalDigi.SimCaloHitCollection = ["EcalBarrelCollection", "EcalEndcapsCollection"]
+EcalDigi.ReadOutName = ["EcalBarrelCollection", "EcalEndcapsCollection"]
+EcalDigi.CaloHitCollection = ["ECALBarrel", "ECALEndcaps"]
+EcalDigi.CaloAssociationCollection = ["ECALBarrelAssoCol", "ECALEndcapsAssoCol"]
+EcalDigi.CaloMCPAssociationCollection = ["ECALBarrelParticleAssoCol", "ECALEndcapsParticleAssoCol"]
 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.EcalMIP_Thre = 0.05
-EcalDigi.Debug=1
-EcalDigi.WriteNtuple = 0
-EcalDigi.OutFileName = "Digi_ECAL.root"
+EcalDigi.TimeResolution = 0.7            # 0.7 ns
+EcalDigi.EcalMIPEnergy = 8.9             # MIP energy 8.9 MeV for 1 cm BGO
+EcalDigi.EcalMIP_Thre = 0.05              # 0.05 mip at each side, 0.1 mip for one bar
+EcalDigi.UseRealisticDigi = 1
+# scintillation
+EcalDigi.UseDigiScint = 1
+EcalDigi.EcalCryIntLY = 8200             #intrinsic LY 8200 [p.e./MIP]
+EcalDigi.EcalCryMipLY = 200              #Detected effective LY 200 [p.e./MIP]
+EcalDigi.AttenuationLength = 1e8         # 8000 mm for 5% non-uniformity
+# SiPM
+EcalDigi.SiPMDigiVerbose = 2             # 0:w/o response, w/o correction; 1:w/ response, w/o correction; 2:w/ response, w/ simple correction; 3:w/ response, w/ full correction
+EcalDigi.EcalSiPMPDE = 0.25              # NDL-EQR06, PDE 0.25
+EcalDigi.EcalSiPMDCR = 0                 # NDL-EQR06, dark count rate 2500000 [Hz]
+EcalDigi.EcalTimeInterval = 0.           # Time interval 0.000002 [s]. DCR*TimeInterval = dark count noise
+EcalDigi.EcalSiPMCT = 0.                 # SiPM crosstalk Probability 12%
+EcalDigi.EcalSiPMGainMean = 50           # 50 [ADC/p.e.]
+EcalDigi.EcalSiPMGainSigma = 0.08        # 0.08
+#EcalDigi.EcalSiPMNoiseSigma = 0          # 0
+# ADC
+EcalDigi.ADC = 8192                      # 13-bit, 8192
+EcalDigi.ADCSwitch = 8000                # 8000
+EcalDigi.Pedestal = 50                   # Pedestal 50 ADC
+EcalDigi.GainRatio_12 = 50               # Gain ratio 50
+EcalDigi.GainRatio_23 = 60               # Gain ratio 60
+#EcalDigi.EcalNoiseADCSigma = 4           # 4
+# temperature control
+EcalDigi.UseCryTemp = 0
+EcalDigi.UseCryTempCor = 0
+EcalDigi.UseSiPMTemp = 0
+EcalDigi.UseSiPMTempCor = 0
+EcalDigi.EcalTempGrad = 3./27            # 3./27 = 3K from 0 to 27 layer
+EcalDigi.EcalBGOTempCoef = -0.0138       # -0.0138 [%/K]
+EcalDigi.EcalSiPMGainTempCoef = -0.03    # -0.03 [%/K]
+EcalDigi.EcalSiPMDCRTempCoef = 3.34/80   # 3.34/80 [10^{k*deltaT}]
 #########################################
+EcalDigi.WriteNtuple = 0
 
 ##HCAL##
 from Configurables import HcalDigiAlg
 HcalDigi = HcalDigiAlg("HcalDigiAlg")
-HcalDigi.ReadOutName = "HcalBarrelCollection"
-HcalDigi.SimCaloHitCollection = "HcalBarrelCollection"
-HcalDigi.CaloHitCollection = "HCALBarrel"
-HcalDigi.CaloAssociationCollection = "HCALBarrelAssoCol"
-HcalDigi.CaloMCPAssociationCollection = "HCALBarrelParticleAssoCol"
+HcalDigi.SimCaloHitCollection = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+HcalDigi.ReadOutName = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+HcalDigi.CaloHitCollection = ["HCALBarrel", "HCALEndcaps"]
+HcalDigi.CaloAssociationCollection = ["HCALBarrelAssoCol", "HCALEndcapsAssoCol"]
+HcalDigi.CaloMCPAssociationCollection = ["HCALBarrelParticleAssoCol", "HCALEndcapsParticleAssoCol"]
 HcalDigi.SkipEvt = 0
 HcalDigi.Seed = 2079
-#Digitalization parameters
-HcalDigi.MIPResponse = 0.007126  # MeV / MIP
-HcalDigi.MIPThreshold = 0.1    # Unit: MIP
 HcalDigi.CalibrHCAL = 1.
-HcalDigi.UseRealisticDigi = 1    # Flag to use digitization model.
-HcalDigi.SiPMPixel = 57600       # 57600 for 6025PE (6*6 mm, 25 um pixel pitch)
+#Digitalization parameters
+HcalDigi.UseRealisticDigi = 0     #---------Flag to use digitization model.
+HcalDigi.MIPResponse = 0.007126   # 0.007.126 GeV / MIP
+HcalDigi.MIPThreshold = 0.1       # ----------Unit: MIP
+HcalDigi.TemperatureVariation = 0 # Temperature variation 1K
+# Scintillation
+HcalDigi.UseTileLYMap = 0
+HcalDigi.MIPLY = 80               # Glass LY
+HcalDigi.LYTempCoef = 0           # Glass LY with temperature
 HcalDigi.TileNonUniformity = 0.0
-HcalDigi.EffAttenLength = 1e7
-HcalDigi.ADCError = 0.0
-HcalDigi.MIPADCMean = 80.*30.0   # Light yield 80 pe/mip
-HcalDigi.PeADCMean = 30.0
-HcalDigi.PeADCSigma = 0.
-HcalDigi.ADCBaselineHG = 0
-HcalDigi.ADCBaselineSigmaHG = 0.
-HcalDigi.ADCBaselineLG = 0
-HcalDigi.ADCBaselineSigmaLG = 0.
-HcalDigi.ADCHLRatio = 1
-HcalDigi.ADCSwitch = 1e7
-HcalDigi.ADCLimit = 1e7
+# SiPM
+HcalDigi.SiPMPixel = 57600           #---------57600 for 6025PE (6*6 mm, 25 um pixel pitch)
+HcalDigi.SiPMDCR = 1600              #---------1600 for 6025PE (6*6 mm, 25 um pixel pitch), 3200 for 6015PS ()
+HcalDigi.SiPMCT = 0.0                #---------SiPM crosstalk Probability 0.12
+HcalDigi.TimeInterval = 0.           #---------Shaping time 2 us
+HcalDigi.SiPMGainTempCoef = 0        #---------Temperature dependence of SiPM gain (-3%/K)
+HcalDigi.SiPMDCRTempCoef = 0         #---------Temperature dependence of SiPM DCR (10^{k*deltaT}, k=3.34/80)
+# ADC
+HcalDigi.ADC = 8192
+HcalDigi.ADCSwitch = 1e7          # Switch at 8000
+HcalDigi.GainRatio_12 = 50
+HcalDigi.GainRatio_23 = 60
+HcalDigi.SiPMGainMean = 20        # SiPM gain: 2 ADC / p.e.
+HcalDigi.SiPMGainSigma = 0.08     # Fluctuation of ADC / p.e.
+HcalDigi.SiPMNoiseSigma = 0       # SiPM noise sigma
+HcalDigi.Pedestal = 50            # Pedestal 50 ADC
+HcalDigi.PedestalSigma = 4        # Sigma of electronic noise (4 ADC)
 HcalDigi.WriteNtuple = 0
-HcalDigi.OutFileName = "Digi_HCAL.root"
 
 
 # output
@@ -121,10 +160,16 @@ out.outputCommands = ["drop *",
     "keep TPCCollection",
     "keep OTKBarrelCollection",
     "keep FTDCollection",
+    "keep MuonBarrelCollection",
+    "keep MuonEndcapCollection",
     "keep ECALBarrel",
     "keep HCALBarrel",
     "keep ECALBarrelParticleAssoCol",
-    "keep HCALBarrelParticleAssoCol" ]
+    "keep HCALBarrelParticleAssoCol",
+    "keep ECALEndcaps",
+    "keep HCALEndcaps",
+    "keep ECALEndcapsParticleAssoCol",
+    "keep HCALEndcapsParticleAssoCol" ]
 
 
 # ApplicationMgr
diff --git a/Reconstruction/RecPFACyber/script/rec.py b/Reconstruction/RecPFACyber/script/rec.py
index e844f945..e61b0843 100644
--- a/Reconstruction/RecPFACyber/script/rec.py
+++ b/Reconstruction/RecPFACyber/script/rec.py
@@ -36,10 +36,15 @@ crystalecalcorr.CorrectionFile = os.path.join(cepcswdatatop, "CEPCSWData/offline
 ########## Podio Input ###################
 from Configurables import PodioInput
 inp = PodioInput("InputReader")
-inp.collections = [ "ECALBarrel", 
+inp.collections = [ 
+                    "ECALBarrel",
                     "ECALBarrelParticleAssoCol",
+#                    "ECALEndcaps",
+#                    "ECALEndcapsParticleAssoCol",
                     "HCALBarrel",
                     "HCALBarrelParticleAssoCol",
+#                    "HCALEndcaps",
+#                    "HCALEndcapsParticleAssoCol",
                     "MCParticle", 
                     "CompleteTracks", 
                     "CompleteTracksParticleAssociation"]
@@ -54,14 +59,26 @@ CyberPFAlg.BField = 3.
 CyberPFAlg.Debug = 0
 CyberPFAlg.SkipEvt = 0
 CyberPFAlg.WriteAna = 1
-CyberPFAlg.AnaFileName = "RecAnaTuple_TDR_o1_v01_mu.root"
-CyberPFAlg.UseTruthTrack = 0
-CyberPFAlg.EcalGlobalCalib = 1.05
-CyberPFAlg.HcalGlobalCalib = 4.5
+CyberPFAlg.AnaFileName = "RecAnaTuple_TDR_o1_v01.root"
+CyberPFAlg.UseMCPTrack = 0
+CyberPFAlg.UseTruthMatchTrack = 0
+CyberPFAlg.DoCleanTrack = 1
+CyberPFAlg.TrackIDFile = "/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest/CEPCSWData/offline-data/Reconstruction/CyberPFA_trackID/TrkID_BDT_BDTG.weights.xml"
+CyberPFAlg.TrackIDMethod = "BDTG"
+CyberPFAlg.EcalChargedCalib = 1.26
+CyberPFAlg.HcalChargedCalib = 4.0
+CyberPFAlg.EcalNeutralCalib = 1.0
+CyberPFAlg.HcalNeutralCalib = 4.0
 ##----Readin collections----
 CyberPFAlg.MCParticleCollection = "MCParticle"
 CyberPFAlg.TrackCollections = ["CompleteTracks"]
 CyberPFAlg.MCRecoTrackParticleAssociationCollection = "CompleteTracksParticleAssociation"
+#CyberPFAlg.ECalCaloHitCollections = ["ECALBarrel","ECALEndcaps"]
+#CyberPFAlg.ECalReadOutNames = ["EcalBarrelCollection","EcalEndcapsCollection"]
+#CyberPFAlg.ECalMCPAssociationName = ["ECALBarrelParticleAssoCol", "ECALEndcapsParticleAssoCol"]
+#CyberPFAlg.HCalCaloHitCollections = ["HCALBarrel", "HCALEndcaps"]
+#CyberPFAlg.HCalReadOutNames = ["HcalBarrelCollection", "HcalEndcapsCollection"]
+#CyberPFAlg.HCalMCPAssociationName = ["HCALBarrelParticleAssoCol", "HCALEndcapsParticleAssoCol"]
 CyberPFAlg.ECalCaloHitCollections = ["ECALBarrel"]
 CyberPFAlg.ECalReadOutNames = ["EcalBarrelCollection"]
 CyberPFAlg.ECalMCPAssociationName = ["ECALBarrelParticleAssoCol"]
@@ -97,7 +114,7 @@ CyberPFAlg.AlgParNames = [ ["InputECALBars","OutputECAL1DClusters","OutputECALHa
                                  ["InputHCALHits", "OutputHCALClusters"], #12
                                  ["DoECALClustering","DoHCALClustering","InputHCALHits","OutputHCALClusters"], #15
                                  ["ReadinECALClusterName", "ReadinHCALClusterName", "OutputCombPFO"],  #16
-                                 ["ECALCalib", "HCALCalib", "MinAngleForNeuMerge"] ]#17
+                                 ["ECALChargedCalib", "HCALChargedCalib", "ECALNeutralCalib", "HCALNeutralCalib"] ]#17
 CyberPFAlg.AlgParTypes = [ ["string","string","string"],#1
                                  ["string"],#2
                                  ["string","string"],#3
@@ -109,7 +126,7 @@ CyberPFAlg.AlgParTypes = [ ["string","string","string"],#1
                                  ["string", "string"], #12
                                  ["bool","bool","string","string"], #15
                                  ["string","string","string"],  #16
-                                 ["double","double","double"] ]#17
+                                 ["double","double", "double","double"] ]#17
 CyberPFAlg.AlgParValues = [ ["BarCol","Cluster1DCol","HalfClusterCol"],#1
                                   ["AllLocalMax"],#2
                                   ["AllLocalMax","TrackAxis"],#3
@@ -121,7 +138,7 @@ CyberPFAlg.AlgParValues = [ ["BarCol","Cluster1DCol","HalfClusterCol"],#1
                                   ["HCALBarrel", "SimpleHCALCluster"], #12
                                   ["0","1","HCALBarrel","HCALCluster"], #15
                                   ["EcalCluster", "SimpleHCALCluster", "outputPFO"],  #16
-                                  ["1.05","4.5","0.12"]  ]#17
+                                  ["1.26","4.", "1.", "4."]  ]#17
 
 
 ##############################################################################
diff --git a/Reconstruction/RecPFACyber/script/roofit_jets.cpp b/Reconstruction/RecPFACyber/script/roofit_jets.cpp
new file mode 100644
index 00000000..43d53ffc
--- /dev/null
+++ b/Reconstruction/RecPFACyber/script/roofit_jets.cpp
@@ -0,0 +1,229 @@
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <TFile.h>
+#include <TCanvas.h>
+#include <TH1F.h>
+#include <TF1.h>
+#include <TRandom3.h>
+#include <RooRealVar.h>
+#include <RooGaussian.h>
+#include <RooDataHist.h>
+#include <RooFitResult.h>
+#include <RooPlot.h>
+#include "/afs/ihep.ac.cn/users/g/guofy/RootUtils/AtlasStyle.C"
+#include "/afs/ihep.ac.cn/users/g/guofy/RootUtils/AtlasUtils.C"
+#include "/afs/ihep.ac.cn/users/g/guofy/RootUtils/AtlasLabels.C"
+#include "/afs/ihep.ac.cn/users/g/guofy/HggTwoSidedCBPdf.cxx"
+#include "/afs/ihep.ac.cn/users/g/guofy/HggTwoSidedCBPdf.h"
+
+using namespace std;
+using namespace RooFit;
+
+vector<double> get_rms90(vector<double> data);
+
+vector<double> roofit_jets(){
+  SetAtlasStyle();
+  //gStyle->SetLegendTextSize(0.04);
+  gStyle->SetLegendFont(42);
+  gStyle->SetErrorX(0.5); 
+  gStyle->SetOptStat(0);
+  gStyle->SetLabelSize(0.05);
+
+
+  // Read data from txt file
+  double m_jj, jet1_costheta, jet2_costheta, invPt, barrelRatio;
+  std::vector<double> event;
+  std::vector<double> inv_mass; 
+  std::vector<double> mc_chargeE; 
+  std::vector<double> mc_neuhadE; 
+  std::vector<double> rec_trackE;
+
+  // std::ifstream file("out/invmass_fullrec_ecal1.1_hcal70.txt"); 
+  // std::ifstream file("out/invmass_MCtrk_recHCAL_ecal1.1_hcal70.txt"); 
+  // std::ifstream file("scan_calibration/out/invmass_ECALCali1.100_HCALCali70.0.txt"); 
+
+/*  std::ifstream file("output.txt"); 
+  if(file.is_open()) 
+  {
+    // double ll_event, ll_invmass, ll_chargeE, ll_neuhadE, ll_rectrack, ll_EECAL, ll_EHCAL;
+    // while (file >> ll_event >> ll_invmass ) 
+    // {  // 逐行读取文件中的数据
+    //   // double dE = ll_chargeE - ll_rectrack;
+    //   // if( (dE<-5) || (dE>5) ) continue;
+    //   event.push_back(ll_event);
+    //   inv_mass.push_back(ll_invmass);  // 将每个数添加到vector中
+    //   // mc_chargeE.push_back(ll_chargeE);
+    //   // mc_neuhadE.push_back(ll_neuhadE);
+    //   // rec_trackE.push_back(ll_rectrack);
+    // }
+    // file.close();  // 关闭文件
+    double ll_invmass;
+    while (file >> ll_invmass ) 
+    {  // 逐行读取文件中的数据
+      inv_mass.push_back(ll_invmass);  // 将每个数添加到vector中
+    }
+    file.close();  // 关闭文件
+  }
+*/
+  TFile* rfile = new TFile("jet_all.root","read");
+  TTree* rtree = (TTree*)rfile->Get("jets");
+  rtree->SetBranchAddress("mass_allParticles", &m_jj);
+  rtree->SetBranchAddress("GEN_jet1_costheta", &jet1_costheta);
+  rtree->SetBranchAddress("GEN_jet2_costheta", &jet2_costheta);
+  rtree->SetBranchAddress("GEN_inv_pt", &invPt);
+  rtree->SetBranchAddress("barrelRatio", &barrelRatio);
+
+  for(int ievt=0; ievt<rtree->GetEntries(); ievt++){
+    //if(ievt>10000) continue;
+    rtree->GetEntry(ievt);
+    //if(fabs(jet1_costheta)>0.6 || fabs(jet2_costheta)>0.6 || invPt>1) continue;
+    if(barrelRatio<0.95) continue;
+    inv_mass.push_back(m_jj);
+  }
+
+  // 创建RooFit变量
+  // RooRealVar x("x", "Invariant mass / GeV", 90, 150);
+  RooRealVar x("x", "Invariant mass / GeV", 80, 180);
+  // 创建空的RooDataSet
+  RooDataSet data("data", "data", RooArgSet(x));
+  for(int i=0; i<inv_mass.size();i++){
+    if(inv_mass[i]<80) continue;
+    x.setVal(inv_mass[i]);
+    data.add(RooArgSet(x));
+  }
+  data.Print();
+
+  // RooRealVar rf_x("x", "x", 90, 150);
+  RooRealVar rf_mean("mean", "mean of gaussian", 123, 115, 135);
+  RooRealVar rf_sigma("sigma", "width of gaussian", 5, 3, 12);
+
+  TCanvas *c2 = new TCanvas("c2", "c2", 800, 600);
+  c2->cd();
+  //RooGaussian rf_gauss("gauss", "gaussian PDF", x, rf_mean, rf_sigma);
+  //vector<double> rms90_range = get_rms90(inv_mass);
+  //cout << "yyy:   " << rms90_range[0] << " " << rms90_range[1] << endl;
+  //x.setRange("rms90", rms90_range[0], rms90_range[1]);
+  ////x.setRange(110, 140);
+  //rf_gauss.fitTo(data, Range("rms90"));
+
+
+
+  RooRealVar alphaLo("alphaLo","alphaLo",0,5);
+  RooRealVar nLo("nLo","nLo",0,200);
+  RooRealVar alphaHi("alphaHi","alphaHi",0,5);
+  RooRealVar nHi("nHi","nHi",0,150);
+ 
+  RooAbsPdf* rf_dscb = new HggTwoSidedCBPdf("rf_dscb", "rf_dscb", x, rf_mean, rf_sigma, alphaLo, nLo, alphaHi, nHi);
+  rf_dscb->fitTo(data);
+  RooPlot* xframe = x.frame();
+  data.plotOn(xframe, Name("gr_data"), DataError(RooAbsData::SumW2), Binning(50), Invisible());
+  //rf_gauss.plotOn(xframe, Name("rf_gauss"), LineColor(2), LineWidth(2));
+  rf_dscb->plotOn(xframe, Name("rf_dscb"), LineColor(2), LineWidth(2));
+  //rf_dscb->paramOn(xframe);
+
+  
+  //xframe->GetYaxis()->SetRangeUser(0, 390);
+  xframe->GetYaxis()->SetTitle("Events / GeV");
+  xframe->GetXaxis()->SetTitleSize(0.06);
+  xframe->GetYaxis()->SetTitleSize(0.06);
+  xframe->GetXaxis()->CenterTitle();
+  xframe->GetYaxis()->CenterTitle();
+  xframe->GetXaxis()->SetLabelSize(0.05);
+  xframe->GetYaxis()->SetLabelSize(0.05);
+  xframe->Draw();
+
+
+  TGraphAsymmErrors* gr1 = (TGraphAsymmErrors*)(xframe->getObject(0));
+  TGraphAsymmErrors* gr2 = new TGraphAsymmErrors();
+  gr2->SetName("gr_data");
+  for(int i=0; i<gr1->GetN(); i++){
+    if(gr1->GetPointY(i)==0) continue;
+    else{
+      gr2->SetPoint(i, gr1->GetPointX(i), gr1->GetPointY(i));
+      gr2->SetPointError(i, 0, 0, sqrt(gr1->GetPointY(i)), sqrt(gr1->GetPointY(i)));
+    }
+  }
+
+  gr2->GetXaxis()->SetRangeUser(100, 160);
+  gr2->GetYaxis()->SetRangeUser(0, 260);
+  gr2->GetXaxis()->SetTitle("m_{jj} [GeV]");
+  gr2->GetYaxis()->SetTitle("Events / GeV");
+  gr2->Draw("P same");
+
+  //xframe->getObject(1)->Print();
+
+  //TF1* func = (TF1*)xframe->getObject(1);
+  //func->Print();
+  //func->SetName("rf_dscb");
+  //func->SetLineStyle(1);
+  //func->SetLineWidth(2);
+  //func->GetXaxis()->SetRangeUser(105,160);
+  //func->GetYaxis()->SetRangeUser(0, 4400);
+  //func->Draw("C same");
+
+  TLegend* l1 = new TLegend(0.23, 0.65, 0.50, 0.9);
+  l1->SetBorderSize(0);
+  l1->AddEntry("gr_data", "Rec. events", "PE" );
+  l1->AddEntry("rf_dscb", "H #rightarrow jj, DSCB fit", "L");
+  //l1->AddEntry("rf_gauss", "H #rightarrow jj, DSCB fit", "L");
+  l1->Draw();
+
+  //TLatex text_CEPC;
+  //text_CEPC.SetNDC();
+  //text_CEPC.SetTextSize(0.050);
+  //text_CEPC.SetTextFont(22);
+  //text_CEPC.DrawLatex(0.2, 0.8, "CEPC Simulation");
+
+  //text_CEPC.SetTextFont(62);
+  //text_CEPC.SetTextSize(0.04);
+  //text_CEPC.DrawLatex(0.2, 0.75, "e^{+}e^{-} #rightarrow ZH, H #rightarrow #gamma#gamma");
+  //text_CEPC.DrawLatex(0.2, 0.7, "#sqrt{s} = 240 GeV");
+
+  // 获取拟合参数的值和误差
+  double fittedMean = rf_mean.getVal();
+  double fittedMeanError = rf_mean.getError();
+  double fittedSigma = rf_sigma.getVal();
+  double fittedSigmaError = rf_sigma.getError();
+  double BMR_fit = fittedSigma / fittedMean;
+  double BMR_error = BMR_error = BMR_fit * 
+                                  sqrt( (fittedMeanError / fittedMean)*(fittedMeanError / fittedMean) + 
+                                        (fittedSigmaError / fittedSigma)*(fittedSigmaError / fittedSigma) );
+
+  // 打印拟合结果
+  // data.Print();
+  std::cout << "Fitted mean: " << fittedMean << " +/- " << fittedMeanError << std::endl;
+  std::cout << "Fitted sigma: " << fittedSigma << " +/- " << fittedSigmaError << std::endl;
+  cout << "BMR = " << BMR_fit*100. << " +/- " << BMR_error*100. << " %" << endl;
+
+  vector<double> output; 
+  output.push_back(BMR_fit*100.);
+  output.push_back(BMR_error*100.);
+
+  return output; 
+}
+
+
+vector<double> get_rms90(vector<double> data){
+  std::sort(data.begin(), data.end());
+  int num_data = data.size();
+  int num_data90 = num_data*0.90;
+  int num_data10 = num_data*0.10;
+
+  double lower_range = 0;
+  double upper_range = 0;
+  double range = 10000.0;
+  for(int i=0; i<num_data10-3; i++){
+    double temp_lower_range = data[i];
+    double temp_upper_range = data[i+num_data90];
+    double temp_range = temp_upper_range - temp_lower_range;
+    if (temp_range < range){
+      range = temp_range;
+      lower_range = temp_lower_range;
+      upper_range = temp_upper_range;
+    }
+  }
+
+  vector<double> aa{lower_range, upper_range};
+  return aa;
+}
diff --git a/Reconstruction/RecPFACyber/script/sim.py b/Reconstruction/RecPFACyber/script/sim.py
index a8b14c52..2b10df3f 100644
--- a/Reconstruction/RecPFACyber/script/sim.py
+++ b/Reconstruction/RecPFACyber/script/sim.py
@@ -6,7 +6,7 @@ from Configurables import k4DataSvc
 dsvc = k4DataSvc("EventDataSvc")
 
 from Configurables import RndmGenSvc, HepRndm__Engine_CLHEP__RanluxEngine_
-seed = [12340]
+seed = [1024]
 # 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
@@ -57,7 +57,6 @@ from Configurables import GenPrinter
 stdheprdr = StdHepRdr("StdHepRdr")
 stdheprdr.Input = "/cefs/data/stdhep/CEPC240/higgs/update_from_LiangHao_1M/data/E240.Pnnh_gg.e0.p0.whizard195/nnh_gg.e0.p0.00001.stdhep"
 
-
 genalg = GenAlgo("GenAlgo")
 #genalg.GenTools = ["GtGunTool"]
 genalg.GenTools = ["StdHepRdr"]
@@ -90,9 +89,9 @@ tpc_sensdettool.TypeOption = 1
 from Configurables import CalorimeterSensDetTool
 from Configurables import DriftChamberSensDetTool
 cal_sensdettool = CalorimeterSensDetTool("CalorimeterSensDetTool")
-cal_sensdettool.CalNamesMergeDisable = ["EcalBarrel", "CaloDetectorEndcap", "HcalBarrel", "HcalEndcaps"]
-#cal_sensdettool.CalNamesApplyBirks = ["EcalBarrel", "CaloDetectorEndcap", "HcalBarrel","HcalEndcaps"]
-#cal_sensdettool.CalNamesBirksConstants = [0.008415, 0.008415, 0.01, 0.01] # BGO and Glass scintillator
+cal_sensdettool.CalNamesMergeDisable = ["EcalBarrel", "EcalEndcap", "HcalBarrel", "HcalEndcaps"]
+cal_sensdettool.CalNamesApplyBirks = ["EcalBarrel", "EcalEndcap", "HcalBarrel","HcalEndcaps"]
+cal_sensdettool.CalNamesBirksConstants = [0.008415, 0.008415, 0.01, 0.01] # BGO and Glass scintillator
 
 # output
 from Configurables import PodioOutput
diff --git a/Reconstruction/RecPFACyber/script/tracking.py b/Reconstruction/RecPFACyber/script/tracking.py
index 7e07f554..be11bff4 100644
--- a/Reconstruction/RecPFACyber/script/tracking.py
+++ b/Reconstruction/RecPFACyber/script/tracking.py
@@ -6,7 +6,7 @@ from Configurables import k4DataSvc
 dsvc = k4DataSvc("EventDataSvc", input="CaloDigi_TDR_o1_v01.root")
 
 from Configurables import RndmGenSvc, HepRndm__Engine_CLHEP__RanluxEngine_
-seed = [12340]
+seed = [1024]
 # 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
@@ -52,7 +52,9 @@ podioinput = PodioInput("PodioReader", collections=[
     "SITCollection",
     "TPCCollection",
     "OTKBarrelCollection",
-    "FTDCollection"
+    "FTDCollection",
+    "MuonBarrelCollection",
+    "MuonEndcapCollection"
     ])
 
 # digitization
@@ -135,6 +137,16 @@ digiTPC.TPCTrackerHitsCol = gashitname
 #digiTPC.N_eff = 30
 #digiTPC.OutputLevel = DEBUG
 
+## Muon Detector ##
+from Configurables import MuonDigiAlg
+digiMuon = MuonDigiAlg("MuonDigiAlg")
+digiMuon.MuonBarrelHitsCollection = "MuonBarrelCollection"
+digiMuon.MuonEndcapHitsCollection = "MuonEndcapCollection"
+digiMuon.MuonBarrelTrackerHits = "MuonBarrelTrackerHits"
+digiMuon.MuonEndcapTrackerHits = "MuonEndcapTrackerHits"
+digiMuon.WriteNtuple = 0
+digiMuon.OutFileName = "Digi_MUON.root"
+
 # tracking
 from Configurables import KalTestTool
 # Close multiple scattering and smooth, used by clupatra
@@ -220,12 +232,14 @@ full.FTDRawHits     = ftdhitname
 full.TPCTracks = "ClupatraTracks" # add standalone TPC track
 full.SiTracks  = "SubsetTracks"
 full.OutputTracks  = "CompleteTracks" # default name
-full.VTXHitToTrackDistance = 5.
+#full.VTXHitToTrackDistance = 5.
 full.FTDHitToTrackDistance = 5.
 full.SITHitToTrackDistance = 3.
 full.SETHitToTrackDistance = 5.
 full.MinChi2ProbForSiliconTracks = 0
-full.MaxChi2PerHit = 500
+full.MaxChi2PerHit = 200
+full.ForceSiTPCMerging = True
+full.ForceTPCSegmentsMerging = True
 #full.OutputLevel = DEBUG
 
 from Configurables import TPCDndxAlg
@@ -248,14 +262,14 @@ tmt.MuonTagEfficiency = 0.95 # muon true tag efficiency, default is 1.0 (100%)
 tmt.MuonDetTanTheta = 1.2 # muon det barrel/endcap separation tan(theta)
 #tmt.OutputLevel = DEBUG
 
-from Configurables import ReadDigiAlg
-readtrk = ReadDigiAlg("ReadDigiAlg")
-readtrk.SiTracks = "SubsetTracks"
-readtrk.TPCTracks = "ClupatraTracks"
-readtrk.FullTracks = "CompleteTracks"
-readtrk.TPCTracksAssociation = "ClupatraTracksParticleAssociation"
-readtrk.FullTracksAssociation = "CompleteTracksParticleAssociation"
-readtrk.OutFileName = "TrackAnaTuple_mu.root"
+#from Configurables import ReadDigiAlg
+#readtrk = ReadDigiAlg("ReadDigiAlg")
+#readtrk.SiTracks = "SubsetTracks"
+#readtrk.TPCTracks = "ClupatraTracks"
+#readtrk.FullTracks = "CompleteTracks"
+#readtrk.TPCTracksAssociation = "ClupatraTracksParticleAssociation"
+#readtrk.FullTracksAssociation = "CompleteTracksParticleAssociation"
+#readtrk.OutFileName = "TrackAnaTuple_mu.root"
 
 # output
 from Configurables import PodioOutput
@@ -266,6 +280,10 @@ out.outputCommands = ["drop *",
   "keep ECALBarrelParticleAssoCol",
   "keep HCALBarrel",
   "keep HCALBarrelParticleAssoCol",
+  "keep ECALEndcaps",
+  "keep HCALEndcaps",
+  "keep ECALEndcapsParticleAssoCol",
+  "keep HCALEndcapsParticleAssoCol",
   "keep MCParticle",
   "keep CompleteTracks",
   "keep CompleteTracksParticleAssociation" ]
@@ -273,7 +291,7 @@ out.outputCommands = ["drop *",
 # ApplicationMgr
 from Configurables import ApplicationMgr
 mgr = ApplicationMgr(
-    TopAlg = [podioinput, digiVXD, digiSIT, digiSET, digiFTD, digiTPC, tracking, forward, subset, clupatra, full, tpr, tpc_dndx, tmt, readtrk, out],
+    TopAlg = [podioinput, digiVXD, digiSIT, digiSET, digiFTD, digiTPC, digiMuon, tracking, forward, subset, clupatra, full, tpr, tpc_dndx, tmt, out],
     EvtSel = 'NONE',
     EvtMax = 10,
     ExtSvc = [rndmengine, rndmgensvc, dsvc, evtseeder, geosvc, gearsvc, tracksystemsvc, pidsvc],
diff --git a/Reconstruction/RecPFACyber/src/Algorithm/PFOReclusteringAlg.cpp b/Reconstruction/RecPFACyber/src/Algorithm/PFOReclusteringAlg.cpp
index f7d59919..c87a00bc 100644
--- a/Reconstruction/RecPFACyber/src/Algorithm/PFOReclusteringAlg.cpp
+++ b/Reconstruction/RecPFACyber/src/Algorithm/PFOReclusteringAlg.cpp
@@ -8,15 +8,17 @@ StatusCode PFOReclusteringAlg::ReadSettings(Settings& m_settings){
 
   //Initialize parameters
   if(settings.map_stringPars.find("ReadinPFOName")==settings.map_stringPars.end()) settings.map_stringPars["ReadinPFOName"] = "outputPFO";
-  if(settings.map_floatPars.find("ECALCalib")==settings.map_floatPars.end()) settings.map_floatPars["ECALCalib"] = 1.02;
-  if(settings.map_floatPars.find("HCALCalib")==settings.map_floatPars.end()) settings.map_floatPars["HCALCalib"] = 65.;
+  if(settings.map_floatPars.find("ECALChargedCalib")==settings.map_floatPars.end()) settings.map_floatPars["ECALChargedCalib"] = 1.26;
+  if(settings.map_floatPars.find("HCALChargedCalib")==settings.map_floatPars.end()) settings.map_floatPars["HCALChargedCalib"] = 4.0;
+  if(settings.map_floatPars.find("ECALNeutralCalib")==settings.map_floatPars.end()) settings.map_floatPars["ECALNeutralCalib"] = 1.0;
+  if(settings.map_floatPars.find("HCALNeutralCalib")==settings.map_floatPars.end()) settings.map_floatPars["HCALNeutralCalib"] = 4.0;
   
   if(settings.map_floatPars.find("EnergyRes")==settings.map_floatPars.end()) settings.map_floatPars["EnergyRes"] = 0.4;
-  if(settings.map_floatPars.find("SplitSigma")==settings.map_floatPars.end()) settings.map_floatPars["SplitSigma"] = 0.;
+  if(settings.map_floatPars.find("SplitSigma")==settings.map_floatPars.end()) settings.map_floatPars["SplitSigma"] = 0.2;
   if(settings.map_floatPars.find("NeutralMergeSigma")==settings.map_floatPars.end()) settings.map_floatPars["NeutralMergeSigma"] = 0.;
-  if(settings.map_floatPars.find("VirtualMergeSigma")==settings.map_floatPars.end()) settings.map_floatPars["VirtualMergeSigma"] = 0.5;
-  if(settings.map_floatPars.find("MinAngleForNeuMerge")==settings.map_floatPars.end()) settings.map_floatPars["MinAngleForNeuMerge"] = 0.12;
-  if(settings.map_floatPars.find("MinAngleForVirMerge")==settings.map_floatPars.end()) settings.map_floatPars["MinAngleForVirMerge"] = 0.12;
+  if(settings.map_floatPars.find("VirtualMergeSigma")==settings.map_floatPars.end()) settings.map_floatPars["VirtualMergeSigma"] = 0.4;
+  if(settings.map_floatPars.find("MinAngleForNeuMerge")==settings.map_floatPars.end()) settings.map_floatPars["MinAngleForNeuMerge"] = 0.20;
+  if(settings.map_floatPars.find("MinAngleForVirMerge")==settings.map_floatPars.end()) settings.map_floatPars["MinAngleForVirMerge"] = 0.24;
 
 
   return StatusCode::SUCCESS;
@@ -40,88 +42,67 @@ StatusCode PFOReclusteringAlg::RunAlgorithm( CyberDataCol& m_datacol ){
   }
 
   std::sort(m_chargedPFOs.begin(), m_chargedPFOs.end(), compTrkP);
-/*
- double totE_Ecal = 0;
- double totE_Hcal = 0;
- cout<<"Readin PFO: "<<p_PFObjects->size()<<", charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<endl;
- for(int i=0; i<m_neutralPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
- totE_Ecal = 0;
- totE_Hcal = 0;
- for(int i=0; i<m_chargedPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
-*/
 
   //If P_trk < E_cluster, create a virtual neutral PFO. 
   ReCluster_SplitFromChg(m_chargedPFOs, m_neutralPFOs);
 
-/*
-  cout<<" PFO after ReCluster_SplitFromChg: "<<p_PFObjects->size()<<", charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<endl;
- totE_Ecal = 0;
- totE_Hcal = 0;
- cout<<"After split from Ch: charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<", total "<<p_PFObjects->size()<<endl;
- for(int i=0; i<m_neutralPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
- totE_Ecal = 0;
- totE_Hcal = 0;
- for(int i=0; i<m_chargedPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
-*/
+  // double totE_Ecal = 0;
+  // double totE_Hcal = 0;
+  // cout<<"PFO after splitting: "<<p_PFObjects->size()<<", charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<endl;
+  // for(int i=0; i<m_neutralPFOs.size(); i++){
+  //   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
+  //   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"]<<endl;
+  //   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"];
+  // }
+  // cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+  // totE_Ecal = 0;
+  // totE_Hcal = 0;
+  // for(int i=0; i<m_chargedPFOs.size(); i++){
+  //   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
+  //   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"]<<endl;
+  //   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"];
+  // }
+  // cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+
 
   //If P_trk > E_cluster, merge nearby neutral PFO into the charged. 
   ReCluster_MergeToChg(m_chargedPFOs, m_neutralPFOs);
 
   m_datacol.map_CaloHit["bkHit"].insert( m_datacol.map_CaloHit["bkHit"].end(), m_bkCol.map_CaloHit["bkHit"].begin(), m_bkCol.map_CaloHit["bkHit"].end() );
+  m_datacol.map_BarCol["bkBar"].insert( m_datacol.map_BarCol["bkBar"].end(), m_bkCol.map_BarCol["bkBar"].begin(), m_bkCol.map_BarCol["bkBar"].end() );
+  m_datacol.map_1DCluster["bk1DCluster"].insert( m_datacol.map_1DCluster["bk1DCluster"].end(), m_bkCol.map_1DCluster["bk1DCluster"].begin(), m_bkCol.map_1DCluster["bk1DCluster"].end() );
+  m_datacol.map_2DCluster["bk2DCluster"].insert( m_datacol.map_2DCluster["bk2DCluster"].end(), m_bkCol.map_2DCluster["bk2DCluster"].begin(), m_bkCol.map_2DCluster["bk2DCluster"].end() );
+  m_datacol.map_HalfCluster["bkHalfCluster"].insert( m_datacol.map_HalfCluster["bkHalfCluster"].end(), m_bkCol.map_HalfCluster["bkHalfCluster"].begin(), m_bkCol.map_HalfCluster["bkHalfCluster"].end() );
   m_datacol.map_CaloCluster["bk3DCluster"].insert( m_datacol.map_CaloCluster["bk3DCluster"].end(), m_bkCol.map_CaloCluster["bk3DCluster"].begin(), m_bkCol.map_CaloCluster["bk3DCluster"].end() );
   m_datacol.map_PFObjects["bkPFO"].insert( m_datacol.map_PFObjects["bkPFO"].end(), m_bkCol.map_PFObjects["bkPFO"].begin(), m_bkCol.map_PFObjects["bkPFO"].end() );
 
-/*
- double totE_Ecal = 0;
- double totE_Hcal = 0;
- cout<<"After merge all virtual to Ch: charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<", total "<<p_PFObjects->size()<<endl;
- for(int i=0; i<m_neutralPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
- totE_Ecal = 0;
- totE_Hcal = 0;
- for(int i=0; i<m_chargedPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
-*/
+
+  //double totE_Ecal = 0;
+  //double totE_Hcal = 0;
+  //cout<<"After merge all virtual to Ch: charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<", total "<<p_PFObjects->size()<<endl;
+  //for(int i=0; i<m_neutralPFOs.size(); i++){
+  //  cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
+  //  cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //  cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"]<<endl;
+  //  totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //  totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"];
+  //}
+  //cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+  //totE_Ecal = 0;
+  //totE_Hcal = 0;
+  //for(int i=0; i<m_chargedPFOs.size(); i++){
+  //  cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
+  //  cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //  cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"]<<endl;
+  //  totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //  totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"];
+  //}
+  //cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+
 
   m_chargedPFOs.clear();
   m_neutralPFOs.clear();
@@ -144,8 +125,8 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
     if(m_chargedPFOs[ic]->getECALClusters().size()==0 && m_chargedPFOs[ic]->getHCALClusters().size()==0) continue;
 
     double track_energy = m_chargedPFOs[ic]->getTrackMomentum();
-    double ECAL_energy = settings.map_floatPars["ECALCalib"]*m_chargedPFOs[ic]->getECALClusterEnergy();
-    double HCAL_energy = settings.map_floatPars["HCALCalib"]*m_chargedPFOs[ic]->getHCALClusterEnergy();
+    double ECAL_energy = settings.map_floatPars["ECALChargedCalib"]*m_chargedPFOs[ic]->getECALClusterEnergy();
+    double HCAL_energy = settings.map_floatPars["HCALChargedCalib"]*m_chargedPFOs[ic]->getHCALClusterEnergy();
     if(track_energy<0 || ECAL_energy<0 || HCAL_energy<0){
       std::cout<<"ERROR: Charged PFO info break. Ptrk "<<track_energy<<", E_ecal "<<ECAL_energy<<", E_hcal "<<HCAL_energy<<endl;
       continue;
@@ -158,7 +139,7 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
 //cout<<": ECAL cluster size "<<m_chargedPFOs[ic]->getECALClusters().size()<<", HCAL cluster size "<<m_chargedPFOs[ic]->getHCALClusters().size();
 //cout<<", Ptrk = "<<track_energy<<", Eecal = "<<ECAL_energy<<", Ehcal = "<<HCAL_energy<<", deltaE = "<<delta_energy<<", sigmaE = "<<sigmaE<<endl;
 
-    if(delta_energy >= settings.map_floatPars["NeutralMergeSigma"]*sigmaE) continue;
+    if(delta_energy - settings.map_floatPars["NeutralMergeSigma"]*sigmaE >= -1e-9) continue;
 //cout<<"    Do charged PFO merge. "<<endl;
 
     // All HCAL clusters in the neutral PFO
@@ -168,6 +149,10 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
       all_neutral_HCAL_clus.insert(all_neutral_HCAL_clus.end(), tmp_HCAL_clus.begin(), tmp_HCAL_clus.end());
     }
 //cout<<"      Neutral HCAL cluster size "<<all_neutral_HCAL_clus.size()<<endl;
+//cout<<"      Print all HCAL clusters "<<endl;
+//for(int acl=0; acl<all_neutral_HCAL_clus.size(); acl++){
+//printf("        Cluster #%d: energy %.8f, position (%.3f, %.3f, %.3f) \n", acl, settings.map_floatPars["HCALCalib"]*all_neutral_HCAL_clus[acl]->getHitsE(), all_neutral_HCAL_clus[acl]->getHitCenter().x(), all_neutral_HCAL_clus[acl]->getHitCenter().y(), all_neutral_HCAL_clus[acl]->getHitCenter().z() );
+//}
 
     TVector3 trackclus_pos(0, 0, 0);
     if(m_chargedPFOs[ic]->getECALClusters().size()>0){
@@ -175,17 +160,18 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
     }
     else{
       for(int jc=0; jc<m_chargedPFOs[ic]->getHCALClusters().size(); jc++)
-        trackclus_pos += m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitCenter() * settings.map_floatPars["HCALCalib"]*m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitsE();
+        trackclus_pos += m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitCenter() * settings.map_floatPars["HCALChargedCalib"]*m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitsE();
 
       trackclus_pos = trackclus_pos*(1./HCAL_energy);
     }
-//printf("    charged cluster trk pos: [%.3f, %.3f, %.3f] \n", trackclus_pos.x(), trackclus_pos.y(), trackclus_pos.z());  
+//printf("    charged cluster trk pos: [%.3f, %.3f, %.3f] \n", trackclus_pos.x(), trackclus_pos.y(), trackclus_pos.z());
 
     int loop_count = 0;
     std::vector<const Cyber::Calo3DCluster*> skip_clus;
     while(delta_energy < 0){
       loop_count++;
       if(loop_count>all_neutral_HCAL_clus.size()+10){
+//cout<<"    --- Out of loop number: "<<loop_count<<endl;
         break;
       }
       double min_angle = 999.0;
@@ -200,12 +186,13 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
           min_angle=pfo_angle;
           clus_index = in;
         }
+//printf("      Check neutral HCAL cluster #%d: energy %.8f, position (%.3f, %.3f, %.3f), angle with ch: %.4f, current closest cluster %d, minAngle %.4f \n", in, settings.map_floatPars["HCALCalib"]*all_neutral_HCAL_clus[in]->getHitsE(), all_neutral_HCAL_clus[in]->getHitCenter().x(), all_neutral_HCAL_clus[in]->getHitCenter().y(), all_neutral_HCAL_clus[in]->getHitCenter().z(), pfo_angle, clus_index, min_angle );
       }
 
-//cout<<"    In Loop "<<loop_count<<": current deltaE = "<<delta_energy<<", closest virtual cluster index "<<clus_index<<endl;
+//cout<<"    In Loop "<<loop_count<<": current deltaE = "<<delta_energy<<", closest virtual cluster index "<<clus_index<<", min Angle "<<min_angle<<endl;
       if(clus_index<0) break;  // No neutral Hcal cluster to be merged
 
-      double tmp_delta_E = delta_energy + settings.map_floatPars["HCALCalib"]*all_neutral_HCAL_clus[clus_index]->getHitsE();
+      double tmp_delta_E = delta_energy + settings.map_floatPars["HCALNeutralCalib"]*all_neutral_HCAL_clus[clus_index]->getHitsE();
       if (TMath::Abs(tmp_delta_E) >= TMath::Abs(delta_energy)){
         skip_clus.push_back(all_neutral_HCAL_clus[clus_index]);
         continue;  // No need to merge this HCAL cluster
@@ -214,7 +201,8 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
       // Update delta_energy
       delta_energy = tmp_delta_E;
       // Add this HCAL cluster to charged PFO
-      m_chargedPFOs[ic]->addHCALCluster(all_neutral_HCAL_clus[clus_index]);
+//cout<<"    Add neutral HCAL cluster #"<<clus_index<<" into charged PFO #"<<ic<<". Cluster E "<<settings.map_floatPars["HCALCalib"]*all_neutral_HCAL_clus[clus_index]->getHitsE()<<", deltaE "<<delta_energy<<endl;
+     m_chargedPFOs[ic]->addHCALCluster(all_neutral_HCAL_clus[clus_index]);
 
       // Remove this HCAL cluster from neutral PFO
       bool is_found = false;
@@ -256,29 +244,29 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
     }
   }
 
-/*
- double totE_Ecal = 0;
- double totE_Hcal = 0;
- cout<<"After merge real neu to Ch: charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<", total "<<p_PFObjects->size()<<endl;
- for(int i=0; i<m_neutralPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
- totE_Ecal = 0;
- totE_Hcal = 0;
- for(int i=0; i<m_chargedPFOs.size(); i++){
-   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy();
-   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy();
- }
- cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
-*/
+
+  // double totE_Ecal = 0;
+  // double totE_Hcal = 0;
+  // cout<<"After merge real neu to Ch: charged "<<m_chargedPFOs.size()<<", neutral "<<m_neutralPFOs.size()<<", total "<<p_PFObjects->size()<<endl;
+  // for(int i=0; i<m_neutralPFOs.size(); i++){
+  //   cout<<"    PFO #"<<i<<": track size "<<m_neutralPFOs[i]->getTracks().size()<<", leading P "<<m_neutralPFOs[i]->getTrackMomentum();
+  //   cout<<", ECAL cluster size "<<m_neutralPFOs[i]->getECALClusters().size()<<", totE "<<m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //   cout<<", HCAL cluster size "<<m_neutralPFOs[i]->getHCALClusters().size()<<", totE "<<m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"]<<endl;
+  //   totE_Ecal += m_neutralPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALNeutralCalib"];
+  //   totE_Hcal += m_neutralPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALNeutralCalib"];
+  // }
+  // cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+  // totE_Ecal = 0;
+  // totE_Hcal = 0;
+  // for(int i=0; i<m_chargedPFOs.size(); i++){
+  //   cout<<"    PFO #"<<i<<": track size "<<m_chargedPFOs[i]->getTracks().size()<<", leading P "<<m_chargedPFOs[i]->getTrackMomentum();
+  //   cout<<", ECAL cluster size "<<m_chargedPFOs[i]->getECALClusters().size()<<", totE "<<m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //   cout<<", HCAL cluster size "<<m_chargedPFOs[i]->getHCALClusters().size()<<", totE "<<m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"]<<endl;
+  //   totE_Ecal += m_chargedPFOs[i]->getECALClusterEnergy()*settings.map_floatPars["ECALChargedCalib"];
+  //   totE_Hcal += m_chargedPFOs[i]->getHCALClusterEnergy()*settings.map_floatPars["HCALChargedCalib"];
+  // }
+  // cout<<"-----Charged cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
+
 
 
   //Merge virtual neutral PFOs created from splitting. 
@@ -289,8 +277,8 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
         m_chargedPFOs[ic]->getTracks()[0]->getTrackStates("Hcal").size()==0) continue;
 
     double track_energy = m_chargedPFOs[ic]->getTrackMomentum();
-    double ECAL_energy = settings.map_floatPars["ECALCalib"]*m_chargedPFOs[ic]->getECALClusterEnergy();
-    double HCAL_energy = settings.map_floatPars["HCALCalib"]*m_chargedPFOs[ic]->getHCALClusterEnergy();
+    double ECAL_energy = settings.map_floatPars["ECALChargedCalib"]*m_chargedPFOs[ic]->getECALClusterEnergy();
+    double HCAL_energy = settings.map_floatPars["HCALChargedCalib"]*m_chargedPFOs[ic]->getHCALClusterEnergy();
     if(track_energy<0 || ECAL_energy<0 || HCAL_energy<0){
       std::cout<<"ERROR: Charged PFO info break. Ptrk "<<track_energy<<", E_ecal "<<ECAL_energy<<", E_hcal "<<HCAL_energy<<endl;
       continue;
@@ -336,7 +324,7 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
     }
     else{
       for(int jc=0; jc<m_chargedPFOs[ic]->getHCALClusters().size(); jc++)
-        trackclus_pos += m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitCenter() * settings.map_floatPars["HCALCalib"]*m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitsE();
+        trackclus_pos += m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitCenter() * settings.map_floatPars["HCALChargedCalib"]*m_chargedPFOs[ic]->getHCALClusters()[jc]->getHitsE();
 
       trackclus_pos = trackclus_pos*(1./HCAL_energy);
     }
@@ -366,7 +354,7 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
 
       if(clus_index<0) break;  // No neutral Hcal cluster to be merged
 
-      double tmp_delta_E = delta_energy + settings.map_floatPars["HCALCalib"]*all_neutral_HCAL_clus[clus_index]->getHitsE();
+      double tmp_delta_E = delta_energy + settings.map_floatPars["HCALNeutralCalib"]*all_neutral_HCAL_clus[clus_index]->getHitsE();
 // cout<<"    If include this cluster: new deltaE "<<tmp_delta_E<<", merge = "<<(tmp_delta_E > sigmaE * settings.map_floatPars["VirtualMergeSigma"])<<endl;
 
       if(tmp_delta_E > sigmaE * settings.map_floatPars["VirtualMergeSigma"]){
@@ -377,7 +365,7 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
         //Create a new virtual neutral cluster with energy = absorbed_energy. 
 
         std::shared_ptr<Cyber::CaloHit> m_hit = all_neutral_HCAL_clus[clus_index]->getCaloHits()[0]->Clone();
-        m_hit->setEnergy(absorbed_energy/settings.map_floatPars["HCALCalib"]);
+        m_hit->setEnergy(absorbed_energy/settings.map_floatPars["HCALNeutralCalib"]);
 
         std::shared_ptr<Cyber::Calo3DCluster> m_clus = std::make_shared<Cyber::Calo3DCluster>();
         m_clus->addHit(m_hit.get());
@@ -399,7 +387,7 @@ StatusCode PFOReclusteringAlg::ReCluster_MergeToChg(std::vector< std::shared_ptr
 
           if(tmp_HCAL_clus[0]==all_neutral_HCAL_clus[clus_index]){
             std::shared_ptr<Cyber::CaloHit> m_newhit = all_neutral_HCAL_clus[clus_index]->getCaloHits()[0]->Clone();
-            m_newhit->setEnergy(all_neutral_HCAL_clus[clus_index]->getHitsE() - absorbed_energy/settings.map_floatPars["HCALCalib"] );
+            m_newhit->setEnergy(all_neutral_HCAL_clus[clus_index]->getHitsE() - absorbed_energy/settings.map_floatPars["HCALNeutralCalib"] );
             std::shared_ptr<Cyber::Calo3DCluster> m_newclus = std::make_shared<Cyber::Calo3DCluster>();
             m_newclus->addHit(m_newhit.get());
             m_newclus->setType(-1);            
@@ -490,15 +478,15 @@ StatusCode PFOReclusteringAlg::ReCluster_SplitFromChg( std::vector< std::shared_
     if(m_chargedPFOs[ipfo]->getECALClusters().size()==0 && m_chargedPFOs[ipfo]->getHCALClusters().size()==0) continue;
 
     double track_energy = m_chargedPFOs[ipfo]->getTrackMomentum();
-    double ECAL_energy = settings.map_floatPars["ECALCalib"]*m_chargedPFOs[ipfo]->getECALClusterEnergy();
-    double HCAL_energy = settings.map_floatPars["HCALCalib"]*m_chargedPFOs[ipfo]->getHCALClusterEnergy();
+    double ECAL_energy = settings.map_floatPars["ECALChargedCalib"]*m_chargedPFOs[ipfo]->getECALClusterEnergy();
+    double HCAL_energy = settings.map_floatPars["HCALChargedCalib"]*m_chargedPFOs[ipfo]->getHCALClusterEnergy();
     if(track_energy<0 || ECAL_energy<0 || HCAL_energy<0){
       std::cout<<"ERROR: Charged PFO info break. Ptrk "<<track_energy<<", E_ecal "<<ECAL_energy<<", E_hcal "<<HCAL_energy<<endl;
       continue;
     }
 
     double delta_energy = ECAL_energy + HCAL_energy - track_energy;
-    double sigmaE = settings.map_floatPars["EnergyRes"] * sqrt(ECAL_energy + HCAL_energy);
+    double sigmaE = settings.map_floatPars["EnergyRes"] * sqrt(track_energy);
     
 //cout<<"  ReCluster_MergeToChg: In ChPFO #"<<ipfo<<": Ptrk = "<<track_energy<<", Eecal = "<<ECAL_energy<<", Ehcal = "<<HCAL_energy<<", deltaE = "<<delta_energy<<", sigmaE = "<<sigmaE<<endl;
 
@@ -506,54 +494,127 @@ StatusCode PFOReclusteringAlg::ReCluster_SplitFromChg( std::vector< std::shared_
 //cout<<"    Do charged PFO splitting. "<<endl;
 
     //Create a new hit and cluster
-    TVector3 tmp_pos(0,0,0); 
+    TVector3 tmp_pos(0,0,0);
     for(int ic=0; ic<m_chargedPFOs[ipfo]->getECALClusters().size(); ic++)
-      tmp_pos += settings.map_floatPars["ECALCalib"] * m_chargedPFOs[ipfo]->getECALClusters()[ic]->getLongiE() * m_chargedPFOs[ipfo]->getECALClusters()[ic]->getShowerCenter();
-    for(int ic=0; ic<m_chargedPFOs[ipfo]->getHCALClusters().size(); ic++) 
-      tmp_pos += settings.map_floatPars["HCALCalib"] * m_chargedPFOs[ipfo]->getHCALClusters()[ic]->getHitsE() * m_chargedPFOs[ipfo]->getHCALClusters()[ic]->getHitCenter();
+      tmp_pos += settings.map_floatPars["ECALChargedCalib"] * m_chargedPFOs[ipfo]->getECALClusters()[ic]->getLongiE() * m_chargedPFOs[ipfo]->getECALClusters()[ic]->getShowerCenter();
+    for(int ic=0; ic<m_chargedPFOs[ipfo]->getHCALClusters().size(); ic++)
+      tmp_pos += settings.map_floatPars["HCALChargedCalib"] * m_chargedPFOs[ipfo]->getHCALClusters()[ic]->getHitsE() * m_chargedPFOs[ipfo]->getHCALClusters()[ic]->getHitCenter();
     tmp_pos = tmp_pos*(1./(ECAL_energy+HCAL_energy));
 
-    std::shared_ptr<Cyber::CaloHit> m_hit = std::make_shared<Cyber::CaloHit>();
-    m_hit->setPosition( tmp_pos );
-    m_hit->setEnergy( delta_energy/settings.map_floatPars["HCALCalib"] );
+    if(ECAL_energy>0 || HCAL_energy>0){
+      //Create a new ECAL virtual PFO
+      if(ECAL_energy>0){
+        double tmp_virtualE = delta_energy * ECAL_energy / (ECAL_energy + HCAL_energy) / settings.map_floatPars["ECALChargedCalib"];
+        // -- Create bar
+        std::shared_ptr<Cyber::CaloUnit> m_bar_u = std::make_shared<Cyber::CaloUnit>();
+        std::shared_ptr<Cyber::CaloUnit> m_bar_v = std::make_shared<Cyber::CaloUnit>();
+        m_bar_u->setQ(tmp_virtualE/4., tmp_virtualE/4);
+        m_bar_u->setPosition(tmp_pos);
+        m_bar_v->setQ(tmp_virtualE/4., tmp_virtualE/4);
+        m_bar_v->setPosition(tmp_pos);
+   
+        // -- Create 1D cluster U/V
+        std::shared_ptr<Cyber::Calo1DCluster> m_1dclus_u = std::make_shared<Cyber::Calo1DCluster>();
+        std::shared_ptr<Cyber::Calo1DCluster> m_1dclus_v = std::make_shared<Cyber::Calo1DCluster>();
+        m_1dclus_u->addUnit(m_bar_u.get());
+        m_1dclus_v->addUnit(m_bar_v.get());
+   
+        // -- Create 2D cluster 
+        std::shared_ptr<Cyber::Calo2DCluster> m_2dclus = std::make_shared<Cyber::Calo2DCluster>();
+        m_2dclus->addShowerU(m_1dclus_u.get());
+        m_2dclus->addShowerV(m_1dclus_v.get());
+        m_2dclus->addTowerID(0., 0., 0.);
+        m_2dclus->setPos(tmp_pos);
+   
+        // -- Create Half cluster U/V
+        std::shared_ptr<Cyber::CaloHalfCluster> m_hfclus_u = std::make_shared<Cyber::CaloHalfCluster>();
+        std::shared_ptr<Cyber::CaloHalfCluster> m_hfclus_v = std::make_shared<Cyber::CaloHalfCluster>();
+        m_hfclus_u->addUnit(m_1dclus_u.get());
+        m_hfclus_v->addUnit(m_1dclus_v.get());
+   
+        // -- Create ECAL 3D cluster
+        std::shared_ptr<Cyber::Calo3DCluster> m_clus = std::make_shared<Cyber::Calo3DCluster>();
+        m_clus->addHalfClusterU("LinkedLongiCluster", m_hfclus_u.get());
+        m_clus->addHalfClusterV("LinkedLongiCluster", m_hfclus_v.get());
+        m_clus->addUnit(m_2dclus.get());
+        m_clus->setType(-1);
+   
+        std::shared_ptr<Cyber::PFObject> m_pfo = std::make_shared<Cyber::PFObject>();
+        m_pfo->addECALCluster( m_clus.get() );
+   
+        m_neutralPFOs.push_back( m_pfo );
+        p_PFObjects->push_back( m_pfo );
+        
+//cout<<"  In ChPFO #"<<ipfo<<": create a neutral ECAL PFO. En "<<m_pfo->getECALClusterEnergy()*settings.map_floatPars["ECALCalib"]<<endl;
+   
+        m_bkCol.map_BarCol["bkBar"].push_back( m_bar_u );
+        m_bkCol.map_BarCol["bkBar"].push_back( m_bar_v );
+        m_bkCol.map_1DCluster["bk1DCluster"].push_back( m_1dclus_u );
+        m_bkCol.map_1DCluster["bk1DCluster"].push_back( m_1dclus_v );
+        m_bkCol.map_HalfCluster["bkHalfCluster"].push_back( m_hfclus_u );
+        m_bkCol.map_HalfCluster["bkHalfCluster"].push_back( m_hfclus_v );
+        m_bkCol.map_2DCluster["bk2DCluster"].push_back( m_2dclus );
+        m_bkCol.map_CaloCluster["bk3DCluster"].push_back(m_clus);
+        m_bkCol.map_PFObjects["bkPFO"].push_back(m_pfo);
+      }
+
+      //Create a new virtual HCAL PFO
+      if(HCAL_energy>0){
+        double tmp_virtualE = delta_energy * HCAL_energy / (ECAL_energy + HCAL_energy) / settings.map_floatPars["HCALChargedCalib"];
+        std::shared_ptr<Cyber::CaloHit> m_hit = std::make_shared<Cyber::CaloHit>();
+        m_hit->setPosition( tmp_pos );
+        m_hit->setEnergy( tmp_virtualE );
+
+        std::shared_ptr<Cyber::Calo3DCluster> m_clus_hcal = std::make_shared<Cyber::Calo3DCluster>();
+        m_clus_hcal->addHit(m_hit.get());
+        m_clus_hcal->setType(-1);
 
-    std::shared_ptr<Cyber::Calo3DCluster> m_clus = std::make_shared<Cyber::Calo3DCluster>();
-    m_clus->addHit(m_hit.get());
-    m_clus->setType(-1);
+        std::shared_ptr<Cyber::PFObject> m_pfo_hcal = std::make_shared<Cyber::PFObject>();
+        m_pfo_hcal->addHCALCluster( m_clus_hcal.get() );
 
-    std::shared_ptr<Cyber::PFObject> m_pfo = std::make_shared<Cyber::PFObject>();
-    m_pfo->addHCALCluster( m_clus.get() );
-//cout<<"Create a new Neutral PFO: energy "<<m_pfo->getHCALClusterEnergy()<<endl;
+        m_neutralPFOs.push_back( m_pfo_hcal );
+        p_PFObjects->push_back( m_pfo_hcal );
 
-    m_neutralPFOs.push_back( m_pfo );   
-    p_PFObjects->push_back( m_pfo );
+//cout<<"  In ChPFO #"<<ipfo<<": create a neutral HCAL PFO. En "<<m_pfo_hcal->getHCALClusterEnergy()*settings.map_floatPars["HCALCalib"]<<endl;
 
-    //For this charged PFO: reset HCAL energy. (negative HCAL energy is NOT allowed) 
-    if(HCAL_energy>0 && HCAL_energy-delta_energy>0){
-      double m_HcalEnScale = (HCAL_energy-delta_energy)/HCAL_energy;
-//cout<<"[FY debug] In PFO "<<ipfo<<": track P "<<m_chargedPFOs[ipfo]->getTrackMomentum()<<", HCAL cluster size "<<m_chargedPFOs[ipfo]->getHCALClusters().size()<<", first HCAL has Nhit "<<m_chargedPFOs[ipfo]->getHCALClusters()[0]->getCaloHits().size()<<endl;
-//cout<<"[FY debug] Hcal energy scale = "<<m_HcalEnScale<<endl;
+        m_bkCol.map_CaloHit["bkHit"].push_back( m_hit );
+        m_bkCol.map_CaloCluster["bk3DCluster"].push_back(m_clus_hcal);
+        m_bkCol.map_PFObjects["bkPFO"].push_back(m_pfo_hcal);
+      }
 
-      //Create new HCAL cluster
+      //Reset origin cluster energy
+      double m_EnScale = (ECAL_energy + HCAL_energy - delta_energy)/(ECAL_energy + HCAL_energy);
+//cout<<"[FY debug] In PFO "<<ipfo<<": track P "<<m_chargedPFOs[ipfo]->getTrackMomentum()<<", HCAL cluster size "<<m_chargedPFOs[ipfo]->getHCALClusters().size()<<endl;
+//", first HCAL has Nhit "<<m_chargedPFOs[ipfo]->getHCALClusters()[0]->getCaloHits().size()<<endl;
+//cout<<"[FY debug] Hcal energy scale = "<<m_EnScale<<endl;
+
+      //Create a new PFO
+      std::shared_ptr<Cyber::PFObject> m_newpfo = m_chargedPFOs[ipfo]->Clone();
+      // -- Reset ECAL cluster
+      std::vector<const Cyber::Calo3DCluster*> tmp_clusvec; tmp_clusvec.clear();
+      for(int ic=0; ic<m_chargedPFOs[ipfo]->getECALClusters().size(); ic++){
+        std::shared_ptr<Cyber::Calo3DCluster> m_newclus = m_chargedPFOs[ipfo]->getECALClusters()[ic]->Clone();
+        m_newclus->setEnergyScale( m_EnScale*m_newclus->getEnergyScale() );
+        tmp_clusvec.push_back(m_newclus.get()); 
+        m_bkCol.map_CaloCluster["bk3DCluster"].push_back(m_newclus);
+      }
+      m_newpfo->setECALCluster(tmp_clusvec);
+    
+      // -- Reset HCAL cluster
       std::shared_ptr<Cyber::Calo3DCluster> m_newclus = std::make_shared<Cyber::Calo3DCluster>();
       for(int ic=0; ic<m_chargedPFOs[ipfo]->getHCALClusters().size(); ic++){
         std::vector<const Cyber::CaloHit*> tmp_hits = m_chargedPFOs[ipfo]->getHCALClusters()[ic]->getCaloHits();
         for(int ih=0; ih<tmp_hits.size(); ih++){
           std::shared_ptr<CaloHit> tmp_newhit = tmp_hits[ih]->Clone();
-          tmp_newhit->setEnergy( tmp_newhit->getEnergy()*m_HcalEnScale );
+          tmp_newhit->setEnergy( tmp_newhit->getEnergy()*m_EnScale );
           m_newclus->addHit(tmp_newhit.get());
           m_bkCol.map_CaloHit["bkHit"].push_back( tmp_newhit );
         }
       }
       m_bkCol.map_CaloCluster["bk3DCluster"].push_back(m_newclus);
-
-//cout<<"[FY debug] new HCAL cluster: hit size "<<m_newclus->getCaloHits().size()<<", total energy "<<m_newclus->getHitsE()<<endl;
-
-      //Create a new PFO
-      std::shared_ptr<Cyber::PFObject> m_newpfo = m_chargedPFOs[ipfo]->Clone();
-      std::vector<const Cyber::Calo3DCluster*> tmp_clusvec; tmp_clusvec.clear(); 
-      tmp_clusvec.push_back(m_newclus.get());
-      m_newpfo->setHCALCluster(tmp_clusvec);
+      std::vector<const Cyber::Calo3DCluster*> tmp_hcalclus; tmp_hcalclus.clear();
+      tmp_hcalclus.push_back(m_newclus.get());
+      m_newpfo->setHCALCluster(tmp_hcalclus);
 
       m_bkCol.map_PFObjects["bkPFO"].push_back(m_newpfo);
 
@@ -566,15 +627,10 @@ StatusCode PFOReclusteringAlg::ReCluster_SplitFromChg( std::vector< std::shared_
 //cout<<"[FY debug] The splitted new charged PFO: track size "<<m_newpfo->getTracks().size()<<", leading P "<<m_newpfo->getTrackMomentum();
 //cout<<", ECAL cluster size "<<m_newpfo->getECALClusters().size()<<", totE "<<m_newpfo->getECALClusterEnergy();
 //cout<<", HCAL cluster size "<<m_newpfo->getHCALClusters().size()<<", totE "<<m_newpfo->getHCALClusterEnergy()<<endl;
+//cout<<endl;
     }
-
-    m_bkCol.map_CaloHit["bkHit"].push_back( m_hit );
-    m_bkCol.map_CaloCluster["bk3DCluster"].push_back(m_clus);
-    m_bkCol.map_PFObjects["bkPFO"].push_back(m_pfo);
   }
 
-
-
   return StatusCode::SUCCESS;
 };
 
diff --git a/Reconstruction/RecPFACyber/src/Algorithm/TrackClusterConnectingAlg.cpp b/Reconstruction/RecPFACyber/src/Algorithm/TrackClusterConnectingAlg.cpp
index 5d3ff580..c4a68647 100644
--- a/Reconstruction/RecPFACyber/src/Algorithm/TrackClusterConnectingAlg.cpp
+++ b/Reconstruction/RecPFACyber/src/Algorithm/TrackClusterConnectingAlg.cpp
@@ -9,11 +9,15 @@ StatusCode TrackClusterConnectingAlg::ReadSettings(Settings& m_settings){
   //Initialize parameters
   if(settings.map_stringPars.find("ReadinECALClusterName")==settings.map_stringPars.end()) settings.map_stringPars["ReadinECALClusterName"] = "EcalCluster";
   if(settings.map_stringPars.find("ReadinHCALClusterName")==settings.map_stringPars.end()) settings.map_stringPars["ReadinHCALClusterName"] = "HcalCluster";
+  if(settings.map_floatPars.find("ECALChargedCalib")==settings.map_floatPars.end()) settings.map_floatPars["ECALChargedCalib"] = 1.26;
+  if(settings.map_floatPars.find("HCALChargedCalib")==settings.map_floatPars.end()) settings.map_floatPars["HCALChargedCalib"] = 4.0;
+  if(settings.map_floatPars.find("ECALNeutralCalib")==settings.map_floatPars.end()) settings.map_floatPars["ECALNeutralCalib"] = 1.0;
+  if(settings.map_floatPars.find("HCALNeutralCalib")==settings.map_floatPars.end()) settings.map_floatPars["HCALNeutralCalib"] = 4.0;
 
   if(settings.map_floatPars.find("th_ChFragEn")==settings.map_floatPars.end()) settings.map_floatPars["th_ChFragEn"] = 2.;
   if(settings.map_floatPars.find("th_ChFragDepth")==settings.map_floatPars.end()) settings.map_floatPars["th_ChFragDepth"] = 100.;
   if(settings.map_floatPars.find("th_ChFragMinR")==settings.map_floatPars.end()) settings.map_floatPars["th_ChFragMinR"] = 200.;
-  if(settings.map_floatPars.find("th_HcalMatchingR")==settings.map_floatPars.end()) settings.map_floatPars["th_HcalMatchingR"] = 150.;
+  if(settings.map_floatPars.find("th_HcalMatchingR")==settings.map_floatPars.end()) settings.map_floatPars["th_HcalMatchingR"] = 100.;
 
   if(settings.map_floatPars.find("th_MIPEnergy")==settings.map_floatPars.end()) settings.map_floatPars["th_MIPEnergy"] = 0.5;
   if(settings.map_floatPars.find("th_AbsorbCone")==settings.map_floatPars.end()) settings.map_floatPars["th_AbsorbCone"] = 0.8;
@@ -43,6 +47,8 @@ StatusCode TrackClusterConnectingAlg::Initialize( CyberDataCol& m_datacol ){
     m_tracks.push_back( m_datacol.TrackCol[itrk].get() );
   }
 
+  m_bkCol.EnergyCorrSvc = m_datacol.EnergyCorrSvc;
+
 //cout<<"Readin Track size: "<<m_tracks.size()<<", ECAL cluster size: "<<m_EcalClusters.size()<<", HCAL cluster size "<<m_HcalClusters.size()<<endl;
 //cout<<"Print track"<<endl;
 //for(int i=0; i<m_tracks.size(); i++)
@@ -305,6 +311,18 @@ StatusCode TrackClusterConnectingAlg::EcalChFragAbsorption( std::vector<const Cy
       }
     }
   }
+
+  //Do cluster energy correction
+  for(int ic=0; ic<m_newclusCol.size(); ic++){
+    double tmp_clusE = m_newclusCol[ic]->getEnergy()*settings.map_floatPars.at("ECALNeutralCalib");
+    TVector3 clus_pos = m_newclusCol[ic]->getShowerCenter();
+    double tmp_phi = std::atan2(clus_pos.y(), clus_pos.x())* 180.0 / TMath::Pi(); //TODO: use TVector3 to calculate
+    if (tmp_phi < 0) tmp_phi += 360.0;
+    double tmp_theta = std::atan2(clus_pos.z(), clus_pos.Perp())* 180.0 / TMath::Pi() + 90;  
+
+    double tmp_scale = m_bkCol.EnergyCorrSvc->energyCorrection(tmp_clusE, tmp_phi, tmp_theta)/tmp_clusE;
+    m_newclusCol[ic]->setEnergyScale( tmp_scale );
+  }
 //for(int ic=0; ic<m_newclusCol.size(); ic++){
 //  cout<<"    ECAL Cluster #"<<ic<<": En = "<<m_newclusCol[ic]->getLongiE()<<", track size "<<m_newclusCol[ic]->getAssociatedTracks().size()<<endl;
 //}
diff --git a/Reconstruction/RecPFACyber/src/CyberPFAlg.cpp b/Reconstruction/RecPFACyber/src/CyberPFAlg.cpp
index 70185d2c..cf64cb4c 100644
--- a/Reconstruction/RecPFACyber/src/CyberPFAlg.cpp
+++ b/Reconstruction/RecPFACyber/src/CyberPFAlg.cpp
@@ -12,8 +12,8 @@ using namespace dd4hep;
 int Cyber::CaloUnit::Nmodule = 32;
 int Cyber::CaloUnit::Nstave = 15;
 int Cyber::CaloUnit::Nlayer = 14;
-int Cyber::CaloUnit::NbarPhi_odd[14] = {39, 39, 39, 39, 37, 37, 37, 37, 37, 35, 35, 35, 35, 33};
-int Cyber::CaloUnit::NbarPhi_even[14] = {29, 29, 31, 31, 33, 35, 35, 37, 37, 39, 41, 41, 43, 43};
+int Cyber::CaloUnit::NbarPhi_odd[14] = {39, 37, 37, 37, 37, 37, 35, 35, 35, 35, 33, 33, 33, 33};
+int Cyber::CaloUnit::NbarPhi_even[14] = {27, 29, 29, 31, 31, 33, 35, 35, 37, 37, 39, 41, 41, 43};
 int Cyber::CaloUnit::NbarZ = 36;
 //int Cyber::CaloUnit::over_module[28] = {13,15,16,18,19,21,22,24,25,26,28,29,30,32,33,35,36,38,39,41,42,43,45,46};
 //int Cyber::CaloUnit::over_module_set = 2;
@@ -51,16 +51,22 @@ StatusCode CyberPFAlg::initialize()
   m_pMCParticleCreatorSettings.map_stringPars["MCParticleCollections"] = name_MCParticleCol.value();
 
   m_pTrackCreatorSettings.map_stringVecPars["trackCollections"] = name_TrackCol.value();
+  m_pTrackCreatorSettings.map_boolPars["DoCleanTrack"] = m_doCleanTrack.value();
+  m_pTrackCreatorSettings.map_boolPars["UseTruthMatchTrk"] = m_useTruthMatchTrk.value();
+  m_pTrackCreatorSettings.map_stringPars["TrackIDWeightFile"] = m_trackIDFile.value();
+  m_pTrackCreatorSettings.map_stringPars["TrackIDMethod"] = m_trackIDMethod.value();
   m_pTrackCreatorSettings.map_floatPars["BField"] = m_BField; 
-  m_pTrackCreatorSettings.map_floatPars["TrkEndZCut"] = 200.;
-  m_pTrackCreatorSettings.map_floatPars["TrkEndRCutMin"] = 700.;
-  m_pTrackCreatorSettings.map_floatPars["TrkEndRCutMax"] = 1600.;
-  m_pTrackCreatorSettings.map_floatPars["TrkStartRCutMin"] = 635.;
-  m_pTrackCreatorSettings.map_floatPars["TrkStartRCutMax"] = 640.;
-  m_pTrackCreatorSettings.map_floatPars["TrkLengthCut"] = 130.;
-  m_pTrackCreatorSettings.map_floatPars["BrokenTrkMinP"] = 0.5;
-  m_pTrackCreatorSettings.map_floatPars["BrokenTrkDeltaPCut"] = 0.15;
-  m_pTrackCreatorSettings.map_floatPars["BrokenTrkDistance"] = 10.;
+  m_pTrackCreatorSettings.map_floatPars["TrkMaxIP"] = 100.;
+  m_pTrackCreatorSettings.map_floatPars["BDTCut"] = -0.8289;
+  //m_pTrackCreatorSettings.map_floatPars["TrkEndZCut"] = 200.;
+  //m_pTrackCreatorSettings.map_floatPars["TrkEndRCutMin"] = 700.;
+  //m_pTrackCreatorSettings.map_floatPars["TrkEndRCutMax"] = 1600.;
+  //m_pTrackCreatorSettings.map_floatPars["TrkStartRCutMin"] = 635.;
+  //m_pTrackCreatorSettings.map_floatPars["TrkStartRCutMax"] = 640.;
+  //m_pTrackCreatorSettings.map_floatPars["TrkLengthCut"] = 130.;
+  //m_pTrackCreatorSettings.map_floatPars["BrokenTrkMinP"] = 0.5;
+  //m_pTrackCreatorSettings.map_floatPars["BrokenTrkDeltaPCut"] = 0.15;
+  //m_pTrackCreatorSettings.map_floatPars["BrokenTrkDistance"] = 10.;
 
   std::vector<std::string> name_CaloHits = name_EcalHits; 
   std::vector<std::string> name_CaloReadout = name_EcalReadout;
@@ -71,10 +77,13 @@ StatusCode CyberPFAlg::initialize()
   m_CaloHitsCreatorSettings.map_stringPars["EcalType"] = m_EcalType.value();
 
   m_OutputCreatorSettings.map_stringPars["OutputPFO"] = name_PFObject.value();
-  m_OutputCreatorSettings.map_boolPars["UseTruthTrk"] = m_useTruthTrk.value();
+  m_OutputCreatorSettings.map_boolPars["UseTruthTrk"] = m_useMCPTrk.value();
+  m_OutputCreatorSettings.map_boolPars["UseTruthMatchTrk"] = m_useTruthMatchTrk.value();
   m_OutputCreatorSettings.map_floatPars["BField"] = m_BField.value();
-  m_OutputCreatorSettings.map_floatPars["ECALCalib"] = m_EcalCalib.value();
-  m_OutputCreatorSettings.map_floatPars["HCALCalib"] = m_HcalCalib.value();
+  m_OutputCreatorSettings.map_floatPars["ECALChargedCalib"] = m_EcalChargedCalib.value();
+  m_OutputCreatorSettings.map_floatPars["HCALChargedCalib"] = m_HcalChargedCalib.value();
+  m_OutputCreatorSettings.map_floatPars["ECALNeutralCalib"] = m_EcalNeutralCalib.value();
+  m_OutputCreatorSettings.map_floatPars["HCALNeutralCalib"] = m_HcalNeutralCalib.value();
 
   //Initialize Creators
   m_pMCParticleCreator = new MCParticleCreator( m_pMCParticleCreatorSettings );
@@ -157,6 +166,12 @@ StatusCode CyberPFAlg::initialize()
   m_geosvc = service<IGeomSvc>("GeomSvc");
   if ( !m_geosvc )  throw "CyberPFAlg :Failed to find GeomSvc ...";
 
+  m_dd4hep = m_geosvc->lcdd();
+  if ( !m_dd4hep )  throw "CyberPFAlg :Failed to get dd4hep::Detector ...";
+
+  m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep);
+  m_volumeManager = m_dd4hep->volumeManager();
+
   m_energycorsvc = service<ICrystalEcalSvc>("CrystalEcalEnergyCorrectionSvc");
   if ( !m_energycorsvc )  throw "CyberPFAlg :Failed to find CrystalEcalEnergyCorrectionSvc ...";
   //m_energycorsvc->initialize();
@@ -207,6 +222,9 @@ StatusCode CyberPFAlg::initialize()
     t_MCParticle->Branch("mcEn", &m_mcEn);
     t_MCParticle->Branch("mcMass", &m_mcMass);
     t_MCParticle->Branch("mcCharge", &m_mcCharge);
+    t_MCParticle->Branch("mcVTXx", &m_mcVTXx);
+    t_MCParticle->Branch("mcVTXy", &m_mcVTXy);
+    t_MCParticle->Branch("mcVTXz", &m_mcVTXz);
     t_MCParticle->Branch("mcEPx", &m_mcEPx);
     t_MCParticle->Branch("mcEPy", &m_mcEPy);
     t_MCParticle->Branch("mcEPz", &m_mcEPz);
@@ -610,6 +628,7 @@ StatusCode CyberPFAlg::initialize()
     // Tracks
     t_Track->Branch("m_Ntrk", &m_Ntrk);
     t_Track->Branch("m_type", &m_type);
+    t_Track->Branch("m_Nhit", &m_Nhit);
     t_Track->Branch("m_trkstate_d0", &m_trkstate_d0);
     t_Track->Branch("m_trkstate_z0", &m_trkstate_z0);
     t_Track->Branch("m_trkstate_phi", &m_trkstate_phi);
@@ -678,9 +697,9 @@ StatusCode CyberPFAlg::execute()
 
   //Readin collections 
   m_pMCParticleCreator->CreateMCParticle( m_DataCol, *r_MCParticleCol );
-  if(m_useTruthTrk) m_pTrackCreator->CreateTracksFromMCParticle(m_DataCol, *r_MCParticleCol);
+  if(m_useMCPTrk) m_pTrackCreator->CreateTracksFromMCParticle(m_DataCol, *r_MCParticleCol);
   else m_pTrackCreator->CreateTracks( m_DataCol, r_TrackCols, r_MCPTrkAssoCol );
-  m_pCaloHitsCreator->CreateCaloHits( m_DataCol, r_CaloHitCols, map_readout_decoder, map_CaloMCPAssoCols );
+  m_pCaloHitsCreator->CreateCaloHits( m_DataCol, r_CaloHitCols, map_readout_decoder, map_CaloMCPAssoCols, m_volumeManager);
 
   //Perform PFA algorithm
   m_algorithmManager.RunAlgorithm( m_DataCol );
@@ -710,6 +729,9 @@ StatusCode CyberPFAlg::execute()
       m_mcEn.push_back( m_MCPCol[imc].getEnergy() );
       m_mcMass.push_back( m_MCPCol[imc].getMass() );
       m_mcCharge.push_back( m_MCPCol[imc].getCharge() );
+      m_mcVTXx.push_back( m_MCPCol[imc].getVertex()[0] );
+      m_mcVTXy.push_back( m_MCPCol[imc].getVertex()[1] );
+      m_mcVTXz.push_back( m_MCPCol[imc].getVertex()[2] );
       m_mcEPx.push_back( m_MCPCol[imc].getEndpoint()[0] );
       m_mcEPy.push_back( m_MCPCol[imc].getEndpoint()[1] );
       m_mcEPz.push_back( m_MCPCol[imc].getEndpoint()[2] );
@@ -1377,7 +1399,8 @@ StatusCode CyberPFAlg::execute()
       if (tmp_phi < 0) tmp_phi += 360.0;
       double tmp_theta = std::atan2(m_EcalClusterCol[icl]->getShowerCenter().z(), m_EcalClusterCol[icl]->getShowerCenter().Perp())* 180.0 / M_PI + 90; 
       //cout<<" Theta: "<<tmp_theta<<" Phi: "<<tmp_phi<<endl;
-      m_EcalClus_Escale.push_back(m_energycorsvc->energyCorrection(m_EcalClusterCol[icl]->getLongiE(), tmp_phi, tmp_theta));
+      //m_EcalClus_Escale.push_back(m_energycorsvc->energyCorrection(m_EcalClusterCol[icl]->getLongiE(), tmp_phi, tmp_theta));
+      m_EcalClus_Escale.push_back(m_EcalClusterCol[icl]->getLongiE());
    
    
       if(m_EcalClusterCol[icl]->getAssociatedTracks().size()==1){
@@ -1518,6 +1541,7 @@ StatusCode CyberPFAlg::execute()
     m_Ntrk = m_trkCol.size();
     for(int itrk=0; itrk<m_Ntrk; itrk++){
       m_type.push_back(m_trkCol[itrk]->getType());
+      m_Nhit.push_back(m_trkCol[itrk]->getTrackerHits());
       std::vector<TrackState> AllTrackStates = m_trkCol[itrk]->getAllTrackStates();
       for(int istate=0; istate<AllTrackStates.size(); istate++){
         m_trkstate_d0.push_back( AllTrackStates[istate].D0 );
@@ -1590,7 +1614,7 @@ StatusCode CyberPFAlg::execute()
         double tmp_phi = std::atan2(t_ecal_clusters[ie]->getShowerCenter().y(), t_ecal_clusters[ie]->getShowerCenter().x())* 180.0 / M_PI;
         if (tmp_phi < 0) tmp_phi += 360.0;
         double tmp_theta = std::atan2(t_ecal_clusters[ie]->getShowerCenter().z(), t_ecal_clusters[ie]->getShowerCenter().Perp())* 180.0 / M_PI + 90; 
-        pfo_ecal_clus_Escale.push_back(m_energycorsvc->energyCorrection(t_ecal_clusters[ie]->getLongiE(), tmp_phi, tmp_theta));
+        pfo_ecal_clus_Escale.push_back(t_ecal_clusters[ie]->getLongiE());
    
       }
       for(int ih=0; ih<t_hcal_clusters.size(); ih++){
@@ -1655,7 +1679,7 @@ StatusCode CyberPFAlg::finalize()
   //r_HCalHitCols.clear();
   r_CaloHitCols.clear();
   //m_energycorsvc->finalize();
-
+  delete m_cellIDConverter, m_geosvc;
   info() << "Processed " << _nEvt << " events " << endmsg;
   return GaudiAlgorithm::finalize();
 }
@@ -1669,6 +1693,9 @@ void CyberPFAlg::ClearMCParticle(){
   m_mcEn.clear();
   m_mcMass.clear();
   m_mcCharge.clear();
+  m_mcVTXx.clear();
+  m_mcVTXy.clear();
+  m_mcVTXz.clear();
   m_mcEPx.clear();
   m_mcEPy.clear();
   m_mcEPz.clear();
@@ -2093,6 +2120,7 @@ void CyberPFAlg::ClearCluster(){
 
 void CyberPFAlg::ClearTrack(){
   m_type.clear();
+  m_Nhit.clear();
   m_trkstate_d0.clear();
   m_trkstate_z0.clear();
   m_trkstate_phi.clear();
diff --git a/Reconstruction/RecPFACyber/src/Objects/Calo1DCluster.cc b/Reconstruction/RecPFACyber/src/Objects/Calo1DCluster.cc
index 5e9a8728..9e99f930 100644
--- a/Reconstruction/RecPFACyber/src/Objects/Calo1DCluster.cc
+++ b/Reconstruction/RecPFACyber/src/Objects/Calo1DCluster.cc
@@ -65,10 +65,11 @@ namespace Cyber{
   }
 
   TVector3 Calo1DCluster::getPos() const{
-    TVector3 pos(0,0,0);
+    if(pos.x()!=0 || pos.y()!=0 || pos.z()!=0) return pos;
+    TVector3 m_pos(0,0,0);
     double Etot=getEnergy();
-    for(int i=0;i<Bars.size();i++) pos += Bars[i]->getPosition() * (Bars[i]->getEnergy()/Etot);
-    return pos;
+    for(int i=0;i<Bars.size();i++) m_pos += Bars[i]->getPosition() * (Bars[i]->getEnergy()/Etot);
+    return m_pos;
   }
 
   double Calo1DCluster::getT1() const{
diff --git a/Reconstruction/RecPFACyber/src/Objects/Calo2DCluster.cc b/Reconstruction/RecPFACyber/src/Objects/Calo2DCluster.cc
index 69605fcc..bc91695b 100644
--- a/Reconstruction/RecPFACyber/src/Objects/Calo2DCluster.cc
+++ b/Reconstruction/RecPFACyber/src/Objects/Calo2DCluster.cc
@@ -100,9 +100,9 @@ namespace Cyber{
 
 
   TVector3 Calo2DCluster::getPos() const{
-    TVector3 m_pos(0, 0, 0); 
-    if(towerID.size()==0) return m_pos; 
+    if( pos.x()!=0 || pos.y()!=0 || pos.z()!=0 || towerID.size()==0 ) return pos;
 
+    TVector3 m_pos(0., 0., 0.);
     float rotAngle = -towerID[0][0]*TMath::TwoPi()/Cyber::CaloUnit::Nmodule;
     TVector3 m_vecX(0., 0., 0.);  
     TVector3 m_vecY(0., 0., 0.);
diff --git a/Reconstruction/RecPFACyber/src/Objects/Calo3DCluster.cc b/Reconstruction/RecPFACyber/src/Objects/Calo3DCluster.cc
index dbbf49fa..2ddce73e 100644
--- a/Reconstruction/RecPFACyber/src/Objects/Calo3DCluster.cc
+++ b/Reconstruction/RecPFACyber/src/Objects/Calo3DCluster.cc
@@ -51,6 +51,7 @@ namespace Cyber{
       for(int ihf=0; ihf<iter.second.size(); ihf++) m_clus->addHalfClusterV(iter.first, iter.second[ihf]);
     for(auto iter:m_TrackCol)
       m_clus->addAssociatedTrack(iter);
+    m_clus->setEnergyScale(Escale);
     m_clus->setLinkedMCP(MCParticleWeight);
     m_clus->FitAxis();
 
@@ -215,13 +216,14 @@ namespace Cyber{
   double Calo3DCluster::getHitsE() const{
     double en=0;
     for(int i=0;i<hits.size(); i++) en+=hits[i]->getEnergy();
-    return en;
+    return en*Escale;
   }
 
   double Calo3DCluster::getEnergy() const{
     double result = 0;
     for(int m=0; m<m_2dclusters.size(); m++)
       result += m_2dclusters[m]->getEnergy();
+    if(result == 0) result = getLongiE();
     return result;
   }
 
@@ -237,7 +239,7 @@ namespace Cyber{
       for(auto iclus: iter.second)
         en += iclus->getEnergy();
     }
-    return en;
+    return en*Escale;
   }
 
   TVector3 Calo3DCluster::getHitCenter() const{
diff --git a/Reconstruction/RecPFACyber/src/Objects/CaloUnit.cc b/Reconstruction/RecPFACyber/src/Objects/CaloUnit.cc
index b2a9b619..649e777e 100644
--- a/Reconstruction/RecPFACyber/src/Objects/CaloUnit.cc
+++ b/Reconstruction/RecPFACyber/src/Objects/CaloUnit.cc
@@ -101,7 +101,7 @@ namespace Cyber{
   std::shared_ptr<CaloUnit> CaloUnit::Clone() const{
     std::shared_ptr<CaloUnit> m_bar = std::make_shared<CaloUnit>();
     m_bar->setcellID(cellID);
-    m_bar->setcellID( system, module, stave, dlayer, slayer, bar );
+    m_bar->setcellID( system, module, stave, part, dlayer, slayer, bar );
     m_bar->setPosition(position);
     m_bar->setQ(Q1, Q2);
     m_bar->setT(T1, T2);
diff --git a/Reconstruction/RecPFACyber/src/Tools/CaloHitsCreator.cpp b/Reconstruction/RecPFACyber/src/Tools/CaloHitsCreator.cpp
index 2b19c092..6eb324dd 100644
--- a/Reconstruction/RecPFACyber/src/Tools/CaloHitsCreator.cpp
+++ b/Reconstruction/RecPFACyber/src/Tools/CaloHitsCreator.cpp
@@ -11,7 +11,8 @@ namespace Cyber{
   StatusCode CaloHitsCreator::CreateCaloHits( CyberDataCol& m_DataCol, 
                                               std::vector<DataHandle<edm4hep::CalorimeterHitCollection>*>& r_CaloHitCols, 
                                               std::map<std::string, dd4hep::DDSegmentation::BitFieldCoder*>& map_decoder,
-                                              std::map<std::string, DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>*>& map_CaloParticleAssoCol )
+                                              std::map<std::string, DataHandle<edm4hep::MCRecoCaloParticleAssociationCollection>*>& map_CaloParticleAssoCol,
+                                              const dd4hep::VolumeManager& m_volumeManager )
   {
     if(r_CaloHitCols.size()==0 || settings.map_stringVecPars.at("CaloHitCollections").size()==0) StatusCode::SUCCESS;
 
@@ -32,7 +33,7 @@ namespace Cyber{
 
     //Convert to local objects: 
     for(auto iter : m_DataCol.collectionMap_CaloHit){
-      if( settings.map_stringPars.at("EcalType")=="BarEcal" && iter.first == "ECALBarrel") continue; 
+      if( settings.map_stringPars.at("EcalType")=="BarEcal" && (iter.first == "ECALBarrel" || iter.first == "ECALEndcaps" )) continue; 
       
       std::vector<std::shared_ptr<Cyber::CaloHit>> m_hitCol; m_hitCol.clear();
       const edm4hep::MCRecoCaloParticleAssociationCollection* const_MCPCaloAssoCol;
@@ -65,60 +66,117 @@ namespace Cyber{
     if(settings.map_stringPars.at("EcalType")=="BarEcal"){
       std::vector<std::shared_ptr<Cyber::CaloUnit>> m_barCol; m_barCol.clear(); 
 
-      const edm4hep::MCRecoCaloParticleAssociationCollection* const_MCPCaloAssoCol = map_CaloParticleAssoCol["ECALBarrel"]->get();   
-      auto CaloHits = m_DataCol.collectionMap_CaloHit["ECALBarrel"]; 
-      std::map<std::uint64_t, std::vector<Cyber::CaloUnit> > map_cellID_hits; map_cellID_hits.clear();
-      for(auto& hit : CaloHits){ 
-        Cyber::CaloUnit m_bar; 
-        m_bar.setcellID(hit.getCellID());
-        m_bar.setPosition( TVector3(hit.getPosition().x, hit.getPosition().y, hit.getPosition().z) );
-        m_bar.setQ(hit.getEnergy()/2., hit.getEnergy()/2.);
-        m_bar.setT(hit.getTime(), hit.getTime());
-        for(int ilink=0; ilink<const_MCPCaloAssoCol->size(); ilink++){
-          if( hit == const_MCPCaloAssoCol->at(ilink).getRec() ) m_bar.addLinkedMCP( std::make_pair(const_MCPCaloAssoCol->at(ilink).getSim(), const_MCPCaloAssoCol->at(ilink).getWeight()) );
-        } 
-
-
-        map_cellID_hits[hit.getCellID()].push_back(m_bar);
-      }
-      for(auto& hit : map_cellID_hits){
-        if(hit.second.size()!=2){ std::cout<<"WARNING: didn't find correct hit pairs! "<<std::endl; continue; }
+      //Readin ECAL barrel hits      
+      if( m_DataCol.collectionMap_CaloHit.find("ECALBarrel") != m_DataCol.collectionMap_CaloHit.end() ){
+        const edm4hep::MCRecoCaloParticleAssociationCollection* const_MCPCaloAssoCol = map_CaloParticleAssoCol["ECALBarrel"]->get();   
+        auto CaloHits = m_DataCol.collectionMap_CaloHit["ECALBarrel"]; 
+        std::map<std::uint64_t, std::vector<Cyber::CaloUnit> > map_cellID_hits; map_cellID_hits.clear();
+        for(auto& hit : CaloHits){ 
+          Cyber::CaloUnit m_bar; 
+          m_bar.setcellID(hit.getCellID());
+          m_bar.setPosition( TVector3(hit.getPosition().x, hit.getPosition().y, hit.getPosition().z) );
+          m_bar.setQ(hit.getEnergy()/2., hit.getEnergy()/2.);
+          m_bar.setT(hit.getTime(), hit.getTime());
+
+          unsigned long long tmp_id = hit.getCellID();
+          dd4hep::PlacedVolume ipv = m_volumeManager.lookupVolumePlacement(tmp_id);
+          dd4hep::Volume ivol = ipv.volume();
+          std::vector< double > iVolParam = ivol.solid().dimensions();
+          auto maxElement = std::max_element(iVolParam.begin(), iVolParam.end());
+          iVolParam.clear();
+          m_bar.setBarLength(*maxElement * 20);
+
+          for(int ilink=0; ilink<const_MCPCaloAssoCol->size(); ilink++){
+            if( hit == const_MCPCaloAssoCol->at(ilink).getRec() ) m_bar.addLinkedMCP( std::make_pair(const_MCPCaloAssoCol->at(ilink).getSim(), const_MCPCaloAssoCol->at(ilink).getWeight()) );
+          }
+ 
+          map_cellID_hits[hit.getCellID()].push_back(m_bar);
+        }
+        for(auto& hit : map_cellID_hits){
+          if(hit.second.size()!=2){ std::cout<<"WARNING: didn't find correct hit pairs! "<<std::endl; continue; }
    
-        //Cyber::CaloUnit* m_bar = new Cyber::CaloUnit(); 
-        std::shared_ptr<Cyber::CaloUnit> m_bar = std::make_shared<Cyber::CaloUnit>();
+          //Cyber::CaloUnit* m_bar = new Cyber::CaloUnit(); 
+          std::shared_ptr<Cyber::CaloUnit> m_bar = std::make_shared<Cyber::CaloUnit>();
    
-        unsigned long long id = hit.first; 
-        m_bar->setcellID( id );
-        m_bar->setcellID( map_decoder["ECALBarrel"]->get(id, "system"),
-                          map_decoder["ECALBarrel"]->get(id, "module"),
-                          map_decoder["ECALBarrel"]->get(id, "stave"),
-                          map_decoder["ECALBarrel"]->get(id, "dlayer"),
-                          map_decoder["ECALBarrel"]->get(id, "slayer"),
-                          map_decoder["ECALBarrel"]->get(id, "bar"));
-        m_bar->setPosition(hit.second[0].getPosition());
-        m_bar->setQ( hit.second[0].getEnergy(), hit.second[1].getEnergy() );
-        m_bar->setT( hit.second[0].getT1(), hit.second[1].getT1() );
-
-        //---oooOOO000OOOooo---set bar length---oooOOO000OOOooo---
-        //TODO: reading bar length from geosvc. 
-        double t_bar_length;
-        if(m_bar->getSlayer()==1) t_bar_length = 374.667;
-        else{
-          if( m_bar->getModule()%2==0 ) t_bar_length = 288 + (m_bar->getDlayer()-1)* 12.708;
-          else t_bar_length = 409 - (m_bar->getDlayer()-1)* 4.667;
+          unsigned long long id = hit.first; 
+          m_bar->setcellID( id );
+          m_bar->setcellID( map_decoder["ECALBarrel"]->get(id, "system"),
+                            map_decoder["ECALBarrel"]->get(id, "module"),
+                            map_decoder["ECALBarrel"]->get(id, "stave"),
+                            -1,
+                            map_decoder["ECALBarrel"]->get(id, "dlayer"),
+                            map_decoder["ECALBarrel"]->get(id, "slayer"),
+                            map_decoder["ECALBarrel"]->get(id, "bar"));
+          m_bar->setPosition(hit.second[0].getPosition());
+          m_bar->setBarLength(hit.second[0].getBarLength());  
+          m_bar->setQ( hit.second[0].getEnergy(), hit.second[1].getEnergy() );
+          m_bar->setT( hit.second[0].getT1(), hit.second[1].getT1() );
+
+          //add MCParticle link
+          for(int ilink=0; ilink<hit.second[0].getLinkedMCP().size(); ilink++) m_bar->addLinkedMCP( hit.second[0].getLinkedMCP()[ilink] );
+
+          m_barCol.push_back(m_bar);  //Save for later use in algorithms
         }
-        m_bar->setBarLength(t_bar_length);
-        //---oooOOO000OOOooo---set bar length---oooOOO000OOOooo---
+   
+        m_DataCol.map_BarCol["BarCol"] = m_barCol; 
+        const_MCPCaloAssoCol = nullptr;
+      }
 
-        //add MCParticle link
-        for(int ilink=0; ilink<hit.second[0].getLinkedMCP().size(); ilink++) m_bar->addLinkedMCP( hit.second[0].getLinkedMCP()[ilink] );
+      if( m_DataCol.collectionMap_CaloHit.find("ECALEndcaps") != m_DataCol.collectionMap_CaloHit.end() ){
+        const edm4hep::MCRecoCaloParticleAssociationCollection* const_MCPCaloAssoCol = map_CaloParticleAssoCol["ECALEndcaps"]->get();
+        auto CaloHits = m_DataCol.collectionMap_CaloHit["ECALEndcaps"];
+        std::map<std::uint64_t, std::vector<Cyber::CaloUnit> > map_cellID_hits; map_cellID_hits.clear();
+        for(auto& hit : CaloHits){
+          Cyber::CaloUnit m_bar;
+          m_bar.setcellID(hit.getCellID());
+          m_bar.setPosition( TVector3(hit.getPosition().x, hit.getPosition().y, hit.getPosition().z) );
+          m_bar.setQ(hit.getEnergy()/2., hit.getEnergy()/2.);
+          m_bar.setT(hit.getTime(), hit.getTime());
+
+          unsigned long long tmp_id = hit.getCellID();
+          dd4hep::PlacedVolume ipv = m_volumeManager.lookupVolumePlacement(tmp_id);
+          dd4hep::Volume ivol = ipv.volume();
+          std::vector< double > iVolParam = ivol.solid().dimensions();
+          auto maxElement = std::max_element(iVolParam.begin(), iVolParam.end());
+          iVolParam.clear();
+          m_bar.setBarLength(*maxElement * 20);
+
+          for(int ilink=0; ilink<const_MCPCaloAssoCol->size(); ilink++){
+            if( hit == const_MCPCaloAssoCol->at(ilink).getRec() ) m_bar.addLinkedMCP( std::make_pair(const_MCPCaloAssoCol->at(ilink).getSim(), const_MCPCaloAssoCol->at(ilink).getWeight()) );
+          }
+
+
+          map_cellID_hits[hit.getCellID()].push_back(m_bar);
+        }
+        for(auto& hit : map_cellID_hits){
+          if(hit.second.size()!=2){ std::cout<<"WARNING: didn't find correct hit pairs! "<<std::endl; continue; }
+
+          //Cyber::CaloUnit* m_bar = new Cyber::CaloUnit();
+          std::shared_ptr<Cyber::CaloUnit> m_bar = std::make_shared<Cyber::CaloUnit>();
+
+          unsigned long long id = hit.first;
+          m_bar->setcellID( id );
+          m_bar->setcellID( map_decoder["ECALEndcaps"]->get(id, "system"),
+                            map_decoder["ECALEndcaps"]->get(id, "module"),
+                            map_decoder["ECALEndcaps"]->get(id, "stave"),
+                            map_decoder["ECALEndcaps"]->get(id, "part"),
+                            map_decoder["ECALEndcaps"]->get(id, "dlayer"),
+                            map_decoder["ECALEndcaps"]->get(id, "slayer"),
+                            map_decoder["ECALEndcaps"]->get(id, "bar"));
+          m_bar->setPosition(hit.second[0].getPosition());
+          m_bar->setBarLength(hit.second[0].getBarLength());
+          m_bar->setQ( hit.second[0].getEnergy(), hit.second[1].getEnergy() );
+          m_bar->setT( hit.second[0].getT1(), hit.second[1].getT1() );
+
+          //add MCParticle link
+          for(int ilink=0; ilink<hit.second[0].getLinkedMCP().size(); ilink++) m_bar->addLinkedMCP( hit.second[0].getLinkedMCP()[ilink] );
+
+          m_barCol.push_back(m_bar);  //Save for later use in algorithms
+        }
 
-        m_barCol.push_back(m_bar);  //Save for later use in algorithms
+        m_DataCol.map_BarCol["BarCol"].insert( m_DataCol.map_BarCol["BarCol"].end(), m_barCol.begin(), m_barCol.end() );
+        const_MCPCaloAssoCol = nullptr;
       }
-
-   
-      m_DataCol.map_BarCol["BarCol"] = m_barCol; 
-      const_MCPCaloAssoCol = nullptr;
     }
     return StatusCode::SUCCESS;
   };
diff --git a/Reconstruction/RecPFACyber/src/Tools/OutputCreator.cpp b/Reconstruction/RecPFACyber/src/Tools/OutputCreator.cpp
index 22531521..3ee25ae3 100644
--- a/Reconstruction/RecPFACyber/src/Tools/OutputCreator.cpp
+++ b/Reconstruction/RecPFACyber/src/Tools/OutputCreator.cpp
@@ -28,21 +28,25 @@ namespace Cyber{
     edm4hep::ClusterCollection* m_Hcalcluster = m_outClusterColHandler["HcalCluster"]->createAndPut();
 
     edm4hep::TrackCollection* m_trkCol = nullptr;
-    if(settings.map_boolPars.at("UseTruthTrk")) m_trkCol = m_outTrkHandler.createAndPut();
+    if(settings.map_boolPars.at("UseTruthTrk") || settings.map_boolPars.at("UseTruthMatchTrk") ) m_trkCol = m_outTrkHandler.createAndPut();
 
 
     //PFO
     std::vector<std::shared_ptr<Cyber::PFObject>> p_pfos = m_DataCol.map_PFObjects[settings.map_stringPars.at("OutputPFO")];
 /*
+cout<<endl;
+cout<<"Calibration const: "<<settings.map_floatPars.at("ECALNeutralCalib")<<", "<<settings.map_floatPars.at("ECALChargedCalib")<<", "<<settings.map_floatPars.at("HCALNeutralCalib")<<", "<<settings.map_floatPars.at("HCALChargedCalib")<<endl;
 std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;    
  double totE_Ecal = 0;
  double totE_Hcal = 0;
  for(int i=0; i<p_pfos.size(); i++){
+      double ecalcalib = p_pfos[i]->getTracks().size()==0 ? settings.map_floatPars.at("ECALNeutralCalib") : settings.map_floatPars.at("ECALChargedCalib");
+      double hcalcalib = p_pfos[i]->getTracks().size()==0 ? settings.map_floatPars.at("HCALNeutralCalib") : settings.map_floatPars.at("HCALChargedCalib");
    cout<<"    PFO #"<<i<<": track size "<<p_pfos[i]->getTracks().size()<<", leading P "<<p_pfos[i]->getTrackMomentum();
-   cout<<", ECAL cluster size "<<p_pfos[i]->getECALClusters().size()<<", totE "<<p_pfos[i]->getECALClusterEnergy();
-   cout<<", HCAL cluster size "<<p_pfos[i]->getHCALClusters().size()<<", totE "<<p_pfos[i]->getHCALClusterEnergy()<<endl;
-   totE_Ecal += p_pfos[i]->getECALClusterEnergy();
-   totE_Hcal += p_pfos[i]->getHCALClusterEnergy();
+   cout<<", ECAL cluster size "<<p_pfos[i]->getECALClusters().size()<<", totE "<<p_pfos[i]->getECALClusterEnergy()*ecalcalib;
+   cout<<", HCAL cluster size "<<p_pfos[i]->getHCALClusters().size()<<", totE "<<p_pfos[i]->getHCALClusterEnergy()*hcalcalib<<endl;
+   totE_Ecal += p_pfos[i]->getECALClusterEnergy()*ecalcalib;
+   totE_Hcal += p_pfos[i]->getHCALClusterEnergy()*hcalcalib;
  }
  cout<<"-----Neutral cluster Ecal total energy: "<<totE_Ecal<<", Hcal total energy: "<<totE_Hcal<<endl;
 */
@@ -52,6 +56,8 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
       std::vector<const Track*> vec_trks = p_pfos[ip]->getTracks();
       std::vector<const Calo3DCluster*> vec_Ecalclus = p_pfos[ip]->getECALClusters();
       std::vector<const Calo3DCluster*> vec_Hcalclus = p_pfos[ip]->getHCALClusters();
+      double ecalcalib = vec_trks.size()==0 ? settings.map_floatPars.at("ECALNeutralCalib") : settings.map_floatPars.at("ECALChargedCalib");
+      double hcalcalib = vec_trks.size()==0 ? settings.map_floatPars.at("HCALNeutralCalib") : settings.map_floatPars.at("HCALChargedCalib");
 
       TVector3 vec_Pos(0.,0.,0.);
 
@@ -71,7 +77,7 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
    
           auto _hit = m_calohitCol->create();
           _hit.setCellID(_cellID);
-          _hit.setEnergy( p_hit->getEnergy()*settings.map_floatPars.at("ECALCalib") );
+          _hit.setEnergy( p_hit->getEnergy()*ecalcalib );
           _hit.setPosition( pos );
           _hit.setType(1); //Ecal barrel
           m_clus.addToHits(_hit);
@@ -89,21 +95,21 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
    
           auto _hit = m_corehitCol->create();
           _hit.setCellID(_cellID);
-          _hit.setEnergy( p_core->getEnergy()*settings.map_floatPars.at("ECALCalib") );
+          _hit.setEnergy( p_core->getEnergy()*ecalcalib );
           _hit.setPosition( pos );
           _hit.setType(1); //Ecal barrel
           m_core.addToHits(_hit);
-          totE += p_core->getEnergy()*settings.map_floatPars.at("ECALCalib");
+          totE += p_core->getEnergy()*ecalcalib;
         }
    
-        double tmp_clusE = p_clus->getEnergy()*settings.map_floatPars.at("ECALCalib");
+        double tmp_clusE = p_clus->getLongiE()*ecalcalib;
         TVector3 clus_pos = p_clus->getShowerCenter();
         edm4hep::Vector3f pos( clus_pos.x(), clus_pos.y(), clus_pos.z() );
-        double tmp_phi = std::atan2(clus_pos.y(), clus_pos.x())* 180.0 / M_PI; //TODO: use TVector3 to calculate
-        if (tmp_phi < 0) tmp_phi += 360.0;
-        double tmp_theta = std::atan2(clus_pos.z(), clus_pos.Perp())* 180.0 / M_PI + 90;
-        tmp_clusE = m_DataCol.EnergyCorrSvc->energyCorrection(tmp_clusE, tmp_phi, tmp_theta);
-        totE = m_DataCol.EnergyCorrSvc->energyCorrection(totE, tmp_phi, tmp_theta);
+        //double tmp_phi = std::atan2(clus_pos.y(), clus_pos.x())* 180.0 / M_PI; //TODO: use TVector3 to calculate
+        //if (tmp_phi < 0) tmp_phi += 360.0;
+        //double tmp_theta = std::atan2(clus_pos.z(), clus_pos.Perp())* 180.0 / M_PI + 90;
+        //tmp_clusE = m_DataCol.EnergyCorrSvc->energyCorrection(tmp_clusE, tmp_phi, tmp_theta);
+        //totE = m_DataCol.EnergyCorrSvc->energyCorrection(totE, tmp_phi, tmp_theta);
 
         m_core.setEnergy(totE);
         m_core.setPosition( pos );
@@ -131,7 +137,7 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
           m_clus.addToHits(_hit);
         }
    
-        double tmp_clusE = p_clus->getHitsE()*settings.map_floatPars.at("HCALCalib");
+        double tmp_clusE = p_clus->getHitsE()*hcalcalib;
         m_clus.setEnergy( tmp_clusE );
         edm4hep::Vector3f pos( p_clus->getHitCenter().x(), p_clus->getHitCenter().y(), p_clus->getHitCenter().z() );
         m_clus.setPosition( pos );
@@ -162,7 +168,7 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
         }
         if(trkIndex>=0){
           auto m_trk = vec_trks[trkIndex]->getOriginTrack();
-          if( !m_trk.isAvailable() || settings.map_boolPars.at("UseTruthTrk") )
+          if( !m_trk.isAvailable() || settings.map_boolPars.at("UseTruthTrk") || settings.map_boolPars.at("UseTruthMatchTrk"))
             m_trk = TruthTrack( vec_trks[trkIndex]->getLeadingMCP(), m_trkCol );
 
           m_pfo.addToTracks( m_trk );
@@ -172,6 +178,7 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
           edm4hep::Vector3f p3(p3vec.x(), p3vec.y(), p3vec.z());
           m_pfo.setMomentum(p3);
           m_pfo.setEnergy( vec_trks[trkIndex]->getMomentum() );
+          m_pfo.setMass(139.57039); //TODO: all charged particles are set to pion mass. 
         }
         else{
           TVector3 p3vec = vec_Pos*(  (EcalClusE+HcalClusE)/vec_Pos.Mag() );
@@ -183,7 +190,7 @@ std::cout<<"  Input PFO size: "<<p_pfos.size()<<std::endl;
         }
 
       }
-
+//printf("  Create PFO #%d: charge %.1f, p4 (%.7f, %.7f, %.7f, %.7f), mass %.3f \n", ip, m_pfo.getCharge(), m_pfo.getMomentum().x, m_pfo.getMomentum().y, m_pfo.getMomentum().z, m_pfo.getEnergy(), m_pfo.getMass() );
     }
 /*
 double totE = 0;
@@ -198,7 +205,8 @@ totE = 0;
 for(int i=0; i<m_pfocol->size(); i++){
   auto m_pfo = m_pfocol->at(i);
   if(m_pfo.getCharge()==0) continue;
-   cout<<"    PFO #"<<i<<": track size "<<m_pfo.tracks_size()<<", cluster size "<<m_pfo.clusters_size()<<", energy "<<m_pfo.getEnergy()<<endl;
+   cout<<"    PFO #"<<i<<": track size "<<m_pfo.tracks_size()<<", leading P "<<sqrt(m_pfo.getMomentum().x*m_pfo.getMomentum().x + m_pfo.getMomentum().y*m_pfo.getMomentum().y + m_pfo.getMomentum().z*m_pfo.getMomentum().z);
+   cout<<", cluster size "<<m_pfo.clusters_size()<<", energy "<<m_pfo.getEnergy()<<endl;
    totE += m_pfo.getEnergy();
 }
 cout<<"-----Charged cluster Ecal total energy: "<<totE<<endl;
@@ -227,7 +235,7 @@ std::cout<<"  Created PFO size: "<<m_pfocol->size()<<std::endl;
     m_trkst.Z0 = 0;
     m_trkst.phi = TMath::ATan2(mcp_p.x, mcp_p.x);
     m_trkst.tanLambda = mcp_p.z / mcp_pT;
-    m_trkst.omega = 0.3 * settings.map_floatPars.at("BField") / 1000. / mcp_pT;
+    m_trkst.omega = 0.299792458 * settings.map_floatPars.at("BField") / 1000. / mcp_pT;
     m_trkst.referencePoint = mcp_vertex;
     m_track.addToTrackStates(m_trkst);
 
diff --git a/Reconstruction/RecPFACyber/src/Tools/TrackCreator.cpp b/Reconstruction/RecPFACyber/src/Tools/TrackCreator.cpp
index 7b09a954..06008654 100644
--- a/Reconstruction/RecPFACyber/src/Tools/TrackCreator.cpp
+++ b/Reconstruction/RecPFACyber/src/Tools/TrackCreator.cpp
@@ -14,7 +14,7 @@ namespace Cyber{
                                          std::vector<DataHandle<edm4hep::TrackCollection>*>& r_TrackCols, 
                                          DataHandle<edm4hep::MCRecoTrackParticleAssociationCollection>* r_MCParticleTrkCol ){
 
-    if(r_TrackCols.size()==0 || settings.map_stringVecPars.at("trackCollections").size()==0) StatusCode::SUCCESS;
+    if(r_TrackCols.size()==0 || settings.map_stringVecPars.at("trackCollections").size()==0) return StatusCode::SUCCESS;
 
     //Save readin collections
     m_DataCol.collectionMap_Track.clear(); 
@@ -75,14 +75,14 @@ namespace Cyber{
       }
     }
 
-    //SelectGoodTrack(m_trkCol);
+    if(settings.map_boolPars.at("DoCleanTrack")) SelectGoodTrack(m_trkCol);
     m_DataCol.TrackCol = m_trkCol;
 
-
     //Track extrapolation
     //  Write settings: geometry description
     //  m_TrkExtraSettings.map_floatPar["Nlayers"] = 28;
 
+    if(settings.map_boolPars.at("UseTruthMatchTrk")) m_TrkExtraSettings.map_intPars["Input_track"] = 1;
     m_TrkExtraAlg = new TrackExtrapolatingAlg();
     m_TrkExtraAlg->ReadSettings(m_TrkExtraSettings);
     m_TrkExtraAlg->Initialize( m_DataCol );
@@ -131,7 +131,7 @@ namespace Cyber{
       m_trkst.Kappa = 1 / mcp_pT;
       if(charge<0) m_trkst.Kappa = -m_trkst.Kappa;
       m_trkst.tanLambda = mcp_p.Z() / mcp_pT;
-      m_trkst.Omega = 0.3 * settings.map_floatPars.at("BField") / 1000. / mcp_pT;
+      m_trkst.Omega = 0.299792458 * settings.map_floatPars.at("BField") / 1000. / mcp_pT;
       m_trkst.referencePoint = mcp_vertex;
       m_trkstates.push_back(m_trkst);
 
@@ -157,53 +157,119 @@ namespace Cyber{
 
 
   StatusCode TrackCreator::SelectGoodTrack(std::vector<std::shared_ptr<Cyber::Track>>& trkCol){
-    if(trkCol.size()<2) return StatusCode::SUCCESS;
-
-    for(int itrk=0; itrk<trkCol.size(); itrk++){
-      //Endpoint cut
-      if( fabs( trkCol[itrk]->getEndPoint().z() )<settings.map_floatPars.at("TrkEndZCut") && 
-          trkCol[itrk]->getEndPoint().Perp()>settings.map_floatPars.at("TrkEndRCutMin") &&  
-          trkCol[itrk]->getEndPoint().Perp()<settings.map_floatPars.at("TrkEndRCutMax") ){  
+    //Use truth matched tracks
+    if(settings.map_boolPars.at("UseTruthMatchTrk")){
 
-        trkCol.erase(trkCol.begin() + itrk);
-        itrk--;
-        continue;
+      std::map<edm4hep::MCParticle, std::vector<std::shared_ptr<Cyber::Track>>> truthMap;
+      for(int itrk=0; itrk<trkCol.size(); itrk++){
+        truthMap[ trkCol[itrk]->getLeadingMCP() ].push_back( trkCol[itrk] );
       }
-      //Start point cut
-      if( trkCol[itrk]->getStartPoint().Perp()>settings.map_floatPars.at("TrkStartRCutMin") &&
-          trkCol[itrk]->getStartPoint().Perp()<settings.map_floatPars.at("TrkStartRCutMax") ){ 
+      std::vector<std::shared_ptr<Cyber::Track>> tmp_selTrk; tmp_selTrk.clear();
+      for(auto iter: truthMap){
+        if(iter.second.size()<=0) continue;
+        int m_index = -1;
+        double minIP = 999999;
+        for(int itrk=0; itrk<iter.second.size(); itrk++){
+          double tmp_IP = sqrt( iter.second[itrk]->getD0()*iter.second[itrk]->getD0() + iter.second[itrk]->getZ0()*iter.second[itrk]->getZ0() );
+          if(tmp_IP<minIP){
+            minIP = tmp_IP;
+            m_index = itrk;
+          }
+        }
 
-        trkCol.erase(trkCol.begin() + itrk);
-        itrk--;
-        continue;
+        if(m_index>=0) tmp_selTrk.push_back( iter.second[m_index] );
+      }
+      for(int itrk=0; itrk<trkCol.size(); itrk++){
+        if( find(tmp_selTrk.begin(), tmp_selTrk.end(), trkCol[itrk])==tmp_selTrk.end() ){
+          trkCol.erase(trkCol.begin() + itrk);
+          itrk--;
+        }
       }
-      //Track length cut
-      if( (trkCol[itrk]->getEndPoint().Perp()-trkCol[itrk]->getStartPoint().Perp() )<settings.map_floatPars.at("TrkLengthCut") ){
+//cout<<"Matched track size: "<<trkCol.size()<<endl;
 
-        trkCol.erase(trkCol.begin() + itrk);
-        itrk--;
-        continue;
+      //Create truth track from linked MC particle
+      std::vector<std::shared_ptr<Cyber::Track>> truthtrk; 
+      for(int itrk=0; itrk<trkCol.size(); itrk++){
+        edm4hep::MCParticle mcp = trkCol[itrk]->getLeadingMCP();
+
+        std::shared_ptr<Cyber::Track> m_trk = std::make_shared<Cyber::Track>();
+        std::vector<Cyber::TrackState> m_trkstates;        
+
+        TVector3 mcp_vertex(mcp.getVertex().x, mcp.getVertex().y, mcp.getVertex().z);
+        TVector3 mcp_p(mcp.getMomentum().x, mcp.getMomentum().y, mcp.getMomentum().z);
+        double mcp_pT = TMath::Sqrt(mcp_p.X()*mcp_p.X() + mcp_p.Y()*mcp_p.Y());
+        double charge = mcp.getCharge();
+
+        // Evaluate track state at vertex
+        Cyber::TrackState m_trkst;
+        m_trkst.location = 1;  // At IP
+        m_trkst.D0 = 0;
+        m_trkst.Z0 = 0;
+        m_trkst.phi0 = TMath::ATan2(mcp_p.Y(), mcp_p.X());
+        m_trkst.Kappa = 1 / mcp_pT;
+        if(charge<0) m_trkst.Kappa = -m_trkst.Kappa;
+        m_trkst.tanLambda = mcp_p.Z() / mcp_pT;
+        m_trkst.Omega = 0.3 * settings.map_floatPars.at("BField") / 1000. / mcp_pT;
+        m_trkst.referencePoint = mcp_vertex;
+        m_trkstates.push_back(m_trkst);
+
+        m_trk->setTrackStates("Input", m_trkstates);
+        m_trk->setType(0);  // It is a "MC track" and not detected by any tracker system
+        m_trk->addLinkedMCP( std::make_pair(mcp, 1.) );
+        truthtrk.push_back(m_trk);       
       }
+//cout<<"Created truth track size: "<<truthtrk.size()<<endl;
+      trkCol = truthtrk;
+
+      std::sort(trkCol.begin(), trkCol.end(),  compTrkP);
+      return StatusCode::SUCCESS;
     }
 
-    if(trkCol.size()<2) return StatusCode::SUCCESS;
-
-    //Remove the broken tracks
-    std::sort(trkCol.begin(), trkCol.end(),  compTrkIP);
-    for(int itrk=0; itrk<trkCol.size()-1; itrk++){
-      for(int jtrk=itrk+1; jtrk<trkCol.size(); jtrk++){
-        double deltaP = (trkCol[itrk]->getP3() - trkCol[jtrk]->getP3()).Mag();
-        if( trkCol[jtrk]->getP3().Perp() < settings.map_floatPars.at("BrokenTrkMinP") &&
-            ( deltaP/max(trkCol[itrk]->getMomentum(), trkCol[jtrk]->getMomentum()) < settings.map_floatPars.at("BrokenTrkDeltaPCut") ||
-            (trkCol[itrk]->getEndPoint()-trkCol[jtrk]->getStartPoint()).Mag() < settings.map_floatPars.at("BrokenTrkDistance") ) ){
-          trkCol.erase(trkCol.begin() + jtrk);
-          jtrk--;
-          if(itrk>jtrk+1) itrk--;
-        }
-      }
+
+    //Select tracks with some custom criteria
+    float trk_P, trk_Pt, trk_Nhit, trk_cosT, trk_startR, trk_startZ, trk_endR, trk_endZ, trk_length, trk_IP;
+    std::ifstream file(settings.map_stringPars.at("TrackIDWeightFile"));
+    if(!file.good()){
+      std::cout << "ERROR: Did not find BDT weight file. Will skip the track cleaning. " << std::endl;
+      std::sort(trkCol.begin(), trkCol.end(),  compTrkP);
+      return StatusCode::SUCCESS;
     }
 
+    TMVA::Reader *mva_rdr = new TMVA::Reader("Silent");
+    mva_rdr->AddVariable("trk_P", &trk_P);
+    mva_rdr->AddVariable("trk_Pt", &trk_Pt);
+    mva_rdr->AddVariable("trk_Nhit", &trk_Nhit);
+    mva_rdr->AddVariable("trk_IP", &trk_IP);
+    mva_rdr->AddVariable("trk_cosT", &trk_cosT);
+    mva_rdr->AddVariable("trk_startR", &trk_startR);
+    mva_rdr->AddVariable("trk_startZ", &trk_startZ);
+    mva_rdr->AddVariable("trk_endR", &trk_endR);
+    mva_rdr->AddVariable("trk_endZ", &trk_endZ);
+    mva_rdr->AddVariable("trk_length", &trk_length);
+    
+    mva_rdr->BookMVA(settings.map_stringPars.at("TrackIDMethod"), settings.map_stringPars.at("TrackIDWeightFile"));    
+//cout<<"Use BDT track cleaning. BDT cut "<<settings.map_floatPars.at("BDTCut")<<endl;
+    for(int itrk=0; itrk<trkCol.size(); itrk++){
+      //float tmp_IP = sqrt( trkCol[itrk]->getD0()*trkCol[itrk]->getD0() + trkCol[itrk]->getZ0()*trkCol[itrk]->getZ0() );
+      trk_P = trkCol[itrk]->getMomentum();
+      trk_Pt = trkCol[itrk]->getPt();
+      trk_Nhit = trkCol[itrk]->getTrackerHits();
+      trk_cosT = trkCol[itrk]->getP3().CosTheta();
+      trk_startR = trkCol[itrk]->getStartPoint().Perp();
+      trk_startZ = trkCol[itrk]->getStartPoint().z();
+      trk_endR = trkCol[itrk]->getEndPoint().Perp();
+      trk_endZ = trkCol[itrk]->getEndPoint().z();
+      trk_length = trkCol[itrk]->getEndPoint().Perp() - trkCol[itrk]->getStartPoint().Perp();
+      trk_IP = sqrt(trkCol[itrk]->getD0()*trkCol[itrk]->getD0() + trkCol[itrk]->getZ0()*trkCol[itrk]->getZ0());
+      float BDTout = mva_rdr->EvaluateMVA(settings.map_stringPars.at("TrackIDMethod"));
+//printf("  In track #%d: P %.3f, Pt %.3f, cosT %.3f, start (%.3f, %.3f), end (%.3f, %.3f), Nhit %.0f, length %.3f, IP %.3f, BDT %.3f \n ", itrk, trk_P, trk_Pt, trk_cosT, trk_startR, trk_startZ, trk_endR, trk_endZ, trk_Nhit, trk_length, trk_IP, BDTout);
+      if(BDTout<settings.map_floatPars.at("BDTCut")){
+        trkCol.erase(trkCol.begin() + itrk);
+        itrk--;
+      }
+    }
     std::sort(trkCol.begin(), trkCol.end(),  compTrkP);
+    delete mva_rdr;
 
     return StatusCode::SUCCESS;
   }
-- 
GitLab