Belle II Software  release-08-01-10
SensitiveDetector.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 /* Own header. */
10 #include <ecl/simulation/SensitiveDetector.h>
11 
12 /* ECL headers. */
13 #include <ecl/geometry/ECLGeometryPar.h>
14 
15 /* Basf2 headers. */
16 #include <framework/gearbox/Const.h>
17 #include <framework/gearbox/Unit.h>
18 #include <simulation/background/BkgNeutronWeight.h>
19 
20 using namespace std;
21 using namespace Belle2::ECL;
22 
23 #define UNUSED(x)
24 
25 SensitiveDetector::SensitiveDetector(G4String name, G4double UNUSED(thresholdEnergyDeposit),
26  G4double UNUSED(thresholdKineticEnergy)):
27  Simulation::SensitiveDetectorBase(name, Const::ECL),
28  m_eclSimHitRel(m_mcParticles, m_eclSimHits),
29  m_eclHitRel(m_mcParticles, m_eclHits),
30  m_ECLHadronComponentEmissionFunction()
31  // m_thresholdEnergyDeposit(thresholdEnergyDeposit),
32  // m_thresholdKineticEnergy(thresholdKineticEnergy)
33 {
34  m_trackID = 0;
35  m_WeightedTime = 0;
36  m_energyDeposit = 0;
37  m_hadronenergyDeposit = 0;
38 
39  registerMCParticleRelation(m_eclSimHitRel);
40  registerMCParticleRelation(m_eclHitRel);
41 
42  m_eclSimHits.registerInDataStore();
43  m_eclHits.registerInDataStore();
44 
45  m_mcParticles.registerRelationTo(m_eclSimHits);
46  m_mcParticles.registerRelationTo(m_eclHits);
47 
48  m_HadronEmissionFunction = m_ECLHadronComponentEmissionFunction->getHadronComponentEmissionFunction();
49 }
50 
51 SensitiveDetector::~SensitiveDetector()
52 {
53 }
54 
55 void SensitiveDetector::Initialize(G4HCofThisEvent*)
56 {
57 }
58 
59 //Returns percent of scintillation emission from hadron component for given ionization dEdx value.
60 //See section 5 of S. Longo and J. M. Roney 2018 JINST 13 P03018 for additional details.
62 {
63  if (x < 2) return 0;
64  if (x > 232) return m_HadronEmissionFunction->Eval(232);
65  return m_HadronEmissionFunction->Eval(x);
66 }
67 
68 //Returns total scintillation efficiency, normalized to 1 for photons, for CsI(Tl) given ionization dEdx value.
69 //See section 5 of S. Longo and J. M. Roney 2018 JINST 13 P03018 for additional details.
70 double GetCsITlScintillationEfficiency(double x)
71 {
72  const double p0 = 1.52;
73  const double p1 = 0.00344839;
74  const double p2 = 2.0;
75  double val = 1;
76  if (x > 3.9406) {
77  val = (x * p0) / (x + (p1 * x * x) + p2);
78  }
79  return val;
80 }
81 //-----------------------------------------------------
82 // Method invoked for every step in sensitive detector
83 //-----------------------------------------------------
84 bool SensitiveDetector::step(G4Step* aStep, G4TouchableHistory*)
85 {
86  //
87  double preKineticEnergy = aStep->GetPreStepPoint()->GetKineticEnergy();
88  double postKineticEnergy = aStep->GetPostStepPoint()->GetKineticEnergy();
89  double avgKineticEnergy = 0.5 * (preKineticEnergy + postKineticEnergy);
90  const G4ParticleDefinition* StepParticleDefinition = aStep->GetTrack()->GetParticleDefinition();
91  G4Material* StepMaterial = aStep->GetTrack()->GetMaterial();
92  const double CsIDensity = 4.51; //gcm^-3
93  double ELE_DEDX = m_emCal.ComputeDEDX(avgKineticEnergy, StepParticleDefinition, "eIoni",
94  StepMaterial) / CLHEP::MeV * CLHEP::cm / (CsIDensity);
95  double MU_DEDX = m_emCal.ComputeDEDX(avgKineticEnergy, StepParticleDefinition, "muIoni",
96  StepMaterial) / CLHEP::MeV * CLHEP::cm / (CsIDensity);
97  double HAD_DEDX = m_emCal.ComputeDEDX(avgKineticEnergy, StepParticleDefinition, "hIoni",
98  StepMaterial) / CLHEP::MeV * CLHEP::cm / (CsIDensity);
99  double ION_DEDX = m_emCal.ComputeDEDX(avgKineticEnergy, StepParticleDefinition, "ionIoni",
100  StepMaterial) / CLHEP::MeV * CLHEP::cm / (CsIDensity);
101  G4double DEDX_val = ELE_DEDX + MU_DEDX + HAD_DEDX + ION_DEDX; //Ionization dE/dx for any particle type
102 
103  G4double edep = aStep->GetTotalEnergyDeposit();
104  double LightOutputCorrection = GetCsITlScintillationEfficiency(DEDX_val);
105  edep *= LightOutputCorrection;
106  const G4StepPoint& s0 = *aStep->GetPreStepPoint();
107  const G4StepPoint& s1 = *aStep->GetPostStepPoint();
108  const G4Track& track = *aStep->GetTrack();
109 
110  if (m_trackID != track.GetTrackID()) { //TrackID changed, store track informations
111  m_trackID = track.GetTrackID();
112  m_momentum = s0.GetMomentum(); // Get momentum
113  //Reset track parameters
114  m_energyDeposit = 0;
115  m_WeightedTime = 0;
116  m_WeightedPos.set(0, 0, 0);
118  }
119  //Update energy deposit
120  G4double hedep = 0.5 * edep; // half of energy deposition -- for averaging purpose
121  m_energyDeposit += edep;
122  m_WeightedTime += (s0.GetGlobalTime() + s1.GetGlobalTime()) * hedep;
123  m_WeightedPos += (s0.GetPosition() + s1.GetPosition()) * hedep;
124  //
125  //Calculate hadronic scintillation component intensity from dEdx
126  m_hadronenergyDeposit += (edep / CLHEP::GeV) * GetHadronIntensityFromDEDX(DEDX_val);
127  //
128  //Save Hit if track leaves volume or is killed
129  if (track.GetNextVolume() != track.GetVolume() || track.GetTrackStatus() >= fStopAndKill) {
130  if (m_energyDeposit > 0.0) {
132  G4int cellID = eclp->TouchableToCellID(s0.GetTouchable());
133  G4double dTotalEnergy = 1 / m_energyDeposit;
134  m_WeightedTime *= dTotalEnergy;
135  m_WeightedPos *= dTotalEnergy;
136  int pdgCode = track.GetDefinition()->GetPDGEncoding();
138  }
139  //Reset TrackID
140  m_trackID = 0;
141  }
142  return true;
143 }
144 
145 void SensitiveDetector::EndOfEvent(G4HCofThisEvent*)
146 {
147  struct hit_t { double e, t; };
148  map<int, hit_t> a;
149 
150  struct thit_t { int tid, hid; };
151  vector<thit_t> tr;
152 
154 
155  for (const ECLSimHit& t : m_eclSimHits) {
156  double tof = t.getFlightTime();
157  if (tof >= 8000.0 || tof < -8000.0) continue;
158  int TimeIndex = (tof + 8000.0) * (1. / 100);
159  int cellId = t.getCellId() - 1;
160  int key = cellId * 160 + TimeIndex;
161  double edep = t.getEnergyDep();
162  double tsen = tof + eclp->time2sensor(cellId, t.getPosition()); // flight time to diode sensor
163 
164  hit_t& h = a[key];
165 
166  int trkid = t.getTrackId();
167  tr.push_back({trkid, key});
168 
169  double old_edep = h.e, old_tsen = h.t;
170  double new_edep = old_edep + edep;
171 
172  h.e = new_edep;
173  h.t = (old_edep * old_tsen + edep * tsen) / new_edep;
174  }
175 
176  int hitNum = m_eclHits.getEntries();
177  // assert(hitNum == 0);
178  for (pair<int, hit_t> t : a) {
179  int key = t.first, cellId = key / 160;
180  for (const thit_t& s : tr)
181  if (s.hid == key) m_eclHitRel.add(s.tid, hitNum);
182  const hit_t& h = t.second;
183  m_eclHits.appendNew(cellId + 1, h.e, h.t); hitNum++;
184  }
185 }
186 
187 int SensitiveDetector::saveSimHit(G4int cellId, G4int trackID, G4int pid, G4double tof, G4double edep,
188  const G4ThreeVector& mom, const G4ThreeVector& pos, double Hadronedep)
189 {
190  int simhitNumber = m_eclSimHits.getEntries();
191  m_eclSimHitRel.add(trackID, simhitNumber);
192  tof *= 1 / CLHEP::ns;
193  edep *= 1 / CLHEP::GeV;
194  m_eclSimHits.appendNew(cellId + 1, trackID, pid, tof, edep, mom * (1 / CLHEP::GeV), pos * (1 / CLHEP::cm), Hadronedep);
195  return simhitNumber;
196 }
197 
198 SensitiveDiode::SensitiveDiode(const G4String& name):
199  Simulation::SensitiveDetectorBase(name, Const::ECL)
200 {
201  m_eclHits.registerInDataStore("ECLDiodeHits");
203  m_trackID = -1;
204  m_tsum = 0;
205  m_esum = 0;
206 }
207 
209 {
210 }
211 
212 void SensitiveDiode::Initialize(G4HCofThisEvent*)
213 {
214  m_hits.clear();
215  m_cells.clear();
216 }
217 
218 //-----------------------------------------------------
219 // Method invoked for every step in sensitive detector
220 //-----------------------------------------------------
221 bool SensitiveDiode::step(G4Step* aStep, G4TouchableHistory*)
222 {
223  const G4StepPoint& s0 = *aStep->GetPreStepPoint();
224  const G4StepPoint& s1 = *aStep->GetPostStepPoint();
225  const G4Track& track = *aStep->GetTrack();
226 
227  if (m_trackID != track.GetTrackID()) { //TrackID changed, store track informations
228  m_trackID = track.GetTrackID();
229  //Reset track parameters
230  m_esum = 0;
231  m_tsum = 0;
232  }
233  //Update energy deposit
234  G4double edep = aStep->GetTotalEnergyDeposit();
235  m_esum += edep;
236  m_tsum += (s0.GetGlobalTime() + s1.GetGlobalTime()) * edep;
237  //Save Hit if track leaves volume or is killed
238  if (track.GetNextVolume() != track.GetVolume() ||
239  track.GetTrackStatus() >= fStopAndKill) {
240  if (m_esum > 0.0) {
241  int cellID = m_eclp->TouchableDiodeToCellID(s0.GetTouchable());
242  m_tsum /= 2 * m_esum; // average
243  m_hits.push_back({cellID, m_esum, m_tsum});
244  auto it = find(m_cells.begin(), m_cells.end(), cellID);
245  if (it == m_cells.end())m_cells.push_back(cellID);
246 #if 0
247  const G4ThreeVector& p = s0.GetPosition();
248  G4ThreeVector cp = 10 * m_eclp->getCrystalPos(cellID);
249  G4ThreeVector cv = m_eclp->getCrystalVec(cellID);
250  double dz = (p - cp) * cv;
251  double rho = ((p - cp) - dz * cv).perp();
252  cout << "diff " << cellID << " " << dz << " " << rho << endl;
253  if (abs(dz - 150) > 1) {
254  const G4VTouchable* touch = s0.GetTouchable();
255  const G4NavigationHistory* h = touch->GetHistory();
256  int hd = h->GetDepth();
257  int i1 = h->GetReplicaNo(hd - 1); // index of each volume is set at physical volume creation
258  int i2 = h->GetReplicaNo(hd - 2); // go up in volume hierarchy
259  const G4String& vname = touch->GetVolume()->GetName();
260  cout << vname << " " << hd << " " << i1 << " " << i2 << endl;
261  for (int i = 0; i <= hd; i++) {
262  G4VPhysicalVolume* v = h->GetVolume(i);
263  cout << v->GetName() << endl;
264  }
265  }
266 #endif
267  }
268  //Reset TrackID
269  m_trackID = 0;
270  }
271  return true;
272 }
273 
274 void SensitiveDiode::EndOfEvent(G4HCofThisEvent*)
275 {
276  struct dep_t {double e, t;};
277  vector<dep_t> v;
278  for (int cellId : m_cells) {
279  v.clear();
280  for (const hit_t& h : m_hits) {
281  if (cellId == h.cellId) v.push_back({h.e, h.t});
282  }
283 
284  double esum = 0, tsum = 0;
285  for (const dep_t& t : v) {
286  esum += t.e;
287  tsum += t.t * t.e;
288  }
289  tsum /= esum;
290 
291  tsum *= 1 / CLHEP::ns;
292  esum *= 1 / CLHEP::GeV;
293  m_eclHits.appendNew(cellId + 1, esum, tsum);
294 
295 
296  // cout<<"DD: "<<cellId<<" "<<esum<<" "<<tsum<<" +- "<<sqrt(tsum2)<<endl;
297 
298  // sort(v.begin(),v.end(),[](const dep_t &a, const dep_t &b){return a.t<b.t;});
299  // cout<<"DD: "<<cellId<<" ";
300  // for(const dep_t &t: v)cout<<t.e<<" MeV "<<t.t<<" nsec, ";
301  // cout<<"\n";
302 
303  }
304 }
305 
307  Simulation::SensitiveDetectorBase(name, Const::invalidDetector),
308  m_eclBeamBkgHitRel(m_mcParticles, m_eclBeamBkgHits)
309 {
311  m_eclBeamBkgHits.registerInDataStore();
313 
315  m_energyDeposit = 0;
316  m_startEnergy = 0;
317  m_startTime = 0;
318  m_trackLength = 0;
319  m_trackID = -1;
320 }
321 
322 //-----------------------------------------------------
323 // Method invoked for every step in sensitive detector
324 //-----------------------------------------------------
325 bool BkgSensitiveDiode::step(G4Step* aStep, G4TouchableHistory*)
326 {
327  const G4StepPoint& s0 = *aStep->GetPreStepPoint();
328  const G4Track& track = *aStep->GetTrack();
329 
330  if (m_trackID != track.GetTrackID()) { //TrackID changed, store track informations
331  m_trackID = track.GetTrackID();
332  //Get world position
333  const G4ThreeVector& worldPosition = s0.GetPosition();
334  const double mm2cm = Unit::mm / Unit::cm;
335  m_startPos.SetXYZ(worldPosition.x() * mm2cm, worldPosition.y() * mm2cm, worldPosition.z() * mm2cm);
336  //Get momentum
337  const G4ThreeVector& momentum = s0.GetMomentum() ;
338  m_startMom.SetXYZ(momentum.x() * Unit::MeV, momentum.y() * Unit::MeV, momentum.z() * Unit::MeV);
339  //Get time
340  m_startTime = s0.GetGlobalTime();
341  //Get energy
342  m_startEnergy = s0.GetKineticEnergy() * Unit::MeV;
343  //Reset energy deposit;
344  m_energyDeposit = 0;
345  //Reset track lenght;
346  m_trackLength = 0;
347  }
348  //Update energy deposit
349  m_energyDeposit += aStep->GetTotalEnergyDeposit() * Unit::MeV;
350  m_trackLength += aStep->GetStepLength() * Unit::mm;
351  //Save Hit if track leaves volume or is killed
352  if (track.GetNextVolume() != track.GetVolume() ||
353  track.GetTrackStatus() >= fStopAndKill) {
354  int pdgCode = track.GetDefinition()->GetPDGEncoding();
355  double endEnergy = track.GetKineticEnergy() * Unit::MeV;
356  double neutWeight = 0;
357  if (pdgCode == Const::neutron.getPDGCode()) {
359  neutWeight = wt.getWeight(m_startEnergy / Unit::MeV);
360  }
361 
362  int bkgHitNumber = m_eclBeamBkgHits.getEntries();
363  m_eclBeamBkgHitRel.add(m_trackID, bkgHitNumber);
364 
365  int cellID = m_eclp->TouchableDiodeToCellID(s0.GetTouchable());
366  m_eclBeamBkgHits.appendNew(6, cellID, pdgCode, m_trackID, m_startPos, m_startMom, m_startTime, endEnergy, m_startEnergy,
367  m_energyDeposit, m_trackLength, neutWeight);
368 
369  //Reset TrackID
370  m_trackID = 0;
371  }
372  return true;
373 }
The class to get the weighting factor for a 1-MeV-equivalent neutron flux on silicon.
This class provides a set of constants for the framework.
Definition: Const.h:34
static const ParticleType neutron
neutron particle
Definition: Const.h:666
ClassECLSimHit - Geant4 simulated hit for the ECL.
Definition: ECLSimHit.h:29
bool step(G4Step *aStep, G4TouchableHistory *history) override
Process each step and calculate variables defined in ECLHit.
double m_energyDeposit
energy deposited in volume
ROOT::Math::XYZVector m_startPos
particle position at the entrance in volume
BkgSensitiveDiode(const G4String &)
Constructor.
double m_startEnergy
particle energy at the entrance in volume
double m_trackLength
length of the track in the volume
ECLGeometryPar * m_eclp
pointer to ECLGeometryPar
StoreArray< MCParticle > m_mcParticles
MCParticle array.
RelationArray m_eclBeamBkgHitRel
MCParticle to BeamBackHit relation array.
ROOT::Math::XYZVector m_startMom
particle momentum at the entrance in volume
StoreArray< BeamBackHit > m_eclBeamBkgHits
BeamBackHit array.
The Class for ECL Geometry Parameters.
G4ThreeVector getCrystalVec(int cid)
The direction of crystal.
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
int TouchableToCellID(const G4VTouchable *)
The same as above but without sanity checks.
G4ThreeVector getCrystalPos(int cid)
The Position of crystal.
double time2sensor(int cid, const G4ThreeVector &hit_pos)
function to calculate flight time to diode sensor
int TouchableDiodeToCellID(const G4VTouchable *)
Mapping from G4VTouchable copyNumbers to Crystal CellID.
bool step(G4Step *aStep, G4TouchableHistory *history) override
Process each step and calculate variables defined in ECLHit.
double m_energyDeposit
total energy deposited in a volume by a track
double GetHadronIntensityFromDEDX(double)
Evaluates hadron scintillation component emission function.
double m_hadronenergyDeposit
energy deposited resulting in hadronic scint component
TGraph * m_HadronEmissionFunction
Graph for hadron scintillation component emission function.
StoreArray< ECLSimHit > m_eclSimHits
ECLSimHit array.
G4ThreeVector m_momentum
initial momentum of track before energy deposition inside sensitive volume
G4EmCalculator m_emCal
Used to get dE/dx for pulse shape simulations.
void EndOfEvent(G4HCofThisEvent *eventHC) override
Do what you want to do at the end of each event.
void Initialize(G4HCofThisEvent *HCTE) override
Register ECL hits collection into G4HCofThisEvent.
double m_WeightedTime
average track time weighted by energy deposition
RelationArray m_eclHitRel
MCParticle to ECLHit relation array.
StoreArray< ECLHit > m_eclHits
ECLHit array.
int saveSimHit(G4int, G4int, G4int, G4double, G4double, const G4ThreeVector &, const G4ThreeVector &, double)
Create ECLSimHit and ECLHit and relations from MCParticle and put them in datastore.
G4ThreeVector m_WeightedPos
average track position weighted by energy deposition
RelationArray m_eclSimHitRel
MCParticle to ECLSimHit relation array.
bool step(G4Step *aStep, G4TouchableHistory *history) override
Process each step and calculate variables defined in ECLHit.
std::vector< hit_t > m_hits
array of hits
int m_trackID
current track id
double m_tsum
average track time weighted by energy deposition
std::vector< int > m_cells
array of hitted crystals
SensitiveDiode(const G4String &)
Constructor.
double m_esum
total energy deposited in a volume by a track
void EndOfEvent(G4HCofThisEvent *eventHC) override
Do what you want to do at the end of each event.
void Initialize(G4HCofThisEvent *HCTE) override
Register ECL hits collection into G4HCofThisEvent.
ECLGeometryPar * m_eclp
pointer to ECLGeometryPar
StoreArray< ECLHit > m_eclHits
ECLHit array.
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
static void registerMCParticleRelation(const std::string &name, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
Register an relation involving MCParticles.
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
static const double mm
[millimeters]
Definition: Unit.h:70
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
static const double cm
Standard units with the value = 1.
Definition: Unit.h:47
double getWeight(double ke)
Get weighting factor to convert a neutron to its 1-MeV equivalent.
static BkgNeutronWeight & getInstance()
Return a reference to the singleton BkgNeutronWeight instance.