diff --git a/Reconstruction/CMakeLists.txt b/Reconstruction/CMakeLists.txt index 6bb53e061183577afbe0a7bd5572c109c985793d..414e1160d5b422546cd1b4d9b32a556b36567d83 100644 --- a/Reconstruction/CMakeLists.txt +++ b/Reconstruction/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(SiliconTracking) add_subdirectory(Tracking) add_subdirectory(RecGenfitAlg) add_subdirectory(RecAssociationMaker) +add_subdirectory(TofRecAlg) diff --git a/Reconstruction/TofRecAlg/CMakeLists.txt b/Reconstruction/TofRecAlg/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f66caadd9150fd808898f895331554fdfc5cfe4 --- /dev/null +++ b/Reconstruction/TofRecAlg/CMakeLists.txt @@ -0,0 +1,18 @@ +gaudi_add_module(TofRecAlg + SOURCES src/TofRecAlg.cpp + LINK DataHelperLib + Gaudi::GaudiKernel + EDM4HEP::edm4hep + ${ROOT_LIBRARIES} + ${CLHEP_LIBRARIES} + ${LCIO_LIBRARIES} + ${DD4hep_COMPONENT_LIBRARIES} + DetInterface + k4FWCore::k4FWCore +) + +install(TARGETS TofRecAlg + EXPORT CEPCSWTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + COMPONENT dev) \ No newline at end of file diff --git a/Reconstruction/TofRecAlg/src/TofRecAlg.cpp b/Reconstruction/TofRecAlg/src/TofRecAlg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39ac4193ab0f5fd2c83a9197df214ef60f1de81a --- /dev/null +++ b/Reconstruction/TofRecAlg/src/TofRecAlg.cpp @@ -0,0 +1,297 @@ +#include "TofRecAlg.h" + +#include "GaudiKernel/DataObject.h" +#include "GaudiKernel/IHistogramSvc.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/SmartDataPtr.h" + +#include "DetInterface/IGeomSvc.h" +#include "DataHelper/HelixClass.h" + +#include "DD4hep/Detector.h" +#include "DD4hep/DD4hepUnits.h" +#include "CLHEP/Units/SystemOfUnits.h" +#include <math.h> +#include "UTIL/ILDConf.h" +#include "Identifier/CEPCConf.h" +#include "UTIL/CellIDEncoder.h" + +DECLARE_COMPONENT( TofRecAlg ) + +//------------------------------------------------------------------------------ +TofRecAlg::TofRecAlg( const std::string& name, ISvcLocator* pSvcLocator ) + : Algorithm( name, pSvcLocator ) { + declareProperty("MCParticleCollection", _inMCColHdl, "Handle of the Input MCParticle collection"); + declareProperty("TrackCollection", _inTrackColHdl, "Handle of the Input Track collection from CEPCSW"); +} + +//------------------------------------------------------------------------------ +StatusCode TofRecAlg::initialize(){ + info() << "Booking Ntuple" << endmsg; + + NTuplePtr nt1(ntupleSvc(), "MyTuples/ToF"); + if ( !nt1 ) { + m_tuple = ntupleSvc()->book("MyTuples/ToF",CLID_ColumnWiseTuple,"ToF result"); + if ( 0 != m_tuple ) { + m_tuple->addItem ("ntrk", m_nTracks, 0, 500 ).ignore(); + m_tuple->addIndexedItem("ToFt", m_nTracks, m_ToFt).ignore(); + m_tuple->addIndexedItem("ToFterr", m_nTracks, m_ToFterr).ignore(); + m_tuple->addIndexedItem("ToFx", m_nTracks, m_ToFx).ignore(); + m_tuple->addIndexedItem("ToFy", m_nTracks, m_ToFy).ignore(); + m_tuple->addIndexedItem("ToFz", m_nTracks, m_ToFz).ignore(); + m_tuple->addIndexedItem("length", m_nTracks, m_length).ignore(); + m_tuple->addIndexedItem("lengtherr", m_nTracks, m_lengtherr).ignore(); + m_tuple->addIndexedItem("exp_time", m_nTracks, 5, m_exp_time).ignore(); + m_tuple->addIndexedItem("exp_timeerr", m_nTracks, 5, m_exp_timeerr).ignore();//above need to be stored in edm4hep + + m_tuple->addIndexedItem("trackState0", m_nTracks, 15, trackState0).ignore(); + m_tuple->addIndexedItem("trackState1", m_nTracks, 15, trackState1).ignore(); + m_tuple->addIndexedItem("trackState2", m_nTracks, 15, trackState2).ignore(); + m_tuple->addIndexedItem("trackState3", m_nTracks, 15, trackState3).ignore(); + m_tuple->addIndexedItem("trackState4", m_nTracks, 15, trackState4).ignore(); + + m_tuple->addIndexedItem("p_atIP", m_nTracks, m_p_atIP).ignore(); + m_tuple->addIndexedItem("perr_atIP", m_nTracks, m_perr_atIP).ignore(); + m_tuple->addIndexedItem("p_atLastHit", m_nTracks, m_p_atLast).ignore(); + m_tuple->addIndexedItem("perr_atLastHit", m_nTracks, m_perr_atLast).ignore(); + } + else { // did not manage to book the N tuple.... + fatal() << "Cannot book MyTuples/ToF" <<endmsg; + return StatusCode::FAILURE; + } + } + else{ + m_tuple = nt1; + } + + auto geomSvc = service<IGeomSvc>("GeomSvc"); + if(geomSvc){ + const dd4hep::Direction& field = geomSvc->lcdd()->field().magneticField(dd4hep::Position(0,0,0)); + m_field = field.z()/dd4hep::tesla; + info() << "Magnetic field will obtain from GeomSvc = " << m_field << " tesla" << endmsg; + } + else{ + info() << "Failed to find GeomSvc ..." << endmsg; + info() << "Magnetic field will use what input through python option for this algorithm namse as Field, now " << m_field << " tesla" << endmsg; + } + + _nEvt = 0; + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------------ +StatusCode TofRecAlg::execute(){ + + const edm4hep::TrackCollection* trackCols = nullptr; + + try { + trackCols = _inTrackColHdl.get(); + } + catch ( GaudiException &e ) { + debug() << "Collection " << _inTrackColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return StatusCode::SUCCESS; + } + + + if(trackCols){ + + m_nTracks = 0; + + for(auto track : *trackCols){ + // only take the first track + // if(m_nTracks>=1)break; + + int NHits = track.trackerHits_size(); + int det_id = 0; + bool hasSETHit = false; + bool hasFTDHit = false; + UTIL::BitField64 encoder( lcio::ILDCellID0::encoder_string ); + for ( int hit=0; hit<NHits; hit++ ) { + edm4hep::TrackerHit SimTHit = track.getTrackerHits(hit); + encoder.setValue(SimTHit.getCellID()); + det_id = encoder[lcio::ILDCellID0::subdet]; + if ( det_id == lcio::ILDDetID::SET ){ + hasSETHit = true; + m_ToFt[m_nTracks] = SimTHit.getTime(); + m_ToFx[m_nTracks] = SimTHit.getPosition()[0]; + m_ToFy[m_nTracks] = SimTHit.getPosition()[1]; + m_ToFz[m_nTracks] = SimTHit.getPosition()[2]; + } + else if( det_id == lcio::ILDDetID::FTD ){ + const int cellID = SimTHit.getCellID(); + encoder.setValue(cellID); + int layer = encoder[lcio::ILDCellID0::layer]; + if(layer==4){ + m_ToFt[m_nTracks] = SimTHit.getTime(); + m_ToFx[m_nTracks] = SimTHit.getPosition()[0]; + m_ToFy[m_nTracks] = SimTHit.getPosition()[1]; + m_ToFz[m_nTracks] = SimTHit.getPosition()[2]; + hasFTDHit = true; + }else{ + m_ToFt[m_nTracks] = -999; + m_ToFx[m_nTracks] = -999; + m_ToFy[m_nTracks] = -999; + m_ToFz[m_nTracks] = -999; + } + } + else { + m_ToFt[m_nTracks] = -999; + m_ToFx[m_nTracks] = -999; + m_ToFy[m_nTracks] = -999; + m_ToFz[m_nTracks] = -999; + } + }//end track hits + if ( !hasSETHit && !hasFTDHit ) continue; + + // smearing the measured time by gaussian 0.05 for intrinsic and 0.02 for bunchcrossing, giving the measured terr a constant + m_ToFterr[m_nTracks] = std::sqrt(tof_resolution*tof_resolution + bunchcrossing*bunchcrossing); + m_ToFt[m_nTracks] += normal_distribution_tof(generator_tof); + m_ToFt[m_nTracks] += normal_distribution_bunch(generator_bunch); + + // found ToF hit, then to evaluate trajectory length + for( std::vector<edm4hep::TrackState>::const_iterator it = track.trackStates_begin(); it != track.trackStates_end(); it++ ){ + + edm4hep::TrackState trackState = *it; + int _location = trackState.location; + (*trackStateMap[_location])[m_nTracks][0] = _location; + (*trackStateMap[_location])[m_nTracks][1] = trackState.D0; + (*trackStateMap[_location])[m_nTracks][2] = trackState.phi; + (*trackStateMap[_location])[m_nTracks][3] = trackState.omega; + (*trackStateMap[_location])[m_nTracks][4] = trackState.Z0; + (*trackStateMap[_location])[m_nTracks][5] = trackState.tanLambda; + (*trackStateMap[_location])[m_nTracks][6] = trackState.time; + (*trackStateMap[_location])[m_nTracks][7] = trackState.referencePoint[0]; + (*trackStateMap[_location])[m_nTracks][8] = trackState.referencePoint[1]; + (*trackStateMap[_location])[m_nTracks][9] = trackState.referencePoint[2]; + (*trackStateMap[_location])[m_nTracks][10] = std::sqrt(trackState.covMatrix[0]); + (*trackStateMap[_location])[m_nTracks][11] = std::sqrt(trackState.covMatrix[2]); + (*trackStateMap[_location])[m_nTracks][12] = std::sqrt(trackState.covMatrix[5]); + (*trackStateMap[_location])[m_nTracks][13] = std::sqrt(trackState.covMatrix[9]); + (*trackStateMap[_location])[m_nTracks][14] = std::sqrt(trackState.covMatrix[14]); + + } + + //expected time calculation + if ( hasSETHit || hasFTDHit ){ + + // trackState at IP + float phi0 = (*trackStateMap[1])[m_nTracks][2]; + if (phi0 < 0) phi0 += 2*M_PI; + float phi0err = (*trackStateMap[1])[m_nTracks][11]; + //float z0 = (*trackStateMap[1])[m_nTracks][4]; + //float z0err = (*trackStateMap[1])[m_nTracks][13]; + float omega0 = (*trackStateMap[1])[m_nTracks][3]; + float omega0err = (*trackStateMap[1])[m_nTracks][12]; + float totz0 = (*trackStateMap[1])[m_nTracks][4] + (*trackStateMap[1])[m_nTracks][9]; + float totz0err = (*trackStateMap[1])[m_nTracks][13]; + float tanL0 = (*trackStateMap[1])[m_nTracks][5]; + float tanL0err = (*trackStateMap[1])[m_nTracks][14]; + + float radius0 = 1./std::abs(omega0); + float radius0err = omega0err/(omega0*omega0); + + float pT_tmp = radius0 * m_field * c * 10E-13; + float pTerr_tmp = radius0err * m_field * c * 10E-13; + + float pZ_tmp = pT_tmp*tanL0; + float pZerr_tmp = std::sqrt( pT_tmp*pT_tmp*tanL0err*tanL0err + tanL0*tanL0*pTerr_tmp*pTerr_tmp ); + + float p_atIP = std::sqrt( pT_tmp*pT_tmp + pZ_tmp*pZ_tmp ); + float perr_atIP = std::sqrt( (pT_tmp*pT_tmp / p_atIP*p_atIP)*(pTerr_tmp*pTerr_tmp) + (pZ_tmp*pZ_tmp / p_atIP*p_atIP)*(pZerr_tmp*pZerr_tmp) ); + + // trackState at the last hit + float phi1 = (*trackStateMap[3])[m_nTracks][2]; + if (phi1 < 0) phi1 += 2*M_PI; + float phi1err = (*trackStateMap[3])[m_nTracks][11]; + //float z1 = (*trackStateMap[3])[m_nTracks][4]; + //float z1err = (*trackStateMap[3])[m_nTracks][13]; + float omega1 = (*trackStateMap[3])[m_nTracks][3]; + float omega1err = (*trackStateMap[3])[m_nTracks][12]; + float totz1 = (*trackStateMap[3])[m_nTracks][4] + (*trackStateMap[3])[m_nTracks][9]; + float totz1err = (*trackStateMap[3])[m_nTracks][13]; + float tanL1 = (*trackStateMap[3])[m_nTracks][5]; + float tanL1err = (*trackStateMap[3])[m_nTracks][14]; + + float radius1 = 1./std::abs(omega1); + float radius1err = omega1err/(omega1*omega1); + + float pT_tmp1 = radius1 * m_field * c * 10E-13; + float pTerr_tmp1 = radius1err * m_field * c * 10E-13; + + float pZ_tmp1 = pT_tmp1*tanL1; + float pZerr_tmp1 = std::sqrt( pT_tmp1*pT_tmp1*tanL1err*tanL1err + tanL1*tanL1*pTerr_tmp1*pTerr_tmp1 ); + + float p_atLast = std::sqrt(pT_tmp1*pT_tmp1 + pZ_tmp1*pZ_tmp1); + float perr_atLast = std::sqrt( (pT_tmp1*pT_tmp1 / p_atLast*p_atLast)*(pTerr_tmp1*pTerr_tmp1) + (pZ_tmp1*pZ_tmp1 / p_atLast*p_atLast)*(pZerr_tmp1*pZerr_tmp1) ); + + //assum all tracks end in one circle, for multi cirlce tracks, the result does not make sense + float deltaphi = phi1 -phi0; + if ( omega0 * deltaphi > 0.0 ){ + deltaphi = 2. * M_PI - std::abs( deltaphi ); + } + + // calculate the length + float _length = std::sqrt( radius0*radius0 * (deltaphi)*(deltaphi) + (totz1-totz0)*(totz1-totz0) );//in mm + float _lengtherr = 0.0; + float _ldr2 = (radius0*radius0) * (deltaphi)*(deltaphi)*(deltaphi)*(deltaphi) / (_length*_length); + float _ldphi02 = radius0*radius0*radius0*radius0 * (deltaphi)*(deltaphi) / (_length*_length); + float _ldphi12 = _ldphi02; + float _ldz02 = (totz1-totz0)*(totz1-totz0) / (_length*_length); + float _ldz12 = _ldz02; + + _lengtherr = std::sqrt( _ldr2*radius0err*radius0err + _ldphi02*phi0err*phi0err + _ldphi12*phi1err*phi1err + _ldz02*totz0err*totz0err + _ldz12*totz1err*totz1err ); + m_length[m_nTracks] = _length; + m_lengtherr[m_nTracks] = _lengtherr; + m_p_atIP[m_nTracks] = p_atIP; + m_perr_atIP[m_nTracks] = perr_atIP; + m_p_atLast[m_nTracks] = p_atLast; + m_perr_atLast[m_nTracks] = perr_atLast; + + //momenta to kg m/s + float p_tmp = p_atIP * GeV2kgms; + float perr_tmp = perr_atIP * GeV2kgms; + + for (auto it = masses.begin(); it != masses.end(); ++it){//expected times and errors for e, mu, pi, k, proton + int idx = it->first; + double assum = it->second; + double m_tmp = assum * GeV2kg; + double E_tmp = std::sqrt(p_tmp * p_tmp * c * c + m_tmp * m_tmp * c * c * c * c); + double v_tmp = p_tmp * c * c / E_tmp; + double verr_tmp = perr_tmp * ( c * c * E_tmp - (p_tmp * p_tmp * c * c * c * c/E_tmp))/ (E_tmp * E_tmp); + double t_tmp = 10e5 * _length / v_tmp; + double terr_tmp = 10e5 * std::sqrt( (_lengtherr/v_tmp)*(_lengtherr/v_tmp) + ( (_length*_length)/(v_tmp*v_tmp*v_tmp*v_tmp) )*verr_tmp*verr_tmp ); + m_exp_time[m_nTracks][idx] = t_tmp; + m_exp_timeerr[m_nTracks][idx] = terr_tmp; + debug()<<"idx : "<< idx <<" assum: "<< assum <<" omega: "<<omega0<<" length: "<<_length<<" phi1: "<<phi1<<" phi0: "<<phi0<<" phi1-phi0: "<<deltaphi<<" exp_t: "<<t_tmp<<" obs_t: "<<m_ToFt[m_nTracks]<<endmsg; + } + + }else{ + m_length[m_nTracks] = -999; + m_lengtherr[m_nTracks] = -999; + m_p_atIP[m_nTracks] = -999; + m_perr_atIP[m_nTracks] = -999; + m_p_atLast[m_nTracks] = -999; + m_perr_atLast[m_nTracks] = -999; + for (auto it = masses.begin(); it != masses.end(); ++it){ + int idx = it->first; + m_exp_time[m_nTracks][idx] = -999; + m_exp_timeerr[m_nTracks][idx] = -999; + } + } + m_nTracks++; + + }// end track iteration + + }//end track collection + + m_tuple->write(); + _nEvt++; + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------------ +StatusCode TofRecAlg::finalize(){ + debug() << "Finalizing..." << endmsg; + + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/TofRecAlg/src/TofRecAlg.h b/Reconstruction/TofRecAlg/src/TofRecAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a9a5362a2988774840441ed8765333d52c0d0706 --- /dev/null +++ b/Reconstruction/TofRecAlg/src/TofRecAlg.h @@ -0,0 +1,108 @@ +#ifndef TofRecAlg_h +#define TofRecAlg_h 1 + +#include "k4FWCore/DataHandle.h" +#include "GaudiKernel/Algorithm.h" + +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include <random> +#include "GaudiKernel/NTuple.h" + +class TofRecAlg : public Algorithm { + public: + // Constructor of this form must be provided + TofRecAlg( 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::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackCollection> _inTrackColHdl{"CompleteTracks", Gaudi::DataHandle::Reader, this}; + + Gaudi::Property<double> m_field{this, "Field", 3.0}; + + NTuple::Tuple* m_tuple; + NTuple::Item<long> m_nTracks; + NTuple::Array<float> m_x; + NTuple::Array<float> m_y; + NTuple::Array<float> m_z; + NTuple::Array<float> m_px; + NTuple::Array<float> m_py; + NTuple::Array<float> m_pz; + NTuple::Array<float> m_p; + NTuple::Array<float> m_d0; + NTuple::Array<float> m_phi0; + NTuple::Array<float> m_omega; + NTuple::Array<float> m_z0; + NTuple::Array<float> m_tanLambda; + NTuple::Array<float> m_sigma_d0; + NTuple::Array<float> m_sigma_phi0; + NTuple::Array<float> m_sigma_omega; + NTuple::Array<float> m_sigma_z0; + NTuple::Array<float> m_sigma_tanLambda; + + NTuple::Array<float> m_ToFt; + NTuple::Array<float> m_ToFterr; + NTuple::Array<float> m_ToFx; + NTuple::Array<float> m_ToFy; + NTuple::Array<float> m_ToFz; + + NTuple::Matrix<float> trackState0; + NTuple::Matrix<float> trackState1; + NTuple::Matrix<float> trackState2; + NTuple::Matrix<float> trackState3; + NTuple::Matrix<float> trackState4; + NTuple::Matrix<float> trackState5; + + std::map<int, NTuple::Matrix<float>*> trackStateMap = { + {0, &trackState0}, + {1, &trackState1}, + {2, &trackState2}, + {3, &trackState3}, + {4, &trackState4}, + {5, &trackState5} + }; + + NTuple::Array<float> m_length; + NTuple::Array<float> m_lengtherr; + + NTuple::Array<float> m_p_atIP; + NTuple::Array<float> m_perr_atIP; + NTuple::Array<float> m_p_atLast; + NTuple::Array<float> m_perr_atLast; + + NTuple::Matrix<double> m_exp_time; + NTuple::Matrix<double> m_exp_timeerr; + + int _nEvt; + + const std::map<int, double> masses = {//masses in GeV for e mu pi K p + {0, 0.000511}, + {1, 0.105658}, + {2, 0.139570}, + {3, 0.493677}, + {4, 0.938272}, + }; + + float GeV2kgms = 5.344286e-19;//momenta in GeV to kg m/s + float GeV2kg = 1.78266192e-27;//mass in GeV to kg + float c = 2.99792458e8;//spead of light in m/s + float q = 1.60217662e-19;//electron charge in C + + float bunchcrossing = 0.02;//ns + float tof_resolution = 0.05;//ns + std::default_random_engine generator_tof; + std::normal_distribution<float> normal_distribution_tof{0, tof_resolution}; + std::default_random_engine generator_bunch; + std::normal_distribution<float> normal_distribution_bunch{0, bunchcrossing}; + + +}; + +#endif \ No newline at end of file