From 712dbc0b62671fae40c15a956a0153d0f3a7463a Mon Sep 17 00:00:00 2001 From: Jan Klamka Date: Wed, 17 Jan 2024 15:31:22 +0100 Subject: [PATCH 1/2] [wip] start to integrate TPC pixel readout --- ILD/compact/ILD_common_v02/tpc10_01.xml | 2 +- ILD/compact/ILD_l1_v01/ILD_l1_v01.xml | 6 +- ILD/compact/ILD_l6_v02/ILD_l6_v02.xml | 4 + detector/tracker/TPC10_geo.cpp | 17 +- plugins/TPCSDAction.cpp | 1230 ++++++++++++++--------- 5 files changed, 759 insertions(+), 500 deletions(-) diff --git a/ILD/compact/ILD_common_v02/tpc10_01.xml b/ILD/compact/ILD_common_v02/tpc10_01.xml index eb46b3b73..a1b00eb9a 100644 --- a/ILD/compact/ILD_common_v02/tpc10_01.xml +++ b/ILD/compact/ILD_common_v02/tpc10_01.xml @@ -85,7 +85,7 @@ - system:5,side:2,layer:9,module:8,sensor:8 + system:5,side:-2,layer:9,module:8,sensor:8 diff --git a/ILD/compact/ILD_l1_v01/ILD_l1_v01.xml b/ILD/compact/ILD_l1_v01/ILD_l1_v01.xml index 4afbf7c61..a23e1a307 100644 --- a/ILD/compact/ILD_l1_v01/ILD_l1_v01.xml +++ b/ILD/compact/ILD_l1_v01/ILD_l1_v01.xml @@ -18,6 +18,10 @@ + + + + @@ -148,7 +152,7 @@ - system:5,side:2,layer:9,module:8,sensor:8 + system:5,side:2,layer:17,module:20,sensor:8 diff --git a/ILD/compact/ILD_l6_v02/ILD_l6_v02.xml b/ILD/compact/ILD_l6_v02/ILD_l6_v02.xml index 6cac4da2e..d64bfa93e 100644 --- a/ILD/compact/ILD_l6_v02/ILD_l6_v02.xml +++ b/ILD/compact/ILD_l6_v02/ILD_l6_v02.xml @@ -19,6 +19,10 @@ + + + + diff --git a/detector/tracker/TPC10_geo.cpp b/detector/tracker/TPC10_geo.cpp index 888aff300..95d42532c 100644 --- a/detector/tracker/TPC10_geo.cpp +++ b/detector/tracker/TPC10_geo.cpp @@ -84,6 +84,11 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se const double dzTotal = theDetector.constant("TPC_Ecal_Hcal_barrel_halfZ") * 2. ; const double rInner = theDetector.constant("TPC_inner_radius") ; const double rOuter = theDetector.constant("TPC_outer_radius") ; + + //chose between pixel and pad readout + const std::string TPCReadoutType= theDetector.constantAsString("TPC_readoutType"); + const bool pixelTPC = (TPCReadoutType=="pixel") ; + // Geometry parameters from the geometry environment and from the database @@ -108,8 +113,10 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se // _gear_gas_material = material_TPC_Gas; // #endif - //unused: const double sensitive_threshold_eV = db->fetchDouble("sensitive_threshold_eV") ; - + if(pixelTPC) { + const double sensitive_threshold_eV = db->fetchDouble("sensitive_threshold_eV") ; + sens.setEnergyCutoff(sensitive_threshold_eV); + } // db->exec("SELECT * FROM `cathode`;"); // db->getTuple(); @@ -435,7 +442,7 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ; for (int layer = 0; layer < numberPadRows; layer++) { -#if 1 + if(!pixelTPC) {//padTPC // create twice the number of rings as there are pads, producing an lower and upper part of the pad with the boundry between them the pad-ring centre const double inner_lowerlayer_radius = rMin_Sensitive + (layer * (padHeight)); @@ -477,7 +484,7 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ; lowerlayerLog.setSensitiveDetector(sens); upperlayerLog.setSensitiveDetector(sens); -#else + } else if (pixelTPC) { // create just one volume per pad ring const double inner_radius = rMin_Sensitive + (layer * (padHeight) ); @@ -507,7 +514,7 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ; layerLog.setSensitiveDetector(sens); -#endif + } } // Assembly of the TPC Readout diff --git a/plugins/TPCSDAction.cpp b/plugins/TPCSDAction.cpp index 1c4f385bd..d035d7159 100644 --- a/plugins/TPCSDAction.cpp +++ b/plugins/TPCSDAction.cpp @@ -4,510 +4,754 @@ #include "G4OpticalPhoton.hh" #include "G4VProcess.hh" +//DD4hep +#include "DDRec/DetectorData.h" +#include "IMPL/SimTrackerHitImpl.h" + + +//helper class +#include "InterpolatedHitGenerator.h" + /// Namespace for the AIDA detector description toolkit namespace dd4hep { - - /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit - namespace sim { - - /** - * Geant4SensitiveAction sensitive detector for the special case of - * of a TPC, where every pad row is devided into two halfs in order to get - * the position from the crossing of the middle of the pad row from - * geant4 via volume boundary. Ported of Mokka/TPCSD04.cc - * - * \author F.Gaede ( ported from Mokka/TPCSD04.cc ) - * \version 1.0 - * \ingroup DD4HEP_SIMULATION - */ - struct TPCSDData { - - // helper struct with Mokka controls ... - struct { - double TPCLowPtCut {}; - bool TPCLowPtStepLimit {}; - double TPCLowPtMaxHitSeparation {}; - } Control {}; - - typedef Geant4HitCollection HitCollection; - Geant4Sensitive* sensitive{}; - const BitFieldElement* layerField {}; - - G4double fThresholdEnergyDeposit{}; - Geant4HitCollection *fHitCollection{}; - Geant4HitCollection *fSpaceHitCollection{}; - Geant4HitCollection *fLowPtHitCollection{}; - G4int fHCID{}; - G4int fSpaceHitCollectionID{}; - G4int fLowPtHitCollectionID{}; - - G4ThreeVector CrossingOfPadRingCentre{}; - G4ThreeVector MomentumAtPadRingCentre{}; - G4double dEInPadRow{}; - G4double globalTimeAtPadRingCentre{}; - G4double pathLengthInPadRow{}; - G4double CumulativePathLength{}; - G4double CumulativeEnergyDeposit{}; - G4ThreeVector CumulativeMeanPosition{}; - G4ThreeVector CumulativeMeanMomentum{}; - G4int CumulativeNumSteps{}; - - G4ThreeVector PreviousPostStepPosition{}; //< the end point of the previous step - G4int CurrentPDGEncoding{}; //< the PDG encoding of the particle causing the cumulative energy deposit - G4int CurrentTrackID{}; //< the TrackID of the particle causing the cumulative energy deposit - G4double CurrentGlobalTime{}; ///< the global time of the track causing the cumulative energy deposit - G4int CurrentCopyNumber{}; ///< copy number of the preStepPoint's TouchableHandle for the cumulative energy deposit - - - TPCSDData() : - fThresholdEnergyDeposit(0), - // fHitCollection(0), - // fSpaceHitCollection(0), - // fLowPtHitCollection(0), - fHCID(-1), - fSpaceHitCollectionID(-1), - fLowPtHitCollectionID(-1), - CurrentTrackID(-1) { - - - Control.TPCLowPtCut = CLHEP::MeV ; - Control.TPCLowPtStepLimit = false ; - Control.TPCLowPtMaxHitSeparation = 5. * CLHEP::mm ; - - } - - - /// Clear collected information and restart for new hit - void clear() { - // nothing to clear - } - - - /// return the layer number of the volume (either pre or post-position ) - int getCopyNumber(G4Step* s, bool usePostPos ){ - - int cellID = this->volID( s , usePostPos) ; - - return this->layerField->value( cellID ) ; - } - - - /// Returns the volumeID of sensitive volume corresponding to the step (either pre or post-position ) - long long int volID( G4Step* s, bool usePostPos=false ) { - - Geant4StepHandler h(s); - - Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager(); - - VolumeID volID = ( usePostPos ? volMgr.volumeID(h.postTouchable()) : volMgr.volumeID(h.preTouchable()) ); - - return volID; - } - - - void dumpStep( Geant4StepHandler h, G4Step* s){ - - std::cout << " ----- step in detector " << h.sdName( s->GetPreStepPoint() ) - << " prePos " << h.prePos() - << " postPos " << h.postPos() - << " preStatus " << h.preStepStatus() - << " postStatus " << h.postStepStatus() - << " preVolume " << h.volName( s->GetPreStepPoint() ) - << " postVolume " << h.volName( s->GetPostStepPoint() ) - << " CurrentCopyNumbers " << getCopyNumber( s, false ) - << " - " << getCopyNumber( s, true ) - << std::endl - << " momentum : " << std::scientific - << s->GetPreStepPoint()->GetMomentum()[0] << ", " << s->GetPreStepPoint()->GetMomentum()[1]<< ", " << s->GetPreStepPoint()->GetMomentum()[2] - << " / " - << s->GetPostStepPoint()->GetMomentum()[0] << ", " << s->GetPostStepPoint()->GetMomentum()[1]<< ", " << s->GetPostStepPoint()->GetMomentum()[2] - << ", PDG: " << s->GetTrack()->GetDefinition()->GetPDGEncoding() - << std::endl ; - } - - - - - /// Method for generating hit(s) using the information of G4Step object. - G4bool process(G4Step* step, G4TouchableHistory* ) { - - - fHitCollection = sensitive->collection(0) ; - fSpaceHitCollection = sensitive->collection(1) ; - fLowPtHitCollection = sensitive->collection(2) ; - - Geant4StepHandler h(step); - // dumpStep( h , step ) ; - - // FIXME: - // (i) in the following algorithm if a particle "appears" within a pad-ring half and - // leaves without passing through the middle of the pad-ring it will not create a hit in - // this ring - // (ii) a particle that crosses the boundry between two pad-ring halves will have the hit - // placed on this surface at the last crossing point, and will be assinged the total energy - // deposited in the whole pad-ring. This is a possible source of bias for the hit - - - if (fabs(step->GetTrack()->GetDefinition()->GetPDGCharge()) < 0.01) return true; - - const G4ThreeVector PrePosition = step->GetPreStepPoint()->GetPosition(); - const G4ThreeVector PostPosition = step->GetPostStepPoint()->GetPosition(); - const G4ThreeVector thisMomentum = step->GetPostStepPoint()->GetMomentum(); - - float ptSQRD = thisMomentum[0]*thisMomentum[0]+thisMomentum[1]*thisMomentum[1]; - - - //========================================================================================================= - - if( ptSQRD >= (Control.TPCLowPtCut*Control.TPCLowPtCut) ){ - - //========================================================================================================= - // Step finishes at a geometric boundry - - if(step->GetPostStepPoint()->GetStepStatus() == fGeomBoundary) { - - // step within the same pair of upper and lower pad ring halves - if( getCopyNumber( step, false ) == getCopyNumber( step, true ) ){ - - //this step must have ended on the boundry between these two pad ring halfs - //record the tracks coordinates at this position - //and return - - CrossingOfPadRingCentre = PostPosition; - MomentumAtPadRingCentre = thisMomentum; - dEInPadRow += step->GetTotalEnergyDeposit(); - globalTimeAtPadRingCentre = step->GetTrack()->GetGlobalTime(); - pathLengthInPadRow += step->GetStepLength(); - - // G4cout << "step must have ended on the boundry between these two pad ring halfs" << G4endl; - // G4cout << "CrossingOfPadRingCentre = " - // << sqrt( CrossingOfPadRingCentre[0]*CrossingOfPadRingCentre[0] - // +CrossingOfPadRingCentre[1]*CrossingOfPadRingCentre[1] ) - // << G4endl; - - return true; - - } - else if(!(CrossingOfPadRingCentre[0]==0.0 && CrossingOfPadRingCentre[1]==0.0 && CrossingOfPadRingCentre[2]==0.0)) { - // the above IF statment is to catch the case where the particle "appears" in this pad-row half volume and - // leaves with out crossing the pad-ring centre, as mentioned above - - // it is leaving the pad ring couplet - // write out a hit - - // G4cout << "step must be leaving the pad ring couplet" << G4endl; - // G4cout << "write out hit at " - // << sqrt( CrossingOfPadRingCentre[0]*CrossingOfPadRingCentre[0] - // +CrossingOfPadRingCentre[1]*CrossingOfPadRingCentre[1] ) - // << " " << "dEdx = " << step->GetTotalEnergyDeposit()+dEInPadRow - // << " " << "step length = " << step->GetStepLength()+pathLengthInPadRow - // << G4endl; - - G4double dE = step->GetTotalEnergyDeposit()+dEInPadRow; - - if ( dE > fThresholdEnergyDeposit ) { - - -//xx fHitCollection-> -//xx insert(new TRKHit(touchPre->GetCopyNumber(), -//xx CrossingOfPadRingCentre[0],CrossingOfPadRingCentre[1],CrossingOfPadRingCentre[2], -//xx MomentumAtPadRingCentre[0], -//xx MomentumAtPadRingCentre[1], -//xx MomentumAtPadRingCentre[2], -//xx info->GetTheTrackSummary()->GetTrackID(), -//xx step->GetTrack()->GetDefinition()->GetPDGEncoding(), -//xx dE, -//xx globalTimeAtPadRingCentre, -//xx step->GetStepLength()+pathLengthInPadRow)); -//xx - Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(step->GetTrack()->GetTrackID(), - step->GetTrack()->GetDefinition()->GetPDGEncoding(), - dE, globalTimeAtPadRingCentre); - hit->position = CrossingOfPadRingCentre ; - hit->momentum = MomentumAtPadRingCentre; - hit->length = step->GetStepLength(); - hit->cellID = sensitive->cellID( step ) ; - fHitCollection->add(hit); +/// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit +namespace sim { + +/** + * Geant4SensitiveAction sensitive detector for the special case of + * of a TPC, where every pad row is devided into two halfs in order to get + * the position from the crossing of the middle of the pad row from + * geant4 via volume boundary. Ported of Mokka/TPCSD04.cc + * + * \author F.Gaede ( ported from Mokka/TPCSD04.cc ) + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ +struct trackIDExtension : lcrtrel::LCIntExtension {}; + +struct TPCSDData { + + // helper struct with Mokka controls ... + struct { + double TPCLowPtCut {}; + bool TPCLowPtStepLimit {}; + double TPCLowPtMaxHitSeparation {}; + } Control {}; + + typedef Geant4HitCollection HitCollection; + Geant4Sensitive* sensitive{}; + const BitFieldElement* layerField {}; + + G4double fThresholdEnergyDeposit{}; + Geant4HitCollection *fHitCollection{}; + Geant4HitCollection *fSpaceHitCollection{}; + Geant4HitCollection *fLowPtHitCollection{}; + G4int fHCID{}; + G4int fSpaceHitCollectionID{}; + G4int fLowPtHitCollectionID{}; + + G4ThreeVector CrossingOfPadRingCentre{}; + G4ThreeVector MomentumAtPadRingCentre{}; + G4double dEInPadRow{}; + G4double globalTimeAtPadRingCentre{}; + G4double pathLengthInPadRow{}; + G4double CumulativePathLength{}; + G4double CumulativeEnergyDeposit{}; + G4ThreeVector CumulativeMeanPosition{}, currentMeanPosition{}, firstStepPrePosition{},firstStepPreMomentum{}; + G4ThreeVector CumulativeMeanMomentum{}, currentMeanMomentum{}; + G4int CumulativeNumSteps{}; + G4int firstStepTrackID; + + bool pixelTPC{false}, fastSimulation{false}; + dd4hep::rec::FixedPadSizeTPCData* tpcData{nullptr}; + + G4ThreeVector PreviousPostStepPosition{}; //< the end point of the previous step + G4Step* previousStep{}; //pointer to previous step + G4int CurrentPDGEncoding{}; //< the PDG encoding of the particle causing the cumulative energy deposit + G4int CurrentTrackID{}; //< the TrackID of the particle causing the cumulative energy deposit + G4double CurrentGlobalTime{}; ///< the global time of the track causing the cumulative energy deposit + G4int CurrentCopyNumber{}; ///< copy number of the preStepPoint's TouchableHandle for the cumulative energy deposit + G4int eventNumber{0}; //event number + + + TPCSDData() : + fThresholdEnergyDeposit(0), + // fHitCollection(0), + // fSpaceHitCollection(0), + // fLowPtHitCollection(0), + fHCID(-1), + pixelTPC(false), + fSpaceHitCollectionID(-1), + fLowPtHitCollectionID(-1), + CurrentTrackID(-1), + previousStep(new G4Step()) + { + ResetCumulativeVariables(); + Control.TPCLowPtCut = CLHEP::MeV ; + Control.TPCLowPtStepLimit = false ; + Control.TPCLowPtMaxHitSeparation = 5. * CLHEP::mm ; + + } + +// ~TPCSDData() { +// delete previousStep; +// } + + /// Clear collected information and restart for new hit + void clear() { + // nothing to clear + } + + + /// return the layer number of the volume (either pre or post-position ) + int getCopyNumber(G4Step* s, bool usePostPos ){ + + int cellID = this->volID( s , usePostPos) ; + + return this->layerField->value( cellID ) ; + } + + + /// Returns the volumeID of sensitive volume corresponding to the step (either pre or post-position ) + long long int volID( G4Step* s, bool usePostPos=false ) { + + Geant4StepHandler h(s); + + Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager(); + + VolumeID volID = ( usePostPos ? volMgr.volumeID(h.postTouchable()) : volMgr.volumeID(h.preTouchable()) ); + + return volID; + } + + + void dumpStep( Geant4StepHandler h, G4Step* s){ + + G4cout << " ----- step in detector " << h.sdName( s->GetPreStepPoint() ) + << " prePos " << h.prePos() + << " postPos " << h.postPos() + << " preStatus " << h.preStepStatus() + << " postStatus " << h.postStepStatus() + << " preVolume " << h.volName( s->GetPreStepPoint() ) + << " postVolume " << h.volName( s->GetPostStepPoint() ) + << " stepLength " << s->GetStepLength() + << " EnergyDeposit " << s->GetTotalEnergyDeposit()/CLHEP::eV << " eV" + << " CurrentCopyNumbers " << getCopyNumber( s, false ) + << " - " << getCopyNumber( s, true ) + << "\n" + << " momentum : " << std::scientific + << s->GetPreStepPoint()->GetMomentum()[0] << ", " << s->GetPreStepPoint()->GetMomentum()[1]<< ", " << s->GetPreStepPoint()->GetMomentum()[2] + << " / " + << s->GetPostStepPoint()->GetMomentum()[0] << ", " << s->GetPostStepPoint()->GetMomentum()[1]<< ", " << s->GetPostStepPoint()->GetMomentum()[2] + << ", PDG: " << s->GetTrack()->GetDefinition()->GetPDGEncoding() + << "\n"; + G4cout<<"current cumulative energy is "<collection(0) ; + fSpaceHitCollection = sensitive->collection(1) ; + fLowPtHitCollection = sensitive->collection(2) ; + + Geant4StepHandler h(step); + // dumpStep( h , step ) ; + + // FIXME: + // (i) in the following algorithm if a particle "appears" within a pad-ring half and + // leaves without passing through the middle of the pad-ring it will not create a hit in + // this ring + // (ii) a particle that crosses the boundary between two pad-ring halves will have the hit + // placed on this surface at the last crossing point, and will be assigned the total energy + // deposited in the whole pad-ring. This is a possible source of bias for the hit + + //check charge + if (fabs(step->GetTrack()->GetDefinition()->GetPDGCharge()) < 0.01) return true; + + const G4ThreeVector PrePosition = step->GetPreStepPoint()->GetPosition(); + const G4ThreeVector PostPosition = step->GetPostStepPoint()->GetPosition(); + const G4ThreeVector thisMomentum = step->GetPostStepPoint()->GetMomentum(); + + float ptSQRD = thisMomentum[0]*thisMomentum[0]+thisMomentum[1]*thisMomentum[1]; + + + //========================================================================================================= + + if( ptSQRD >= (Control.TPCLowPtCut*Control.TPCLowPtCut) ){ + + //========================================================================================================= + // Step finishes at a geometric boundry + + if(step->GetPostStepPoint()->GetStepStatus() == fGeomBoundary) { + + // step within the same pair of upper and lower pad ring halves + if( getCopyNumber( step, false ) == getCopyNumber( step, true ) ){ + + //this step must have ended on the boundry between these two pad ring halfs + //record the tracks coordinates at this position + //and return + + CrossingOfPadRingCentre = PostPosition; + MomentumAtPadRingCentre = thisMomentum; + dEInPadRow += step->GetTotalEnergyDeposit(); + globalTimeAtPadRingCentre = step->GetTrack()->GetGlobalTime(); + pathLengthInPadRow += step->GetStepLength(); + + // G4cout << "step must have ended on the boundry between these two pad ring halfs" << G4endl; + // G4cout << "CrossingOfPadRingCentre = " + // << sqrt( CrossingOfPadRingCentre[0]*CrossingOfPadRingCentre[0] + // +CrossingOfPadRingCentre[1]*CrossingOfPadRingCentre[1] ) + // << G4endl; + + return true; + + } + else if(!(CrossingOfPadRingCentre[0]==0.0 && CrossingOfPadRingCentre[1]==0.0 && CrossingOfPadRingCentre[2]==0.0)) { + // the above IF statment is to catch the case where the particle "appears" in this pad-row half volume and + // leaves with out crossing the pad-ring centre, as mentioned above + + // it is leaving the pad ring couplet + // write out a hit + + // G4cout << "step must be leaving the pad ring couplet" << G4endl; + // G4cout << "write out hit at " + // << sqrt( CrossingOfPadRingCentre[0]*CrossingOfPadRingCentre[0] + // +CrossingOfPadRingCentre[1]*CrossingOfPadRingCentre[1] ) + // << " " << "dEdx = " << step->GetTotalEnergyDeposit()+dEInPadRow + // << " " << "step length = " << step->GetStepLength()+pathLengthInPadRow + // << G4endl; + + G4double dE = step->GetTotalEnergyDeposit()+dEInPadRow; + + if ( dE > fThresholdEnergyDeposit ) { + + + //xx fHitCollection-> + //xx insert(new TRKHit(touchPre->GetCopyNumber(), + //xx CrossingOfPadRingCentre[0],CrossingOfPadRingCentre[1],CrossingOfPadRingCentre[2], + //xx MomentumAtPadRingCentre[0], + //xx MomentumAtPadRingCentre[1], + //xx MomentumAtPadRingCentre[2], + //xx info->GetTheTrackSummary()->GetTrackID(), + //xx step->GetTrack()->GetDefinition()->GetPDGEncoding(), + //xx dE, + //xx globalTimeAtPadRingCentre, + //xx step->GetStepLength()+pathLengthInPadRow)); + //xx + Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(step->GetTrack()->GetTrackID(), + step->GetTrack()->GetDefinition()->GetPDGEncoding(), + dE, globalTimeAtPadRingCentre); + hit->position = CrossingOfPadRingCentre ; + hit->momentum = MomentumAtPadRingCentre; + hit->length = step->GetStepLength(); + hit->cellID = sensitive->cellID( step ) ; + + fHitCollection->add(hit); + + sensitive->printM2("+++ TrackID:%6d [%s] CREATE TPC hit at pad row crossing :" + " %e MeV Pos:%8.2f %8.2f %8.2f", + step->GetTrack()->GetTrackID(),sensitive->c_name(), dE, + hit->position.X()/CLHEP::mm,hit->position.Y()/CLHEP::mm,hit->position.Z()/CLHEP::mm); + + } + + // zero cumulative variables + dEInPadRow = 0.0; + globalTimeAtPadRingCentre=0.0; + pathLengthInPadRow=0.0; + CrossingOfPadRingCentre[0]=0.0; + CrossingOfPadRingCentre[1]=0.0; + CrossingOfPadRingCentre[2]=0.0; + MomentumAtPadRingCentre[0]=0.0; + MomentumAtPadRingCentre[1]=0.0; + MomentumAtPadRingCentre[2]=0.0; + return true; + } + + + + } + + //========================================================================================================= + // case for which the step remains within geometric volume + + //FIXME: need and another IF case to catch particles which Stop within the padring + + else { // else if(step->GetPostStepPoint()->GetStepStatus() != fGeomBoundary) { + + // the step is not limited by the step length + if( step->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName() != "StepLimiter"){ + + // if(particle not stoped){ + // add the dEdx and return + // G4cout << "Step ended by Physics Process: Add dEdx and carry on" << G4endl; + dEInPadRow += step->GetTotalEnergyDeposit(); + pathLengthInPadRow += step->GetStepLength(); + return true; + //} + //else{ + // write out the hit and clear counters + //} + + + } else { // GetProcessName() == "StepLimiter" + + // G4cout << "step must have been stopped by the step limiter" << G4endl; + // G4cout << "write out hit at " + // << sqrt( position_x*position_x + // +position_y*position_y ) + // << " " << "dEdx = " << step->GetTotalEnergyDeposit() + // << " " << "step length = " << step->GetStepLength() + // << G4endl; + + // write out step limited hit + // these are just space point hits so do not save the dE, which is set to ZERO + // if ( step->GetTotalEnergyDeposit() > fThresholdEnergyDeposit ) + + //xx fSpaceHitCollection-> + //xx insert(new TRKHit(touchPre->GetCopyNumber(), + //xx position_x,position_y,position_z, + //xx momentum_x,momentum_y,momentum_z, + //xx info->GetTheTrackSummary()->GetTrackID(), + //xx step->GetTrack()->GetDefinition()->GetPDGEncoding(), + //xx 0.0, // dE set to ZERO + //xx step->GetTrack()->GetGlobalTime(), + //xx step->GetStepLength())); + + Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(step->GetTrack()->GetTrackID(), + step->GetTrack()->GetDefinition()->GetPDGEncoding(), + 0.0, globalTimeAtPadRingCentre); // dE set to ZERO + + hit->position = 0.5*( PrePosition + PostPosition ); + hit->momentum = thisMomentum ; + hit->length = step->GetStepLength(); + hit->cellID = sensitive->cellID( step ) ; + + fSpaceHitCollection->add(hit); + + + + // add dE and pathlegth and return + dEInPadRow += step->GetTotalEnergyDeposit(); + pathLengthInPadRow += step->GetStepLength(); + return true; + } + } + + + + } + //========================================================================================================= + // ptSQRD < (Control.TPCLowPtCut*Control.TPCLowPtCut) + + else if (Control.TPCLowPtStepLimit) { // low pt tracks will be treated differently as their step length is limited by the special low pt steplimiter + + if ( ( PreviousPostStepPosition - step->GetPreStepPoint()->GetPosition() ).mag() > 1.0e-6 * CLHEP::mm ) { + + // This step does not continue the previous path. Deposit the energy and begin a new Pt hit. + + if (CumulativeEnergyDeposit > fThresholdEnergyDeposit) { + //dumpStep( h , step ) ; + DepositLowPtHit(); + } + + else { + // reset the cumulative variables if the hit has not been deposited. + // The previous track has ended and the cumulated energy left at the end + // was not enough to ionize + //G4cout << "reset due to new track , discarding " << CumulativeEnergyDeposit / eV << " eV" << std::endl; + ResetCumulativeVariables(); + } + + } + + else { + //G4cout << "continuing track" << endl; + } + + CumulateLowPtStep(step); + + + // check whether to deposit the hit + if( ( CumulativePathLength > Control.TPCLowPtMaxHitSeparation ) ) { + + // hit is deposited because the step limit is reached and there is enough energy + // to ionize + + if ( CumulativeEnergyDeposit > fThresholdEnergyDeposit) { + //dumpStep( h , step ) ; + DepositLowPtHit(); + } + //else { + //G4cout << "not deposited, energy is " << CumulativeEnergyDeposit/eV << " eV" << std::endl; + //} + } + else { // even if the step lenth has not been reached the hit might + // be deposited because the particle track ends + + if ( step->GetPostStepPoint()->GetKineticEnergy() == 0 ) { + - sensitive->printM2("+++ TrackID:%6d [%s] CREATE TPC hit at pad row crossing :" - " %e MeV Pos:%8.2f %8.2f %8.2f", - step->GetTrack()->GetTrackID(),sensitive->c_name(), dE, - hit->position.X()/CLHEP::mm,hit->position.Y()/CLHEP::mm,hit->position.Z()/CLHEP::mm); - - } - - // zero cumulative variables - dEInPadRow = 0.0; - globalTimeAtPadRingCentre=0.0; - pathLengthInPadRow=0.0; - CrossingOfPadRingCentre[0]=0.0; - CrossingOfPadRingCentre[1]=0.0; - CrossingOfPadRingCentre[2]=0.0; - MomentumAtPadRingCentre[0]=0.0; - MomentumAtPadRingCentre[1]=0.0; - MomentumAtPadRingCentre[2]=0.0; - return true; - } - - - - } - - //========================================================================================================= - // case for which the step remains within geometric volume - - //FIXME: need and another IF case to catch particles which Stop within the padring - - else { // else if(step->GetPostStepPoint()->GetStepStatus() != fGeomBoundary) { - - // the step is not limited by the step length - if( step->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName() != "StepLimiter"){ - - // if(particle not stoped){ - // add the dEdx and return - // G4cout << "Step ended by Physics Process: Add dEdx and carry on" << G4endl; - dEInPadRow += step->GetTotalEnergyDeposit(); - pathLengthInPadRow += step->GetStepLength(); - return true; - //} - //else{ - // write out the hit and clear counters - //} - - - } else { // GetProcessName() == "StepLimiter" - - // G4cout << "step must have been stopped by the step limiter" << G4endl; - // G4cout << "write out hit at " - // << sqrt( position_x*position_x - // +position_y*position_y ) - // << " " << "dEdx = " << step->GetTotalEnergyDeposit() - // << " " << "step length = " << step->GetStepLength() - // << G4endl; - - // write out step limited hit - // these are just space point hits so do not save the dE, which is set to ZERO - // if ( step->GetTotalEnergyDeposit() > fThresholdEnergyDeposit ) - -//xx fSpaceHitCollection-> -//xx insert(new TRKHit(touchPre->GetCopyNumber(), -//xx position_x,position_y,position_z, -//xx momentum_x,momentum_y,momentum_z, -//xx info->GetTheTrackSummary()->GetTrackID(), -//xx step->GetTrack()->GetDefinition()->GetPDGEncoding(), -//xx 0.0, // dE set to ZERO -//xx step->GetTrack()->GetGlobalTime(), -//xx step->GetStepLength())); - - Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(step->GetTrack()->GetTrackID(), - step->GetTrack()->GetDefinition()->GetPDGEncoding(), - 0.0, globalTimeAtPadRingCentre); // dE set to ZERO - - hit->position = 0.5*( PrePosition + PostPosition ); - hit->momentum = thisMomentum ; - hit->length = step->GetStepLength(); - hit->cellID = sensitive->cellID( step ) ; - - fSpaceHitCollection->add(hit); - - - - // add dE and pathlegth and return - dEInPadRow += step->GetTotalEnergyDeposit(); - pathLengthInPadRow += step->GetStepLength(); - return true; - } - } + // only deposit the hit if the energy is high enough + if (CumulativeEnergyDeposit > fThresholdEnergyDeposit) { + //dumpStep( h , step ) ; + DepositLowPtHit(); + } + else { // energy is not enoug to ionize. + // However, the track has ended and the energy is discarded and not added to the next step + //G4cout << "reset due to end of track, discarding " << CumulativeEnergyDeposit/CLHEP::eV << " eV" << std::endl; + ResetCumulativeVariables(); + } + } + } + PreviousPostStepPosition = step->GetPostStepPoint()->GetPosition(); + + return true; + + } + + return true; + + + } + + + /// Method for generating hit(s) using the information of G4Step object for a pad readout + G4bool processPixel(G4Step* step, G4TouchableHistory* ) { + + //do only primary track: + // if(step->GetTrack()->GetTrackID()!=1) return true; + //do all except primary track: + // if(step->GetTrack()->GetTrackID()==1) return true; + + + + //get positions from step + // G4cout<<"get position and momentum from step"<GetPreStepPoint()->GetPosition(); + const G4ThreeVector PostPosition = step->GetPostStepPoint()->GetPosition(); + + // This step does not continue the previous path. Deposit the energy at the previous step. + if ( ( PreviousPostStepPosition - step->GetPreStepPoint()->GetPosition() ).mag() > 1.0e-6 * CLHEP::mm //new hit is far from previous + || ( step->GetTrack()->GetTrackID()!=CurrentTrackID ) ) { //or track id is different + // G4cout<<"found new track "<GetTrack()->GetTrackID()< fThresholdEnergyDeposit) { + DepositMultiplePtHits(previousStep); + } + // reset the cumulative variables if the hit has not been deposited. The previous track has ended and the accumulated energy left at the end was not enough to ionize + ResetCumulativeVariables(false); //reset variables, except energy + } + + //fill histograms, do at this point because last step must be completed, but new step cannot be started yet! + // G4cout<<"Fill histograms"<GetPostStepPoint()->GetStepStatus() == fGeomBoundary) { + if ( CumulativeEnergyDeposit > fThresholdEnergyDeposit) { + DepositMultiplePtHits(step); + ResetCumulativeVariables(false); //reset variables, except energy + } + //In contrast to pad readout, do not reset after crossing a boundary here. + } + + // Maximum hit separation reached + if( ( CumulativePathLength > Control.TPCLowPtMaxHitSeparation ) ) { + // hit is deposited because the step limit is reached and there is enough energy to ionize + if ( CumulativeEnergyDeposit > fThresholdEnergyDeposit) { + DepositMultiplePtHits(step); + } + ResetCumulativeVariables(false); //reset variables, except energy + } + + + //save last postStepPosition + PreviousPostStepPosition = step->GetPostStepPoint()->GetPosition(); + *previousStep = *step; //save previous step + + return true; + } + + + + /// Method for generating hit(s) using the information of G4Step object. + G4bool process(G4Step* step, G4TouchableHistory* th) { + // G4cout<<"processing step in TPCSDAction!"<collection(0) ; + fSpaceHitCollection = sensitive->collection(1) ; + fLowPtHitCollection = sensitive->collection(2) ; + + + //check charge + if (fabs(step->GetTrack()->GetDefinition()->GetPDGCharge()) < 0.01) return true; + + //call pixel or pad readout + if(pixelTPC) return processPixel(step,th); + else return processPad(step,th); + } + + + /// Post-event action callback + void endEvent(const G4Event* /* event */) { + // // We need to add the possibly last added hit to the collection here. + // // otherwise the last hit would be assigned to the next event and the + // // MC truth would be screwed. + // // + // // Alternatively the 'update' method would become rather CPU consuming, + // // beacuse the extract action would have to be recalculated over and over. + // if ( current > 0 ) { + // Geant4HitCollection* coll = sensitive->collection(0); + // extractHit(coll); + } + + void ResetCumulativeVariables(bool resetEnergy=true) + { + CumulativeMeanPosition.set(0.0,0.0,0.0); + CumulativeMeanMomentum.set(0.0,0.0,0.0); + currentMeanPosition.set(0.0,0.0,0.0); + currentMeanMomentum.set(0.0,0.0,0.0); + firstStepPrePosition.set(0.0,0.0,0.0); + firstStepPreMomentum.set(0.0,0.0,0.0); + firstStepTrackID=0; + CumulativeNumSteps = 0; + if(resetEnergy) CumulativeEnergyDeposit = 0; + CumulativePathLength = 0; } - //========================================================================================================= - // ptSQRD < (Control.TPCLowPtCut*Control.TPCLowPtCut) - - else if (Control.TPCLowPtStepLimit) { // low pt tracks will be treated differently as their step length is limited by the special low pt steplimiter - - if ( ( PreviousPostStepPosition - step->GetPreStepPoint()->GetPosition() ).mag() > 1.0e-6 * CLHEP::mm ) { - - // This step does not continue the previous path. Deposit the energy and begin a new Pt hit. - - if (CumulativeEnergyDeposit > fThresholdEnergyDeposit) { - //dumpStep( h , step ) ; - DepositLowPtHit(); - } - - else { - // reset the cumulative variables if the hit has not been deposited. - // The previous track has ended and the cumulated energy left at the end - // was not enough to ionize - //G4cout << "reset due to new track , discarding " << CumulativeEnergyDeposit / eV << " eV" << std::endl; - ResetCumulativeVariables(); - } - - } - - else { - //G4cout << "continuing track" << endl; - } - - CumulateLowPtStep(step); - - - // check whether to deposit the hit - if( ( CumulativePathLength > Control.TPCLowPtMaxHitSeparation ) ) { - - // hit is deposited because the step limit is reached and there is enough energy - // to ionize - - if ( CumulativeEnergyDeposit > fThresholdEnergyDeposit) { - //dumpStep( h , step ) ; - DepositLowPtHit(); - } - //else { - //G4cout << "not deposited, energy is " << CumulativeEnergyDeposit/eV << " eV" << std::endl; - //} - } - else { // even if the step lenth has not been reached the hit might - // be deposited because the particle track ends - - if ( step->GetPostStepPoint()->GetKineticEnergy() == 0 ) { - - - // only deposit the hit if the energy is high enough - if (CumulativeEnergyDeposit > fThresholdEnergyDeposit) { - - //dumpStep( h , step ) ; - DepositLowPtHit(); - } - - else { // energy is not enoug to ionize. - // However, the track has ended and the energy is discarded and not added to the next step - //G4cout << "reset due to end of track, discarding " << CumulativeEnergyDeposit/eV << " eV" << std::endl; + + void DepositLowPtHit() + { + + //xx fLowPtHitCollection-> + //xx insert(new TRKHit(CurrentCopyNumber, + //xx CumulativeMeanPosition[0], CumulativeMeanPosition[1], CumulativeMeanPosition[2], + //xx CumulativeMeanMomentum[0], CumulativeMeanMomentum[1], CumulativeMeanMomentum[2], + //xx CurrentTrackID, + //xx CurrentPDGEncoding, + //xx CumulativeEnergyDeposit, + //xx CurrentGlobalTime, + //xx CumulativePathLength)); + + Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(CurrentTrackID, CurrentPDGEncoding, + CumulativeEnergyDeposit, globalTimeAtPadRingCentre); + + hit->position = CumulativeMeanPosition ; + hit->momentum = CumulativeMeanMomentum ; + hit->length = CumulativePathLength ; + hit->cellID = CurrentCopyNumber ; + + fLowPtHitCollection->add(hit); + + // reset the cumulative variables after positioning the hit ResetCumulativeVariables(); - } - } - } - - PreviousPostStepPosition = step->GetPostStepPoint()->GetPosition(); - - return true; - } - return true; - - - } - - - /// Post-event action callback - void endEvent(const G4Event* /* event */) { - // // We need to add the possibly last added hit to the collection here. - // // otherwise the last hit would be assigned to the next event and the - // // MC truth would be screwed. - // // - // // Alternatively the 'update' method would become rather CPU consuming, - // // beacuse the extract action would have to be recalculated over and over. - // if ( current > 0 ) { - // Geant4HitCollection* coll = sensitive->collection(0); - // extractHit(coll); - } - - void ResetCumulativeVariables() - { - CumulativeMeanPosition.set(0.0,0.0,0.0); - CumulativeMeanMomentum.set(0.0,0.0,0.0); - CumulativeNumSteps = 0; - CumulativeEnergyDeposit = 0; - CumulativePathLength = 0; - } - - void DepositLowPtHit() - { - -//xx fLowPtHitCollection-> -//xx insert(new TRKHit(CurrentCopyNumber, -//xx CumulativeMeanPosition[0], CumulativeMeanPosition[1], CumulativeMeanPosition[2], -//xx CumulativeMeanMomentum[0], CumulativeMeanMomentum[1], CumulativeMeanMomentum[2], -//xx CurrentTrackID, -//xx CurrentPDGEncoding, -//xx CumulativeEnergyDeposit, -//xx CurrentGlobalTime, -//xx CumulativePathLength)); - - Geant4Tracker::Hit* hit = new Geant4Tracker::Hit(CurrentTrackID, CurrentPDGEncoding, - CumulativeEnergyDeposit, globalTimeAtPadRingCentre); - - hit->position = CumulativeMeanPosition ; - hit->momentum = CumulativeMeanMomentum ; - hit->length = CumulativePathLength ; - hit->cellID = CurrentCopyNumber ; - - fLowPtHitCollection->add(hit); - - // reset the cumulative variables after positioning the hit - ResetCumulativeVariables(); - } - - void CumulateLowPtStep(G4Step *step) - { - - const G4ThreeVector meanPosition = (step->GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition()) / 2; - const G4ThreeVector meanMomentum = (step->GetPreStepPoint()->GetMomentum() + step->GetPostStepPoint()->GetMomentum()) / 2; - - ++CumulativeNumSteps; - CumulativeMeanPosition = ( (CumulativeMeanPosition*(CumulativeNumSteps-1)) + meanPosition ) / CumulativeNumSteps; - CumulativeMeanMomentum = ( (CumulativeMeanMomentum*(CumulativeNumSteps-1)) + meanMomentum ) / CumulativeNumSteps; - CumulativeEnergyDeposit += step->GetTotalEnergyDeposit(); - CumulativePathLength += step->GetStepLength(); - CurrentPDGEncoding = step->GetTrack()->GetDefinition()->GetPDGEncoding(); - CurrentTrackID = step->GetTrack()->GetTrackID(); - CurrentGlobalTime = step->GetTrack()->GetGlobalTime(); - CurrentCopyNumber = step->GetPreStepPoint()->GetTouchableHandle()->GetCopyNumber(); - - } - - }; - - - /// Initialization overload for specialization - template <> void Geant4SensitiveAction::initialize() { - eventAction().callAtEnd(&m_userData,&TPCSDData::endEvent); - - declareProperty("TPCLowPtCut", m_userData.Control.TPCLowPtCut ); - declareProperty("TPCLowPtStepLimit", m_userData.Control.TPCLowPtStepLimit ); - declareProperty("TPCLowPtMaxHitSeparation", m_userData.Control.TPCLowPtMaxHitSeparation ); - - m_userData.fThresholdEnergyDeposit = m_sensitive.energyCutoff(); - m_userData.sensitive = this; - - IDDescriptor dsc = m_sensitive.idSpec() ; - m_userData.layerField = dsc.field( "layer" ) ; - - } - - /// Define collections created by this sensitivie action object - template <> void Geant4SensitiveAction::defineCollections() { - m_collectionID = defineCollection(m_sensitive.readout().name()); - m_userData.fSpaceHitCollectionID = defineCollection("TPCSpacePointCollection"); - m_userData.fLowPtHitCollectionID = defineCollection("TPCLowPtCollection"); - } - - /// Method for generating hit(s) using the information of G4Step object. - template <> void Geant4SensitiveAction::clear(G4HCofThisEvent*) { - m_userData.clear(); - } - - /// Method for generating hit(s) using the information of G4Step object. - template <> G4bool - Geant4SensitiveAction::process(G4Step* step, G4TouchableHistory* history) { - return m_userData.process(step, history); - } - - typedef Geant4SensitiveAction TPCSDAction; - - } + //deposit hit for pixel + void DepositPtHit(G4Step* step) { + DepositPtHit(step, CumulativeEnergyDeposit); + } + + int getCellIDFromFormula() { + const double toMM=10; + int system=(currentMeanPosition.z()<0) ? 100 : 36;//FIXME: properly find system id of tpc + int nrow=(currentMeanPosition.perp()-(tpcData->rMinReadout)*toMM)/(tpcData->padHeight*toMM); + nrow=nrow<<7; + return system+nrow; + } + + void WriteHit(G4ThreeVector position, G4ThreeVector momentum, long long cid, double EDep, double pathLength) { + IMPL::SimTrackerHitImpl* hit = new IMPL::SimTrackerHitImpl(); + //use SimTrack + hit->setEDep(EDep); + double cmposition[3] = {position.getX(), position.getY(), position.getZ()}; + hit->setPosition(cmposition); + float cmmomentum[3] = {float(momentum.getX()/CLHEP::GeV), float(momentum.getY()/CLHEP::GeV), float(momentum.getZ()/CLHEP::GeV)}; //why is position double and momentum float?! + hit->setMomentum(cmmomentum); + hit->setPathLength(pathLength); + hit->setCellID0(int(cid)); + hit->setCellID1(int(cid>>32)); + hit->ext()=CurrentTrackID; + //missing:CurrentTrackID,CurrentPDGEncoding, + fHitCollection->add(hit); + + //histogram + // _deltahist.FillHit(position, momentum); + } + + int _nprint=0; + void displayHit(G4Step* step) { + //display this hit + long long cid=sensitive->cellID( step ); + //long long cid=getCellIDFromFormula(); + float cmmomentum[3] = {float(currentMeanMomentum.getX()), float(currentMeanMomentum.getY()), float(currentMeanMomentum.getZ())}; //why is position double and momentum float?! + double cmposition[3] = {currentMeanPosition.getX(), currentMeanPosition.getY(), currentMeanPosition.getZ()}; + const int PRINTEVERYN=100000; + if(!(_nprint++%PRINTEVERYN)) + printf( + "+++ TrackID:%6d [%s] CREATE TPC hit at pixel row crossing :" + " %e MeV Pos:%8.2f %8.2f %8.2f Mom:%8.1f %8.1f %8.1f ID:%i-%i (%i)\n", + step->GetTrack()->GetTrackID(),sensitive->c_name(), CumulativeEnergyDeposit, + cmposition[0]/CLHEP::mm,cmposition[1]/CLHEP::mm,cmposition[2]/CLHEP::mm, + cmmomentum[0]/CLHEP::MeV,cmmomentum[1]/CLHEP::MeV,cmmomentum[2]/CLHEP::MeV, + int(cid), int(cid>>32), getCellIDFromFormula()); + // std::cout<<"tpcData->padheight="<padHeight<<" tpcData->rMinReadout="<rMinReadout<<" r="<cellID( step ); + //long long cid=getCellIDFromFormula(); + // G4DynamicParticle mcparticle=step->GetTrack()->GetDynamicParticle(); + WriteHit(CumulativeMeanPosition, CumulativeMeanMomentum, cid, EDep, CumulativePathLength); + displayHit(step); + } + + + + int DepositFastPtHits(G4Step* step) { + G4StepPoint* postStepPoint = step->GetPostStepPoint(); + std::function hitFunction;//use flat hit function for secundary electrons and triangular for the higher energy primary electrons + if ( step->GetTrack()->GetParentID() ) hitFunction=FlatMultipleHitFunction(0); + else hitFunction=TriangularHitFunction(0.1) ; + InterpolatedHitGenerator hitGenerator( + hitFunction, + AngleInterpolation(firstStepPrePosition, postStepPoint->GetPosition(), firstStepPreMomentum, postStepPoint->GetMomentum()) + // LinearVectorInterpolation(firstStepPrePosition, postStepPoint->GetPosition()) + ); + + int nHits=CumulativeEnergyDeposit/fThresholdEnergyDeposit; + std::vector hitpos=hitGenerator.generateHits(nHits), + hitmom=hitGenerator.generateFromFunction( LinearVectorInterpolation( firstStepPreMomentum, postStepPoint->GetMomentum() ) ); + + for(int i=0; iGetPreStepPoint()->GetPosition()<<" and "<GetPostStepPoint()->GetPosition()< + int nhits=0; + while(CumulativeEnergyDeposit>fThresholdEnergyDeposit) { + DepositPtHit(step, fThresholdEnergyDeposit); + CumulativeEnergyDeposit-=fThresholdEnergyDeposit; + ++nhits; + } + //G4cout<<"would have deposited: "<GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition()) / 2; + const G4ThreeVector meanMomentum = (step->GetPreStepPoint()->GetMomentum() + step->GetPostStepPoint()->GetMomentum()) / 2; + currentMeanPosition=meanPosition; currentMeanMomentum=meanMomentum; + if(!CumulativeNumSteps) { //first step? + firstStepPrePosition=step->GetPreStepPoint()->GetPosition(); + firstStepPreMomentum=step->GetPreStepPoint()->GetMomentum(); + firstStepTrackID= step->GetTrack()->GetTrackID(); + } + ++CumulativeNumSteps; + CumulativeMeanPosition = ( (CumulativeMeanPosition*(CumulativeNumSteps-1)) + meanPosition ) / CumulativeNumSteps; + CumulativeMeanMomentum = ( (CumulativeMeanMomentum*(CumulativeNumSteps-1)) + meanMomentum ) / CumulativeNumSteps; + CumulativeEnergyDeposit += step->GetTotalEnergyDeposit(); + CumulativePathLength += step->GetStepLength(); + CurrentPDGEncoding = step->GetTrack()->GetDefinition()->GetPDGEncoding(); + CurrentTrackID = step->GetTrack()->GetTrackID(); + CurrentGlobalTime = step->GetTrack()->GetGlobalTime(); + CurrentCopyNumber = step->GetPreStepPoint()->GetTouchableHandle()->GetCopyNumber(); + + } + + void CumulatePtStep(G4Step *step) { + CumulateStep(step); + } + + void CumulateLowPtStep(G4Step *step) { + CumulateStep(step); + } + +}; + + +/// Initialization overload for specialization +template <> void Geant4SensitiveAction::initialize() { + eventAction().callAtEnd(&m_userData,&TPCSDData::endEvent); + + declareProperty("TPCLowPtCut", m_userData.Control.TPCLowPtCut ); + declareProperty("TPCLowPtStepLimit", m_userData.Control.TPCLowPtStepLimit ); + declareProperty("TPCLowPtMaxHitSeparation", m_userData.Control.TPCLowPtMaxHitSeparation ); + + m_userData.fThresholdEnergyDeposit = m_sensitive.energyCutoff()/CLHEP::keV; //set manually in geometry builder by kees, I do not know if this is the proper use of energyCutoff() + m_userData.sensitive = this; + + IDDescriptor dsc = m_sensitive.idSpec() ; + m_userData.layerField = dsc.field( "layer" ) ; + + + G4cout << "limits of TPC are: "<< this->sensitiveDetector().limits().isValid() << std::endl; + + G4cout << "TPCSDAction: Threshold for Energy Deposit = " << m_userData.fThresholdEnergyDeposit / CLHEP::eV << " eV" << G4endl; + + const std::string TPCReadoutType= m_detDesc.constantAsString("TPC_readoutType"); + m_userData.pixelTPC=(TPCReadoutType=="pixel"); + const std::string TPCSimulationMode= m_detDesc.constantAsString("TPC_simulationMode"); + m_userData.fastSimulation=(TPCSimulationMode=="fast"); + + if(not m_userData.pixelTPC) m_userData.fThresholdEnergyDeposit=0; + + m_userData.tpcData = m_detector.extension(); + if(!m_userData.tpcData) G4cout<<"tpcData not found"< void Geant4SensitiveAction::defineCollections() { + if(m_userData.pixelTPC) { + G4cout<<"defining m_collectionID with SimTrackerHitImpl"<(m_sensitive.readout().name());//define with SimTrackerHit directly + } else { + m_collectionID = defineCollection(m_sensitive.readout().name());//will later be converted to simtrackerhit + } + m_userData.fSpaceHitCollectionID = defineCollection("TPCSpacePointCollection"); + m_userData.fLowPtHitCollectionID = defineCollection("TPCLowPtCollection"); +} + +/// Method for generating hit(s) using the information of G4Step object. +template <> void Geant4SensitiveAction::clear(G4HCofThisEvent*) { + m_userData.clear(); +} + +/// Method for generating hit(s) using the information of G4Step object. +template <> G4bool +Geant4SensitiveAction::process(G4Step* step, G4TouchableHistory* history) { + return m_userData.process(step, history); +} + +typedef Geant4SensitiveAction TPCSDAction; + +} } From a9f18b75a180e2d81432a1455a0e19c1e669aa15 Mon Sep 17 00:00:00 2001 From: Jan Klamka Date: Wed, 17 Jan 2024 16:05:42 +0100 Subject: [PATCH 2/2] add InterpolatedHitGenerator --- plugins/InterpolatedHitGenerator.h | 197 +++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100755 plugins/InterpolatedHitGenerator.h diff --git a/plugins/InterpolatedHitGenerator.h b/plugins/InterpolatedHitGenerator.h new file mode 100755 index 000000000..e5585841a --- /dev/null +++ b/plugins/InterpolatedHitGenerator.h @@ -0,0 +1,197 @@ +/* + * InterpolatedHitGenerator.h + * + * Created on: Oct 12, 2016 + * Author: cligtenb + */ + +#ifndef INTERPOLATEDHITGENERATOR_H_ +#define INTERPOLATEDHITGENERATOR_H_ + +#include +#include +#include +#include + +//geant4 +#include "G4ThreeVector.hh" //is actually a typedef of CLHEP::ThreeVector +#include "Randomize.hh"//also CLHEP + +//root +#include "TRandom.h" +#include "TMath.h" + + +struct LinearVectorInterpolation { + LinearVectorInterpolation( G4ThreeVector x1, G4ThreeVector x2) : + _x1(x1), + _x2(x2) + {} + G4ThreeVector _x1, _x2; + G4ThreeVector operator()(double t) { //t is parameter between 0 and 1 + return _x1+t*(_x2-_x1);//interpolate linearly + } +}; + +struct QuadraticVectorInterpolation { + //interpolate using momentum at second point + QuadraticVectorInterpolation( G4ThreeVector x1, G4ThreeVector x2, G4ThreeVector momentum) : + _x1(x1), + _x2(x2), + _mom(momentum) + {} + G4ThreeVector _x1, _x2, _mom; + G4ThreeVector operator()(double t) { //t is parameter between 0 and 1 + G4ThreeVector vT=(_x2-_x1).mag()*_mom.unit(); + return _x1+t*(2*(_x2-_x1)-vT)+t*t*(_x1-_x2+vT);//interpolate quadratically + } + +}; + +struct AngleInterpolation { + //interpolate using momentum at angle between momenta + AngleInterpolation( G4ThreeVector x1, G4ThreeVector x2, G4ThreeVector p1, G4ThreeVector p2) : + _x1(x1), + _x2(x2), + _u1(p1.unit()), + _u2(p2.unit()) + {} + G4ThreeVector _x1, _x2, _u1, _u2; + int sign(int x) {return x < 0 ? -1 : 1; } + G4ThreeVector operator()(double t) { //t is parameter between 0 and 1 + G4ThreeVector pos {_x1}; + G4ThreeVector difference {_x2-_x1}; + //start with linear base + G4ThreeVector relativePos=t*difference; + //add dS factor in XY plane: + double dphi=_u1.deltaPhi(_u2); //phi difference between vectors + double L=difference.perp(); //point to point distance in XY plane + double dS=L/2*sin(dphi/2)/2; + //G4cout<<"ds="<