Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include "TimeProjectionChamberSensitiveDetector.h"
#include "G4Step.hh"
#include "G4VProcess.hh"
//#include "G4SteppingManager.hh"
#include "G4SDManager.hh"
//#include "UserTrackInformation.hh"
#include "DD4hep/DD4hepUnits.h"
TimeProjectionChamberSensitiveDetector::TimeProjectionChamberSensitiveDetector(const std::string& name,
dd4hep::Detector& description)
: DDG4SensitiveDetector(name, description){
G4String CollName1=name+"Collection";
collectionName.insert(CollName1);
G4String CollName2=name+"SpacePointCollection";
collectionName.insert(CollName2);
G4String CollName3=name+"LowPtCollection";
collectionName.insert(CollName3);
}
void TimeProjectionChamberSensitiveDetector::Initialize(G4HCofThisEvent* HCE){
m_hc = new HitCollection(GetName(), collectionName[0]);
int HCID = G4SDManager::GetSDMpointer()->GetCollectionID(m_hc);
HCE->AddHitsCollection( HCID, m_hc );
m_spaceHC = new HitCollection(GetName(), collectionName[1]);
int HCIDSpace = G4SDManager::GetSDMpointer()->GetCollectionID(m_spaceHC);
HCE->AddHitsCollection( HCIDSpace, m_spaceHC );
m_lowPtHC = new HitCollection(GetName(), collectionName[2]);
int HCIDLowPt = G4SDManager::GetSDMpointer()->GetCollectionID(m_lowPtHC);
HCE->AddHitsCollection( HCIDLowPt, m_lowPtHC );
CumulativeNumSteps=0;
dEInPadRow = 0.0;
CumulativeEnergyDeposit = 0.0;
globalTimeAtPadRingCentre=0.0;
pathLengthInPadRow=0.0;
CumulativePathLength=0.0;
CrossingOfPadRingCentre.SetXYZ(0,0,0);// = dd4hep::Position(0,0,0);
MomentumAtPadRingCentre.SetXYZ(0,0,0);// = dd4hep::sim::Momentum(0,0,0);
CumulativeMeanPosition.SetXYZ(0,0,0);// = dd4hep::Position(0,0,0);
CumulativeMeanMomentum.SetXYZ(0,0,0);// = dd4hep::sim::Momentum(0,0,0);
PreviousPostStepPosition.SetXYZ(0,0,0);// = dd4hep::Position(0,0,0);
CurrentPDGEncoding=0;
CurrentTrackID=-1;
CurrentGlobalTime=0.0;
CurrentCopyNumber=0;
/*
if( m_lowPtStepLimit ) {
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPtStepLimit ON" << std::endl;
}
else {
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPtStepLimit OFF" << std::endl;
}
if( m_writeMCParticleForLowPtHits ) {
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPtStoreMCPForHits ON" << std::endl;
}
else {
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPtStoreMCPForHits OFF" << std::endl;
}
std::cout << "TimeProjectionChamberSensitiveDetector: Threshold for Energy Deposit = " << m_thresholdEnergyDeposit / CLHEP::eV << " eV" << G4endl;
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPtCut = " << m_lowPtCut / CLHEP::MeV << " MeV "<< G4endl;
std::cout << "TimeProjectionChamberSensitiveDetector: TPCLowPt Max hit separation "<< m_lowPtMaxHitSeparation / CLHEP::mm << " mm" << G4endl;
*/
}
G4bool TimeProjectionChamberSensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*){
// 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
G4TouchableHandle touchPost = step->GetPostStepPoint()->GetTouchableHandle();
G4TouchableHandle touchPre = step->GetPreStepPoint()->GetTouchableHandle();
dd4hep::sim::Geant4StepHandler h(step);
if (fabs(h.trackDef()->GetPDGCharge()) < 0.01) return true;
const dd4hep::Position PrePosition = h.prePos();
const dd4hep::Position PostPosition = h.postPos();
const dd4hep::sim::Momentum Momentum = h.postMom(); //use post step momentum, Mokka history
float ptSQRD = Momentum.X()*Momentum.X()+Momentum.Y()*Momentum.Y();
if( ptSQRD >= (m_lowPtCut*m_lowPtCut) ){
// Step finishes at a geometric boundry
if(step->GetPostStepPoint()->GetStepStatus() == fGeomBoundary){
//if(h.postStepStatus() == "GeomBoundary"){
// step within the same pair of upper and lower pad ring halves
if(int(touchPre->GetCopyNumber()/2)==int(touchPost->GetCopyNumber()/2)) {
//this step must have ended on the boundry between these two pad ring halfs
//record the tracks coordinates at this position
//and return
CrossingOfPadRingCentre.SetXYZ(PostPosition.X(),PostPosition.Y(),PostPosition.Z());
MomentumAtPadRingCentre = Momentum;
dEInPadRow += h.deposit();
globalTimeAtPadRingCentre = h.trkTime();
pathLengthInPadRow += h.stepLength();
// 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.X()==0.0 && CrossingOfPadRingCentre.Y()==0.0 && CrossingOfPadRingCentre.Z()==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
//make sure particle is added to MC list
//and return
// 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;
double dE = h.deposit()+dEInPadRow;
if ( dE > m_thresholdEnergyDeposit || m_trackingPhysicsListELossOn == false ) {
// needed for delta electrons: all particles causing hits have to be saved
// TODO: set track flag to save
dd4hep::sim::Geant4TrackerHit* hit = new dd4hep::sim::Geant4TrackerHit(h.trkID(),h.trkPdgID(),dE,globalTimeAtPadRingCentre);
hit->cellID = touchPre->GetCopyNumber()/2+1;//getCellID(step);
hit->energyDeposit = dE;
hit->position = CrossingOfPadRingCentre;
hit->momentum = MomentumAtPadRingCentre;
hit->length = h.stepLength()+pathLengthInPadRow;
m_hc->insert(hit);
}
// zero cumulative variables
dEInPadRow = 0.0;
globalTimeAtPadRingCentre = 0.0;
pathLengthInPadRow = 0.0;
CrossingOfPadRingCentre.SetXYZ(0.,0.,0.);
MomentumAtPadRingCentre.SetXYZ(0.,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 if(step->GetPostStepPoint()->GetStepStatus() != fGeomBoundary){
//else if(h.postStepStatus() != "GeomBoundary") {
//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 += h.deposit();
pathLengthInPadRow += h.stepLength();
return true;
//}
//else{
// write out the hit and clear counters
//}
}
else {
//double position_x = PostPosition[0];
//double position_y = PostPosition[1];
//double position_z = PostPosition[2];
const dd4hep::sim::Momentum PreMomentum = h.preMom();
const dd4hep::sim::Momentum PostMomentum = h.postMom();
//double momentum_x = PostMomentum[0];
//double momentum_y = PostMomentum[1];
//double momentum_z = PostMomentum[2];
// 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 )
// needed for delta electrons: all particles causing hits have to be saved in the LCIO file
// TODO: set track flag to be saved
//UserTrackInformation *info = (UserTrackInformation*)(step->GetTrack()->GetUserInformation());
//if (info) info->GetTheTrackSummary()->SetToBeSaved();
dd4hep::sim::Geant4TrackerHit* hit = new dd4hep::sim::Geant4TrackerHit(h.trkID(),h.trkPdgID(),0.0,h.trkTime());
hit->cellID = touchPre->GetCopyNumber()/2+1;//getCellID(step);
hit->energyDeposit = 0.0;
hit->position = PostPosition;
hit->momentum = PostMomentum;
hit->length = h.stepLength();
m_spaceHC->insert(hit);
// add dE and pathlegth and return
dEInPadRow += h.deposit();
pathLengthInPadRow += h.stepLength();
return true;
}
}
}
else if(m_lowPtStepLimit) { // low pt tracks will be treated differently as their step length is limited by the special low pt steplimiter
if ( ( PreviousPostStepPosition - PrePosition ).R() > 1.0e-6 * dd4hep::mm ) {
// This step does not continue the previous path. Deposit the energy and begin a new Pt hit.
if (CumulativeEnergyDeposit > m_thresholdEnergyDeposit) {
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(h);
// check whether to deposit the hit
if( ( CumulativePathLength > m_lowPtMaxHitSeparation ) ) {
// hit is deposited because the step limit is reached and there is enough energy
// to ionize
if ( CumulativeEnergyDeposit > m_thresholdEnergyDeposit) {
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 ( h.post->GetKineticEnergy() == 0 ) {
// only deposit the hit if the energy is high enough
if (CumulativeEnergyDeposit > m_thresholdEnergyDeposit) {
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;
ResetCumulativeVariables();
}
}
}
PreviousPostStepPosition = h.postPos();
return true;
}
return true;
}
void TimeProjectionChamberSensitiveDetector::EndOfEvent(G4HCofThisEvent* HCE){
// There might be one low Pt hit which has not been added to the collection.
if (CumulativeEnergyDeposit > m_thresholdEnergyDeposit) {
DepositLowPtHit();
}
}
void TimeProjectionChamberSensitiveDetector::DepositLowPtHit(){
dd4hep::sim::Geant4TrackerHit* hit = new dd4hep::sim::Geant4TrackerHit(CurrentTrackID,CurrentPDGEncoding,CumulativeEnergyDeposit,CurrentGlobalTime);
hit->cellID = CurrentCopyNumber;
hit->energyDeposit = CumulativeEnergyDeposit; // FIXME: also use the dedx
hit->position = CumulativeMeanPosition;
hit->momentum = CumulativeMeanMomentum;
hit->length = CumulativePathLength;
m_lowPtHC->insert(hit);
// reset the cumulative variables after positioning the hit
ResetCumulativeVariables();
}
void TimeProjectionChamberSensitiveDetector::ResetCumulativeVariables(){
CumulativeMeanPosition.SetXYZ(0.,0.,0.);// = dd4hep::Position(0.0,0.0,0.0);
CumulativeMeanMomentum.SetXYZ(0.,0.,0.);// = dd4hep::sim::Momentum(0.0,0.0,0.0);
CumulativeNumSteps = 0;
CumulativeEnergyDeposit = 0;
CumulativePathLength = 0;
}
void TimeProjectionChamberSensitiveDetector::CumulateLowPtStep(dd4hep::sim::Geant4StepHandler& h){
//dd4hep::Position prePos = h.prePos();
//dd4hep::Position postPos = h.postPos();
//dd4hep::Position direction = postPos - prePos;
dd4hep::Position meanPosition = h.avgPosition();//0.5*(prePos+postPos);
//double hit_len = direction.R();
dd4hep::Position meanMomentum = 0.5*(h.preMom() + h.postMom());
++CumulativeNumSteps;
CumulativeMeanPosition = ( (CumulativeMeanPosition*(CumulativeNumSteps-1)) + meanPosition ) / CumulativeNumSteps;
CumulativeMeanMomentum = ( (CumulativeMeanMomentum*(CumulativeNumSteps-1)) + meanMomentum ) / CumulativeNumSteps;
CumulativeEnergyDeposit += h.deposit();
CumulativePathLength += h.stepLength();
CurrentPDGEncoding = h.trkPdgID();
CurrentTrackID = h.trkID();
CurrentGlobalTime = h.trkTime();
CurrentCopyNumber = h.preTouchable()->GetCopyNumber()/2+1;//getCellID( h.step );
// needed for delta electrons: all particles causing hits have to be saved in the LCIO file
if ( CumulativeEnergyDeposit > m_thresholdEnergyDeposit ) {
// This low Pt hit will eventually be saved, so set the flag to store the particle
// writing the MC Particles can be turned on or off for the lowPt particles
if(m_writeMCParticleForLowPtHits){
// TODO: here set write flag for this track
}
}
}