Belle II Software  release-08-00-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 <klm/simulation/SensitiveDetector.h>
11 
12 /* KLM headers. */
13 #include <klm/dataobjects/bklm/BKLMElementNumbers.h>
14 #include <klm/dataobjects/KLMElementNumbers.h>
15 #include <klm/eklm/geometry/GeometryData.h>
16 
17 /* Basf2 headers. */
18 #include <simulation/background/BkgSensitiveDetector.h>
19 
20 /* Geant4 headers. */
21 #include <G4Step.hh>
22 #include <G4VProcess.hh>
23 
24 /* CLHEP headers. */
25 #include <CLHEP/Units/SystemOfUnits.h>
26 #include <CLHEP/Vector/ThreeVector.h>
27 
28 /* ROOT headers. */
29 #include <TRandom3.h>
30 
31 using namespace Belle2::KLM;
32 
34  const G4String& name, KLMSubdetectorNumber subdetector) :
35  SensitiveDetectorBase(name, Const::KLM),
36  m_Subdetector(subdetector),
37  m_FirstCall(true),
38  m_BkgSensitiveDetector(nullptr),
39  m_GeoPar(nullptr)
40 {
41  if (!m_SimPar.isValid())
42  B2FATAL("BKLM simulation parameters are not available.");
43  m_HitTimeMax = m_SimPar->getHitTimeMax();
45  m_KLMSimHits.registerInDataStore();
48 }
49 
50 bool SensitiveDetector::stepEKLM(G4Step* aStep, G4TouchableHistory* history)
51 {
52  /* Once-only initializations (constructor is called too early for these). */
53  if (m_FirstCall) {
54  m_FirstCall = false;
55  const EKLM::GeometryData* geometryData = &EKLM::GeometryData::Instance();
56  if (geometryData->beamBackgroundStudy())
58  }
59 
60  // Record a BeamBackHit for any particle
61  if (m_BkgSensitiveDetector != nullptr) {
62  m_BkgSensitiveDetector->step(aStep, history);
63  }
64 
65  const int stripLevel = 1;
66  int section, layer, sector, plane, strip, stripGlobal;
67  HepGeom::Point3D<double> gpos, lpos;
68  G4TouchableHandle hist = aStep->GetPreStepPoint()->GetTouchableHandle();
69  section = hist->GetVolume(stripLevel + 6)->GetCopyNo();
70  layer = hist->GetVolume(stripLevel + 5)->GetCopyNo();
71  sector = hist->GetVolume(stripLevel + 4)->GetCopyNo();
72  plane = hist->GetVolume(stripLevel + 3)->GetCopyNo();
73  strip = hist->GetVolume(stripLevel)->GetCopyNo();
74  stripGlobal = m_ElementNumbers->stripNumber(
75  section, layer, sector, plane, strip);
76  const G4double eDep = aStep->GetTotalEnergyDeposit();
77  /* Do not record hits without deposited energy. */
78  if (eDep <= 0)
79  return false;
80  const G4Track& track = * aStep->GetTrack();
81  const G4double hitTime = track.GetGlobalTime();
82  if (hitTime > m_HitTimeMax)
83  return false;
84  /* Hit position. */
85  gpos = 0.5 * (aStep->GetPostStepPoint()->GetPosition() +
86  aStep->GetPreStepPoint()->GetPosition());
87  lpos = hist->GetHistory()->GetTopTransform().TransformPoint(gpos);
88  /* Create step hit and store in to DataStore */
89  KLMSimHit* hit = m_KLMSimHits.appendNew();
90  hit->setSubdetector(KLMElementNumbers::c_EKLM);
91  hit->setSection(section);
92  hit->setSector(sector);
93  hit->setLayer(layer);
94  hit->setPlane(plane);
95  hit->setStrip(strip);
96  hit->setLastStrip(strip);
97  // hit->setPropagationTime();
98  hit->setTime(hitTime);
99  hit->setEnergyDeposit(eDep);
100  CLHEP::Hep3Vector trackMomentum = track.GetMomentum();
101  hit->setMomentum(ROOT::Math::PxPyPzEVector(trackMomentum.x(), trackMomentum.y(),
102  trackMomentum.z(), track.GetTotalEnergy()));
103  hit->setTrackID(track.GetTrackID());
104  hit->setParentTrackID(track.GetParentID());
105  hit->setLocalPosition(lpos.x() / CLHEP::mm * Unit::mm,
106  lpos.y() / CLHEP::mm * Unit::mm,
107  lpos.z() / CLHEP::mm * Unit::mm);
108  hit->setPosition(gpos.x() / CLHEP::mm * Unit::mm,
109  gpos.y() / CLHEP::mm * Unit::mm,
110  gpos.z() / CLHEP::mm * Unit::mm);
111  hit->setPDG(track.GetDefinition()->GetPDGEncoding());
112  hit->setVolumeID(stripGlobal);
113  m_MCParticlesToKLMSimHits.add(track.GetTrackID(), hit->getArrayIndex());
114  return true;
115 }
116 
117 G4bool SensitiveDetector::stepBKLM(G4Step* step, G4TouchableHistory* history)
118 {
119  /* Once-only initializations (constructor is called too early for these). */
120  if (m_FirstCall) {
121  m_FirstCall = false;
125  if (!gRandom)
126  B2FATAL("gRandom is not initialized; please set up gRandom first");
127  }
128 
129  // Record a BeamBackHit for any particle
130  if (m_BkgSensitiveDetector != nullptr) {
131  m_BkgSensitiveDetector->step(step, history);
132  }
133 
134  // It is not necessary to detect motion from one volume to another (or track death
135  // in the RPC gas volume). Experimentation shows that most tracks pass through the
136  // RPC gas volume in one step (although, on occasion, a delta ray will take a couple
137  // of short steps entirely within gas). Therefore, save every step in the gas
138  // instead of trying to find entry and exit points and then saving only the midpoint.
139  // Do same for scintillators.
140 
141  double eDep = step->GetTotalEnergyDeposit() / CLHEP::MeV; // GEANT4: in MeV
142  G4StepPoint* preStep = step->GetPreStepPoint();
143  G4StepPoint* postStep = step->GetPostStepPoint();
144  G4Track* track = step->GetTrack();
145 
146  // Record a KLMSimHit for a charged track that deposits some energy.
147  if ((eDep > 0.0) && (postStep->GetCharge() != 0.0)) {
148  const G4VTouchable* hist = preStep->GetTouchable();
149  int depth = hist->GetHistoryDepth();
150  if (depth < m_DepthPlane) {
151  B2WARNING("BKLM SensitiveDetector::step(): "
152  << LogVar("Touchable HistoryDepth", depth)
153  << LogVar("Should be at least", m_DepthPlane));
154  return false;
155  }
156  int plane = hist->GetCopyNumber(depth - m_DepthPlane);
157  int layer = hist->GetCopyNumber(depth - m_DepthLayer);
158  int sector = hist->GetCopyNumber(depth - m_DepthSector);
159  int section = hist->GetCopyNumber(depth - m_DepthSection);
160  double time = 0.5 * (preStep->GetGlobalTime() + postStep->GetGlobalTime()); // GEANT4: in ns
161  if (time > m_HitTimeMax)
162  return false;
163  const CLHEP::Hep3Vector globalPosition = 0.5 * (preStep->GetPosition() + postStep->GetPosition()) / CLHEP::cm; // in cm
164  const bklm::Module* m = m_GeoPar->findModule(section, sector, layer);
165  const CLHEP::Hep3Vector localPosition = m->globalToLocal(globalPosition);
166  int trackID = track->GetTrackID();
167  if (m->hasRPCs()) {
168  const CLHEP::Hep3Vector propagationTimes =
169  m->getPropagationTimes(localPosition);
170  int phiStripLower = -1;
171  int phiStripUpper = -1;
172  int zStripLower = -1;
173  int zStripUpper = -1;
174  convertHitToRPCStrips(localPosition, m, phiStripLower, phiStripUpper, zStripLower, zStripUpper);
175  if (zStripLower > 0) {
176  KLMSimHit* simHit = m_KLMSimHits.appendNew();
178  simHit->setSection(section);
179  simHit->setSector(sector);
180  simHit->setLayer(layer);
182  simHit->setStrip(zStripLower);
183  simHit->setLastStrip(zStripUpper);
184  simHit->setPropagationTime(propagationTimes.z());
185  simHit->setTime(time);
186  simHit->setEnergyDeposit(eDep);
187  simHit->setPosition(globalPosition.x(), globalPosition.y(),
188  globalPosition.z());
189  simHit->setPDG(track->GetDefinition()->GetPDGEncoding());
190  m_MCParticlesToKLMSimHits.add(trackID, simHit->getArrayIndex());
191  }
192  if (phiStripLower > 0) {
193  KLMSimHit* simHit = m_KLMSimHits.appendNew();
195  simHit->setSection(section);
196  simHit->setSector(sector);
197  simHit->setLayer(layer);
199  simHit->setStrip(phiStripLower);
200  simHit->setLastStrip(phiStripUpper);
201  simHit->setPropagationTime(propagationTimes.y());
202  simHit->setTime(time);
203  simHit->setEnergyDeposit(eDep);
204  simHit->setPosition(globalPosition.x(), globalPosition.y(),
205  globalPosition.z());
206  simHit->setPDG(track->GetDefinition()->GetPDGEncoding());
207  m_MCParticlesToKLMSimHits.add(trackID, simHit->getArrayIndex());
208  }
209  } else {
210  int scint = hist->GetCopyNumber(depth - m_DepthScintillator);
211  bool phiPlane = (plane == BKLM_INNER);
212  double propagationTime =
213  m->getPropagationTime(localPosition, scint, phiPlane);
214  KLMSimHit* simHit = m_KLMSimHits.appendNew();
216  simHit->setSection(section);
217  simHit->setSector(sector);
218  simHit->setLayer(layer);
219  if (phiPlane) {
221  } else {
223  }
224  simHit->setStrip(scint);
225  simHit->setLastStrip(scint);
226  simHit->setPropagationTime(propagationTime);
227  simHit->setTime(time);
228  simHit->setEnergyDeposit(eDep);
229  simHit->setPosition(globalPosition.x(), globalPosition.y(),
230  globalPosition.z());
231  simHit->setPDG(track->GetDefinition()->GetPDGEncoding());
232  m_MCParticlesToKLMSimHits.add(trackID, simHit->getArrayIndex());
233  }
234  return true;
235  }
236  return false;
237 }
238 
240  const CLHEP::Hep3Vector& localPosition, const bklm::Module* m,
241  int& phiStripLower, int& phiStripUpper, int& zStripLower, int& zStripUpper)
242 {
243  double phiStripD = m->getPhiStrip(localPosition);
244  int phiStrip = int(phiStripD);
245  int pMin = m->getPhiStripMin();
246  if (phiStrip < pMin)
247  return;
248  int pMax = m->getPhiStripMax();
249  if (phiStrip > pMax)
250  return;
251 
252  double zStripD = m->getZStrip(localPosition);
253  int zStrip = int(zStripD);
254  int zMin = m->getZStripMin();
255  if (zStrip < zMin)
256  return;
257  int zMax = m->getZStripMax();
258  if (zStrip > zMax)
259  return;
260 
261  phiStripLower = phiStrip;
262  phiStripUpper = phiStrip;
263  zStripLower = zStrip;
264  zStripUpper = zStrip;
265  double phiStripDiv = fmod(phiStripD, 1.0) - 0.5; // between -0.5 and +0.5 within central phiStrip
266  double zStripDiv = fmod(zStripD, 1.0) - 0.5; // between -0.5 and +0.5 within central zStrip
267  int n = 0;
268  double rand = gRandom->Uniform();
269  for (n = 1; n < m_SimPar->getMaxMultiplicity(); ++n) {
270  if (m_SimPar->getPhiMultiplicityCDF(phiStripDiv, n) > rand)
271  break;
272  }
273  int nextStrip = (phiStripDiv > 0.0 ? 1 : -1);
274  while (--n > 0) {
275  phiStrip += nextStrip;
276  if ((phiStrip >= pMin) && (phiStrip <= pMax)) {
277  phiStripLower = std::min(phiStrip, phiStripLower);
278  phiStripUpper = std::max(phiStrip, phiStripUpper);
279  }
280  nextStrip = (nextStrip > 0 ? -(1 + nextStrip) : 1 - nextStrip);
281  }
282  rand = gRandom->Uniform();
283  for (n = 1; n < m_SimPar->getMaxMultiplicity(); ++n) {
284  if (m_SimPar->getZMultiplicityCDF(zStripDiv, n) > rand)
285  break;
286  }
287  nextStrip = (zStripDiv > 0.0 ? 1 : -1);
288  while (--n > 0) {
289  zStrip += nextStrip;
290  if ((zStrip >= zMin) && (zStrip <= zMax)) {
291  zStripLower = std::min(zStrip, zStripLower);
292  zStripUpper = std::max(zStrip, zStripUpper);
293  }
294  nextStrip = (nextStrip > 0 ? -(1 + nextStrip) : 1 - nextStrip);
295  }
296  return;
297 }
298 
299 bool SensitiveDetector::step(G4Step* step, G4TouchableHistory* history)
300 {
302  return stepBKLM(step, history);
303  else
304  return stepEKLM(step, history);
305 }
The Class for BeamBackground Sensitive Detector.
This class provides a set of constants for the framework.
Definition: Const.h:34
int stripNumber(int section, int layer, int sector, int plane, int strip) const
Get strip number.
bool beamBackgroundStudy() const
Whether to perform beam-background study.
EKLM geometry data.
Definition: GeometryData.h:38
static const GeometryData & Instance(enum DataSource dataSource=c_Database, const GearDir *gearDir=nullptr)
Instantiation.
Definition: GeometryData.cc:33
KLM simulation hit.
Definition: KLMSimHit.h:31
void setPropagationTime(float propagationTime)
Set signal propagation time.
Definition: KLMSimHit.h:305
void setLastStrip(int lastStrip)
Set last strip number.
Definition: KLMSimHit.h:241
void setEnergyDeposit(float eDep)
Set EnergyDeposit.
Definition: KLMSimHit.h:269
void setSection(int Section)
Set section number.
Definition: KLMSimHit.h:143
void setStrip(int strip)
Set strip number.
Definition: KLMSimHit.h:223
void setTime(float time)
Set hit time.
Definition: KLMSimHit.h:287
void setSubdetector(int subdetector)
Set subdetector number.
Definition: KLMSimHit.h:125
void setPDG(int pdg)
Set the lund code of the (leading) particle.
Definition: KLMSimHit.h:62
void setSector(int sector)
Set sector number.
Definition: KLMSimHit.h:179
void setPlane(int plane)
Set plane number.
Definition: KLMSimHit.h:205
void setLayer(int layer)
Set layer number.
Definition: KLMSimHit.h:161
void setPosition(float x, float y, float z)
Set hit global position.
Definition: KLMSimHit.h:365
bool stepBKLM(G4Step *, G4TouchableHistory *)
Step in BKLM.
DBObjPtr< BKLMSimulationPar > m_SimPar
Simulation parameters (from DB).
bool stepEKLM(G4Step *, G4TouchableHistory *)
Step in EKLM.
SensitiveDetector(const G4String &name, KLMSubdetectorNumber subdetector)
Constructor.
bool m_FirstCall
Flag to enforce once-only initializations in Initialize().
KLMSubdetectorNumber m_Subdetector
Subdetector.
RelationArray m_MCParticlesToKLMSimHits
Relation array between MCPartices and KLMSimHits.
static constexpr int m_DepthSection
Section depth.
static constexpr int m_DepthSector
Sector depth.
bklm::GeometryPar * m_GeoPar
Pointer to GeometryPar singleton.
const EKLMElementNumbers * m_ElementNumbers
EKLM element numbers.
bool step(G4Step *, G4TouchableHistory *) override
Process each step and store KLMSimHits.
double m_HitTimeMax
Maximum permissible hit time based on overflow of LeCroy 1877 TDC.
BkgSensitiveDetector * m_BkgSensitiveDetector
Pointer to a sensitive-detector object used for beam-background steps.
static constexpr int m_DepthScintillator
Scintillator depth.
static constexpr int m_DepthPlane
Plane depth.
void convertHitToRPCStrips(const CLHEP::Hep3Vector &, const bklm::Module *, int &, int &, int &, int &)
Find the ranges of matching RPC strips for BKLM hits.
StoreArray< MCParticle > m_MCParticles
MC particles.
static constexpr int m_DepthLayer
Layer depth.
StoreArray< KLMSimHit > m_KLMSimHits
Simulation hits.
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
static void registerMCParticleRelation(const std::string &name, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
Register an relation involving MCParticles.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
static const double mm
[millimeters]
Definition: Unit.h:70
bool doBeamBackgroundStudy(void) const
Get the beam background study flag.
Definition: GeometryPar.h:51
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
Definition: GeometryPar.cc:721
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Definition: GeometryPar.cc:27
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition: Module.h:76
Class to store variables with their name which were sent to the logging service.
uint16_t KLMSubdetectorNumber
Subdetector number.
bool step(G4Step *aStep, G4TouchableHistory *) override
Process each step and calculate variables defined in PXDSimHit.