Belle II Software  release-06-00-14
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/bklm/simulation/SensitiveDetector.h>
11 
12 /* KLM headers. */
13 #include <klm/bklm/geometry/GeometryPar.h>
14 #include <klm/bklm/geometry/Module.h>
15 #include <klm/dataobjects/bklm/BKLMElementNumbers.h>
16 #include <klm/dataobjects/bklm/BKLMStatus.h>
17 
18 /* Belle 2 headers. */
19 #include <simulation/background/BkgSensitiveDetector.h>
20 
21 /* Geant4 headers. */
22 #include <G4Step.hh>
23 #include <G4VProcess.hh>
24 
25 /* CLHEP headers. */
26 #include <CLHEP/Units/SystemOfUnits.h>
27 #include <CLHEP/Vector/ThreeVector.h>
28 
29 /* ROOT headers. */
30 #include <TRandom3.h>
31 
32 using namespace std;
33 using namespace Belle2::bklm;
34 
35 SensitiveDetector::SensitiveDetector(const G4String& name) :
36  SensitiveDetectorBase(name, Const::KLM),
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_SimHits.registerInDataStore();
46  m_SimHitPositions.registerInDataStore();
49  m_SimHitPositions.registerRelationTo(m_SimHits);
50 }
51 
52 //-----------------------------------------------------
53 // Method invoked for every step in sensitive detector
54 //-----------------------------------------------------
55 G4bool SensitiveDetector::step(G4Step* step, G4TouchableHistory* history)
56 {
57  // Once-only initializations (constructor is called too early for these)
58  if (m_FirstCall) {
59  m_FirstCall = false;
63  if (!m_SimPar.isValid())
64  B2FATAL("BKLM simulation parameters are not available.");
65  m_HitTimeMax = m_SimPar->getHitTimeMax();
66  if (!gRandom)
67  B2FATAL("gRandom is not initialized; please set up gRandom first");
68  }
69 
70  // Record a BeamBackHit for any particle
71  if (m_BkgSensitiveDetector != nullptr) {
72  m_BkgSensitiveDetector->step(step, history);
73  }
74 
75  // It is not necessary to detect motion from one volume to another (or track death
76  // in the RPC gas volume). Experimentation shows that most tracks pass through the
77  // RPC gas volume in one step (although, on occasion, a delta ray will take a couple
78  // of short steps entirely within gas). Therefore, save every step in the gas
79  // instead of trying to find entry and exit points and then saving only the midpoint.
80  // Do same for scintillators.
81 
82  double eDep = step->GetTotalEnergyDeposit() / CLHEP::MeV; // GEANT4: in MeV
83  G4StepPoint* preStep = step->GetPreStepPoint();
84  G4StepPoint* postStep = step->GetPostStepPoint();
85  G4Track* track = step->GetTrack();
86 
87  // Record a BKLMSimHit for a charged track that deposits some energy.
88  if ((eDep > 0.0) && (postStep->GetCharge() != 0.0)) {
89  const G4VTouchable* hist = preStep->GetTouchable();
90  int depth = hist->GetHistoryDepth();
91  if (depth < m_DepthPlane) {
92  B2WARNING("BKLM SensitiveDetector::step(): "
93  << LogVar("Touchable HistoryDepth", depth)
94  << LogVar("Should be at least", m_DepthPlane));
95  return false;
96  }
97  int plane = hist->GetCopyNumber(depth - m_DepthPlane);
98  int layer = hist->GetCopyNumber(depth - m_DepthLayer);
99  int sector = hist->GetCopyNumber(depth - m_DepthSector);
100  int section = hist->GetCopyNumber(depth - m_DepthSection);
101  int moduleID =
102  int(BKLMElementNumbers::moduleNumber(section, sector, layer));
103  double time = 0.5 * (preStep->GetGlobalTime() + postStep->GetGlobalTime()); // GEANT4: in ns
104  if (time > m_HitTimeMax)
105  return false;
106  const CLHEP::Hep3Vector globalPosition = 0.5 * (preStep->GetPosition() + postStep->GetPosition()) / CLHEP::cm; // in cm
107  const Module* m = m_GeoPar->findModule(section, sector, layer);
108  const CLHEP::Hep3Vector localPosition = m->globalToLocal(globalPosition);
109  if (postStep->GetProcessDefinedStep() != 0) {
110  if (postStep->GetProcessDefinedStep()->GetProcessType() == fDecay)
111  moduleID |= BKLM_DECAYED_MASK;
112  }
113  int trackID = track->GetTrackID();
114  if (m->hasRPCs()) {
115  const CLHEP::Hep3Vector propagationTimes =
116  m->getPropagationTimes(localPosition);
117  int phiStripLower = -1;
118  int phiStripUpper = -1;
119  int zStripLower = -1;
120  int zStripUpper = -1;
121  convertHitToRPCStrips(localPosition, m, phiStripLower, phiStripUpper, zStripLower, zStripUpper);
122  if (zStripLower > 0) {
123  int moduleIDZ = moduleID;
125  moduleIDZ, BKLMElementNumbers::c_ZPlane);
126  BKLMElementNumbers::setStripInModule(moduleIDZ, zStripLower);
127  BKLMStatus::setMaximalStrip(moduleIDZ, zStripUpper);
128  BKLMSimHit* simHit = m_SimHits.appendNew(moduleIDZ, propagationTimes.z(), time, eDep);
129  m_MCParticlesToSimHits.add(trackID, simHit->getArrayIndex());
130  BKLMSimHitPosition* simHitPosition = m_SimHitPositions.appendNew(globalPosition.x(), globalPosition.y(), globalPosition.z());
131  simHitPosition->addRelationTo(simHit);
132  }
133  if (phiStripLower > 0) {
136  BKLMElementNumbers::setStripInModule(moduleID, phiStripLower);
137  BKLMStatus::setMaximalStrip(moduleID, phiStripUpper);
138  BKLMSimHit* simHit = m_SimHits.appendNew(moduleID, propagationTimes.y(), time, eDep);
139  m_MCParticlesToSimHits.add(trackID, simHit->getArrayIndex());
140  BKLMSimHitPosition* simHitPosition = m_SimHitPositions.appendNew(globalPosition.x(), globalPosition.y(), globalPosition.z());
141  simHitPosition->addRelationTo(simHit);
142  }
143  } else {
144  int scint = hist->GetCopyNumber(depth - m_DepthScintillator);
145  bool phiPlane = (plane == BKLM_INNER);
146  double propagationTime =
147  m->getPropagationTime(localPosition, scint, phiPlane);
148  BKLMElementNumbers::setStripInModule(moduleID, scint);
149  BKLMStatus::setMaximalStrip(moduleID, scint);
150  if (phiPlane) {
153  } else {
155  moduleID, BKLMElementNumbers::c_ZPlane);
156  }
157  BKLMSimHit* simHit = m_SimHits.appendNew(moduleID, propagationTime, time,
158  eDep);
159  m_MCParticlesToSimHits.add(trackID, simHit->getArrayIndex());
160  BKLMSimHitPosition* simHitPosition = m_SimHitPositions.appendNew(globalPosition.x(), globalPosition.y(), globalPosition.z());
161  simHitPosition->addRelationTo(simHit);
162  }
163  return true;
164  }
165  return false;
166 }
167 
168 void SensitiveDetector::convertHitToRPCStrips(const CLHEP::Hep3Vector& localPosition, const Module* m,
169  int& phiStripLower, int& phiStripUpper, int& zStripLower, int& zStripUpper)
170 {
171  double phiStripD = m->getPhiStrip(localPosition);
172  int phiStrip = int(phiStripD);
173  int pMin = m->getPhiStripMin();
174  if (phiStrip < pMin)
175  return;
176  int pMax = m->getPhiStripMax();
177  if (phiStrip > pMax)
178  return;
179 
180  double zStripD = m->getZStrip(localPosition);
181  int zStrip = int(zStripD);
182  int zMin = m->getZStripMin();
183  if (zStrip < zMin)
184  return;
185  int zMax = m->getZStripMax();
186  if (zStrip > zMax)
187  return;
188 
189  phiStripLower = phiStrip;
190  phiStripUpper = phiStrip;
191  zStripLower = zStrip;
192  zStripUpper = zStrip;
193  double phiStripDiv = fmod(phiStripD, 1.0) - 0.5; // between -0.5 and +0.5 within central phiStrip
194  double zStripDiv = fmod(zStripD, 1.0) - 0.5; // between -0.5 and +0.5 within central zStrip
195  int n = 0;
196  double rand = gRandom->Uniform();
197  for (n = 1; n < m_SimPar->getMaxMultiplicity(); ++n) {
198  if (m_SimPar->getPhiMultiplicityCDF(phiStripDiv, n) > rand)
199  break;
200  }
201  int nextStrip = (phiStripDiv > 0.0 ? 1 : -1);
202  while (--n > 0) {
203  phiStrip += nextStrip;
204  if ((phiStrip >= pMin) && (phiStrip <= pMax)) {
205  phiStripLower = min(phiStrip, phiStripLower);
206  phiStripUpper = max(phiStrip, phiStripUpper);
207  }
208  nextStrip = (nextStrip > 0 ? -(1 + nextStrip) : 1 - nextStrip);
209  }
210  rand = gRandom->Uniform();
211  for (n = 1; n < m_SimPar->getMaxMultiplicity(); ++n) {
212  if (m_SimPar->getZMultiplicityCDF(zStripDiv, n) > rand)
213  break;
214  }
215  nextStrip = (zStripDiv > 0.0 ? 1 : -1);
216  while (--n > 0) {
217  zStrip += nextStrip;
218  if ((zStrip >= zMin) && (zStrip <= zMax)) {
219  zStripLower = min(zStrip, zStripLower);
220  zStripUpper = max(zStrip, zStripUpper);
221  }
222  nextStrip = (nextStrip > 0 ? -(1 + nextStrip) : 1 - nextStrip);
223  }
224  return;
225 }
static void setStripInModule(int &module, int strip)
Set strip number in module identifier.
static KLMModuleNumber moduleNumber(int section, int sector, int layer, bool fatalError=true)
Get module number.
static void setPlaneInModule(int &module, int plane)
Set plane number in module identifier.
Store one simulation hit's global position as a ROOT object.
Store one simulation hit as a ROOT object.
Definition: BKLMSimHit.h:25
static void setMaximalStrip(int &module, int strip)
Set maximal strip number.
Definition: BKLMStatus.h:93
This class provides a set of constants for the framework.
Definition: Const.h:34
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
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.
bool doBeamBackgroundStudy(void) const
Get the beam background study flag.
Definition: GeometryPar.h:52
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
Definition: GeometryPar.cc:727
BkgSensitiveDetector * getBkgSensitiveDetector(void) const
Get the beam background study flag.
Definition: GeometryPar.h:58
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Definition: GeometryPar.cc:28
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition: Module.h:76
DBObjPtr< BKLMSimulationPar > m_SimPar
Simulation parameters (from DB)
void convertHitToRPCStrips(const CLHEP::Hep3Vector &, const Module *, int &, int &, int &, int &)
Find the ranges of matching RPC strips for each simulated hit.
bool m_FirstCall
Flag to enforce once-only initializations in Initialize()
static constexpr int m_DepthSection
Section depth.
static constexpr int m_DepthSector
Sector depth.
StoreArray< BKLMSimHit > m_SimHits
BKLM simulated hits.
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.
RelationArray m_MCParticlesToSimHits
Relation array between MCPartices and BKLMSimHits.
StoreArray< BKLMSimHitPosition > m_SimHitPositions
BKLM simulated hit positions.
GeometryPar * m_GeoPar
Pointer to GeometryPar singleton.
bool step(G4Step *, G4TouchableHistory *) override
Process each step in the BKLM.
static constexpr int m_DepthScintillator
Scintillator depth.
static constexpr int m_DepthPlane
Plane depth.
StoreArray< MCParticle > m_MCParticles
MC particles.
static constexpr int m_DepthLayer
Layer depth.
Class to store variables with their name which were sent to the logging service.
bool step(G4Step *aStep, G4TouchableHistory *) override
Process each step and calculate variables defined in PXDSimHit.