ATLAS Offline Software
LArFCS_StepInfoSD.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // class header
6 #include "LArFCS_StepInfoSD.h"
8 #include "G4Step.hh"
9 #include "G4ThreeVector.hh"
10 #include "G4TouchableHistory.hh"
11 
14 #include "CaloDetDescr/CaloDetDescrElement.h"
16 
17 #include "GaudiKernel/MsgStream.h"
18 #include <string>
19 #include <utility>
20 
22  : FCS_StepInfoSD(std::move(a_name), config)
23  , m_calculator(m_config.m_LArCalculator)
24 {
25 }
26 
28 {
29 }
30 
31 G4bool LArFCS_StepInfoSD::ProcessHits(G4Step* a_step,G4TouchableHistory*)
32 {
33  G4bool result(false);
34  // If there's no energy, there's no hit. (Aside: Isn't this energy
35  // the same as the energy from the calculator? Not necessarily.
36  // The calculator may include detector effects such as
37  // charge-collection which are not modeled by Geant4.)
38  if(a_step->GetTotalEnergyDeposit() <= 0.) { return result; }
39 
40  if (m_calculator) {
41  if(!m_calo_dd_man.get()) {
43  }
44 
45  const double StepLength = a_step->GetStepLength()/ CLHEP::mm;
46  const G4ThreeVector preStepPosition = a_step->GetPreStepPoint()->GetPosition(); //pre step is the position we're interested in
47  const G4ThreeVector postStepPosition = a_step->GetPostStepPoint()->GetPosition();
48  std::vector<const G4Step*> steps;
49  bool madeSubSteps(false);
51  //create smaller substeps instead
52  G4int nsub_step=(int) (StepLength/m_config.substpsize) + 1;
53  G4double delta=1./((double) nsub_step);
54  //G4cout <<"Orig prestep: "<<preStepPosition<<std::endl;
55  for (G4int i=0;i<nsub_step;i++) {
56  G4double fraction1 = ((G4double) i)*delta;
57  G4double fraction2 = (((G4double) i) + 1.)*delta;
58  G4ThreeVector subpoint1=preStepPosition*(1-fraction1) + postStepPosition*fraction1;
59  G4ThreeVector subpoint2=preStepPosition*(1-fraction2) + postStepPosition*fraction2;
60  G4StepPoint *startpoint = new G4StepPoint(*(a_step->GetPreStepPoint()));
61  G4StepPoint *endpoint = new G4StepPoint(*(a_step->GetPostStepPoint()));
62  startpoint->SetPosition(subpoint1);
63  endpoint->SetPosition(subpoint2);
64 
65  G4Step* newstep = new G4Step(*a_step);
66  newstep->SetPreStepPoint(startpoint);
67  newstep->SetPostStepPoint(endpoint);
68  newstep->SetStepLength( (subpoint1-subpoint2).mag());
69  newstep->SetTotalEnergyDeposit(a_step->GetTotalEnergyDeposit()/nsub_step);
70  steps.push_back(newstep);
71  madeSubSteps=true;
72  }
73  }
74  else {
75  steps.push_back(a_step);
76  }
77 
78  if (m_config.verboseLevel > 4) {
79  G4cout <<"LArFCS_StepInfoSD::ProcessHits(): original step in Volume: "<<
80  a_step->GetPreStepPoint()->GetPhysicalVolume()->GetName()<<
81  " position: "<<a_step->GetPreStepPoint()->GetPosition()<<" Length="<<a_step->GetStepLength()/CLHEP::mm<<
82  " E="<<a_step->GetTotalEnergyDeposit()<<G4endl;
83  std::vector<LArHitData> processedHits;
84  if (m_calculator->Process(a_step, processedHits)) {
85  if (m_config.verboseLevel > -1) {
86  G4cout <<" #LArHitData="<<processedHits.size();
87  for(const auto& lhd:processedHits) {
88  G4cout <<" ; id="<<(std::string)lhd.id<<" E="<<lhd.energy<<G4endl;
89  }
90  G4cout << G4endl;
91  }
92  }
93  G4cout <<"LArFCS_StepInfoSD::ProcessHits(): #substep="<< steps.size()<<G4endl;
94  }
95 
96  double et_all=0; // Total collected charge in all substeps
97  for (const G4Step* substep : steps) {
98  double et(0.); // Total collected charge in this substep
99  G4ThreeVector stepPosition = 0.5*(substep->GetPreStepPoint()->GetPosition()+substep->GetPostStepPoint()->GetPosition());
100  std::vector<LArHitData> processedHits;
101  if (m_config.verboseLevel > 4) {
102  G4cout <<" LArFCS_StepInfoSD::ProcessHits(): substep in Volume: "<<
103  substep->GetPreStepPoint()->GetPhysicalVolume()->GetName()<<
104  " position: "<<substep->GetPreStepPoint()->GetPosition()<<" Length="<<substep->GetStepLength()/CLHEP::mm<<
105  " E="<<substep->GetTotalEnergyDeposit()<<G4endl;
106  }
107  if (m_calculator->Process(substep, processedHits)) {
108  for (const auto& larhit: processedHits) {
109  et += larhit.energy;
110  et_all += larhit.energy;
111  }
112  if (m_config.verboseLevel > 4) {
113  G4cout <<" substep #LArHitData="<<processedHits.size();
114  for(const auto& lhd:processedHits) {
115  G4cout <<" ; id="<<(std::string)lhd.id<<" E="<<lhd.energy<<G4endl;
116  }
117  G4cout << G4endl;
118  }
119  } else {
120  if (m_config.verboseLevel > 4) {
121  //Maybe 0 hits or something like that...
122  G4cout << this->GetName()<<" WARNING ProcessHits: Call to ILArCalculatorSvc::Process failed! Details:" << G4endl
123  << " " << "Volume: "<< a_step->GetPreStepPoint()->GetPhysicalVolume()->GetName()<<" "<<m_calculator<< " position: "<<stepPosition<<" SL: "<<StepLength<<G4endl
124  << " " << "Orig position: "<<substep->GetPreStepPoint()->GetPosition()<<" / "<<substep->GetPostStepPoint()->GetPosition()<<G4endl
125  << " " << "StepLength: "<<StepLength<<" step: "<<preStepPosition<<" / "<<postStepPosition<<G4endl;
126  }
127  continue;
128  }
129 
130  // drop hits with zero deposited energy (could still happen with negative corrections from calculator)
131  //Or if total energy is <0
132  if (et <= 0.) {
133  if (m_config.verboseLevel > 4) {
134  G4cout << this->GetName()<<" WARNING ProcessHits: Total negative energy: " << et << " not processing..." << G4endl;
135  }
136  continue;
137  }
138 
139  const size_t numberOfProcessedHits = processedHits.size();
140  const G4ThreeVector originalStepPosition = stepPosition;
141  double maxSubHitEnergy = -999.;
142  int maxSubHitEnergyindex =-1;
143  if (numberOfProcessedHits>0) {
144  maxSubHitEnergy = processedHits[0].energy;
145  maxSubHitEnergyindex = 0;
146  }
147  //Figure out the subhit with most energy
148  for (size_t i=1; i<numberOfProcessedHits; ++i) {
149  if (maxSubHitEnergy<processedHits[i].energy) {
150  maxSubHitEnergy = processedHits[i].energy;
151  maxSubHitEnergyindex = i;
152  }
153  }
154  if (maxSubHitEnergyindex == -1){//because there were no hits; numberOfProcessedHits ==0
155  G4cout << this->GetName()<<" WARNING ProcessHits: numberOfProcessedHits is zero" << G4endl;
156  continue;
157  }
158  //Identifier for the subhit with max energy
159  Identifier maxEnergyIdentifier = this->ConvertID(processedHits[maxSubHitEnergyindex].id);
160  const CaloDetDescrElement *maxEnergyCell = m_calo_dd_man.get()->get_element(maxEnergyIdentifier);
161 
162  Identifier invalidIdentifier;
163  //for (size_t i=0; i<numberOfProcessedHits; ++i) {
164  for (const auto& larhit: processedHits) {
165  Identifier id = this->ConvertID(larhit.id);
166  if(larhit.id[0]==10) {
167  if(m_config.verboseLevel > 9) {
168  G4cout << this->GetName()<<" VERBOSE ProcessHits: Dead Material LArG4Identifier: "<<(std::string) larhit.id<<G4endl
169  <<" "<<id<<G4endl
170  <<" "<<id.getString()<<G4endl
171  <<" "<< a_step->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName()<<G4endl
172  <<" numberOfProcessedHits: "<<numberOfProcessedHits<<G4endl;
173  G4cout <<" "<<invalidIdentifier<<G4endl;
174  }
175  }
176  else if (id == invalidIdentifier) {
177  G4cout << this->GetName()<<" WARNING ProcessHits: Something wrong with LArG4Identifier: "<<(std::string) larhit.id<<G4endl
178  <<" "<<id<<G4endl
179  <<" "<<id.getString()<<G4endl
180  <<" "<< a_step->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName()<<G4endl
181  <<" numberOfProcessedHits: "<<numberOfProcessedHits<<G4endl;
182  G4cout <<" "<<invalidIdentifier<<G4endl;
183  }
184  //need to get the cell information
185  if (numberOfProcessedHits>1) {
186  if (!m_larEmID->is_em_barrel(id)) {
187  //It didn't seem to happen outside em_barrel, so flag up if it does:
188  G4cout << this->GetName()<<" WARNING ProcessHits: Outside LAr barrel, but numberOfProcessedHits="<<numberOfProcessedHits
189  <<", LArG4Identifier: "<<(std::string) larhit.id<<G4endl;
190  }
191  else {
193  //find subhit with largest energy
194  if (maxSubHitEnergyindex == -1) {
195  G4cout << this->GetName()<<" WARNING ProcessHits: no subhit index with e>-999??? "<<G4endl;
196  continue;
197  }
198  if(m_config.verboseLevel > 9) {
199  G4cout << this->GetName()<<" VERBOSE ProcessHits: shifting subhits: largest energy subhit index is "<<maxSubHitEnergyindex<<" E: "<<maxSubHitEnergy<<" identifier: "<<maxEnergyIdentifier.getString()<<G4endl;
200  }
201  //from identifier
202  const CaloDetDescrElement *thiscell = m_calo_dd_man.get()->get_element(id);
203  if (!maxEnergyCell) {
204  //How often does this happen? Do not shift.
205  G4cout << this->GetName()<<" WARNING ProcessHits: maxEnergyCell failed: "<<maxEnergyIdentifier.getString()<<G4endl
206  <<" "<<m_calo_dd_man.get()->get_element(id)->getSampling()<<G4endl
207  <<" "<<originalStepPosition.eta()<<G4endl
208  <<" "<< originalStepPosition.phi()<<G4endl;
209  stepPosition = originalStepPosition;
210  }
211  else if (maxEnergyCell == thiscell) {
212  //The cells match, so do not shift this hit.
213  if(m_config.verboseLevel > 9) {
214  G4cout << this->GetName()<<" VERBOSE ProcessHits: Original step position: "<<originalStepPosition.x()<<" "<<originalStepPosition.y()<<" "<<originalStepPosition.z()<<G4endl
215  <<" "<<"This cell: "<<thiscell->x()<<" "<<thiscell->y()<<" "<<thiscell->z()<<G4endl
216  <<" "<<"No shift"<<G4endl;
217  }
218  stepPosition = originalStepPosition;
219  }
220  else {
221  //the two cells do not match => shift
222  G4ThreeVector diff(thiscell->x()-maxEnergyCell->x(), thiscell->y()-maxEnergyCell->y(), thiscell->z()-maxEnergyCell->z());
223  stepPosition = originalStepPosition+diff;
224  if(m_config.verboseLevel > 9) {
225  const CaloDetDescrElement *bestcell = m_calo_dd_man.get()->get_element(m_calo_dd_man.get()->get_element(id)->getSampling(),originalStepPosition.eta(), originalStepPosition.phi());
226  G4cout << this->GetName()<<" VERBOSE ProcessHits: Original step position: "<<originalStepPosition.x()<<" "<<originalStepPosition.y()<<" "<<originalStepPosition.z()<<G4endl
227  <<" "<<"This cell: "<<thiscell->x()<<" "<<thiscell->y()<<" "<<thiscell->z()<<G4endl
228  <<" "<<"Highest E cell: "<<maxEnergyCell->x()<<" "<<maxEnergyCell->y()<<" "<<maxEnergyCell->z()<<G4endl
229  <<" "<<"(Best cell: "<<bestcell->x()<<" "<<bestcell->y()<<" "<<bestcell->z()<<")"<<G4endl
230  <<" "<<"Shifted step position: "<<stepPosition.x()<<" "<<stepPosition.y()<<" "<<stepPosition.z()<<G4endl;
231  }
232  }
233  }
234  }
235  }
236  //Finalize time for LAr hits?: NO
237  //double time = larhit.energy)==0 ? 0. : (double) larhit.time/larhit.energy/CLHEP::ns;
238  double time = larhit.time;
239  double energy = larhit.energy/CLHEP::MeV;
240  // Drop any hits that don't have a good identifier attached
241  if (!m_calo_dd_man.get()->get_element(id)) {
242  if(m_config.verboseLevel > 4) {
243  G4cout<<this->GetName()<<" DEBUG update_map: bad identifier: "<<id.getString()<<" skipping this hit."<<G4endl;
244  }
245  continue;
246  }
247  // Get the appropriate merging limits
248  const CaloCell_ID::CaloSample& layer = m_calo_dd_man.get()->get_element(id)->getSampling();
249  const double timeWindow(m_config.m_maxTime);
250  const double distanceWindow((layer == CaloCell_ID::EMB1 || layer == CaloCell_ID::EME1) ? m_config.m_maxRadiusFine : m_config.m_maxRadius); //Default 1mm merging in layers 1 & 5, 5mm merging elsewhere
251  this->update_map(stepPosition, id, energy, time, true, numberOfProcessedHits, timeWindow, distanceWindow); //store numberOfProcessedHits as info
252  }//numberOfProcessedHits
253  } //istep
254  if (madeSubSteps) {
255  //only delete steps when doing substeps. Do not delete the original G4Step!
256  while(!steps.empty()) { delete steps.back(); steps.pop_back(); }
257  }
258  if (m_config.verboseLevel > 4) {
259  G4cout <<"LArFCS_StepInfoSD::ProcessHits(): Etotal substeps="<<et_all<<G4endl<<G4endl<<G4endl;
260  }
261  }
262 
263  return result;
264 }
265 
267 {
268  Identifier id;
269  if(a_ident[0]==4) {
270  // is LAr
271  if(a_ident[1]==1) {
272  //is LAr EM
273  try {
274  id = m_larEmID->channel_id(a_ident[2], // barrel_ec
275  a_ident[3], // sampling
276  a_ident[4], // region
277  a_ident[5], // eta
278  a_ident[6]); // phi
279  }
280  catch (LArID_Exception& e) {
281  G4ExceptionDescription description;
282  description << "ConvertID: LArEM_ID error code " << e.code() << " "
283  << (std::string) e;
284  G4Exception("LArFCS_StepInfoSD", "ConvertIDEM", FatalException, description);
285  abort();
286  }
287  }
288  else if(a_ident[1]==2) {
289  //is EM HEC
290  try {
291  id = m_larHecID->channel_id(a_ident[2], // zSide
292  a_ident[3], // sampling
293  a_ident[4], // region
294  a_ident[5], // eta
295  a_ident[6]); // phi
296  }
297  catch(LArID_Exception& e) {
298  G4ExceptionDescription description;
299  description << "ConvertID: LArHEC_ID error code " << e.code() << " "
300  << (std::string) e;
301  G4Exception("LArFCS_StepInfoSD", "ConvertIDHEC", FatalException, description);
302  abort();
303  }
304  }
305  else if(a_ident[1]==3) {
306  // FCAL
307  if(a_ident[3]>0) {
308  //is EM FCAL
309  try {
310  id = m_larFcalID->channel_id(a_ident[2], // zSide
311  a_ident[3], // sampling
312  a_ident[4], // eta
313  a_ident[5]); // phi
314  }
315  catch(LArID_Exception& e) {
316  G4ExceptionDescription description;
317  description << "ConvertID: LArFCAL_ID error code " << e.code() << " "
318  << (std::string) e;
319  G4Exception("LArFCS_StepInfoSD", "ConvertIDFCAL", FatalException, description);
320  abort();
321  }
322  }
323  else {
324  G4ExceptionDescription description;
325  description << "ConvertID: Unsupported ID. ";
326  G4Exception("LArFCS_StepInfoSD", "ConvertIDMiniFCAL", FatalException, description);
327  abort();
328  }
329  }
330  }
331  return id;
332 }
LArG4Identifier
Definition: LArG4Identifier.h:121
FCS_StepInfoSD::update_map
void update_map(const CLHEP::Hep3Vector &l_vec, const Identifier &l_identifier, double l_energy, double l_time, bool l_valid, int l_detector, double timeWindow, double distanceWindow)
Definition: FCS_StepInfoSD.cxx:158
et
Extra patterns decribing particle interation process.
get_generator_info.result
result
Definition: get_generator_info.py:21
LArFCS_StepInfoSD::m_calculator
ILArCalculatorSvc * m_calculator
Member variable - the calculator we'll use.
Definition: LArFCS_StepInfoSD.h:47
constants.EMB1
int EMB1
Definition: Calorimeter/CaloClusterCorrection/python/constants.py:53
CaloDetDescrElement::y
float y() const
cell y
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:365
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
xAOD::et
et
Definition: TrigEMCluster_v1.cxx:25
LArFCS_StepInfoSD::ConvertID
Identifier ConvertID(const LArG4Identifier &a_ident) const
Helper function for making "real" identifiers from LArG4Identifiers.
Definition: LArFCS_StepInfoSD.cxx:266
FCS_StepInfoSD::getCaloDDManager
void getCaloDDManager()
Keep a map instead of trying to keep the full vector.
Definition: FCS_StepInfoSD.cxx:145
FCS_Param::Config::m_maxRadius
double m_maxRadius
property, see LArG4GenShowerLib::LArG4GenShowerLib
Definition: FCS_StepInfoSD.h:50
ILArCalculatorSvc::Process
virtual G4bool Process(const G4Step *, std::vector< LArHitData > &) const =0
CaloDetDescrElement
This class groups all DetDescr information related to a CaloCell. Provides a generic interface for al...
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:66
python.SystemOfUnits.MeV
int MeV
Definition: SystemOfUnits.py:154
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
FCS_Param::Config::shift_lar_subhit
bool shift_lar_subhit
Definition: FCS_StepInfoSD.h:45
FCS_StepInfoSD::m_calo_dd_man
CxxUtils::CachedPointer< const CaloDetDescrManager > m_calo_dd_man
Definition: FCS_StepInfoSD.h:128
FCS_Param::Config::m_maxRadiusFine
double m_maxRadiusFine
property, see LArG4GenShowerLib::LArG4GenShowerLib
Definition: FCS_StepInfoSD.h:51
LArEM_Base_ID::channel_id
Identifier channel_id(const ExpandedIdentifier &exp_id) const
Build a cell identifier from an expanded identifier.
FCS_Param::Config::substpsize
double substpsize
Definition: FCS_StepInfoSD.h:47
CaloDetDescrManager.h
Definition of CaloDetDescrManager.
config
Definition: PhysicsAnalysis/AnalysisCommon/AssociationUtils/python/config.py:1
LArFCS_StepInfoSD.h
beamspotman.steps
int steps
Definition: beamspotman.py:505
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
lumiFormat.i
int i
Definition: lumiFormat.py:92
CaloSampling::CaloSample
CaloSample
Definition: Calorimeter/CaloGeoHelpers/CaloGeoHelpers/CaloSampling.h:22
Identifier
Definition: DetectorDescription/Identifier/Identifier/Identifier.h:32
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
LArFCAL_Base_ID::channel_id
Identifier channel_id(const ExpandedIdentifier &exp_id) const
cell identifier for a channel from ExpandedIdentifier
FCS_StepInfoSD::m_larHecID
const LArHEC_ID * m_larHecID
Definition: FCS_StepInfoSD.h:126
LArFCS_StepInfoSD::LArFCS_StepInfoSD
LArFCS_StepInfoSD(G4String a_name, const FCS_Param::Config &config)
Constructor.
Definition: LArFCS_StepInfoSD.cxx:21
FCS_Param::Config::m_maxTime
double m_maxTime
Definition: FCS_StepInfoSD.h:57
constants.EME1
int EME1
Definition: Calorimeter/CaloClusterCorrection/python/constants.py:55
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
FCS_StepInfoSD::m_larEmID
const LArEM_ID * m_larEmID
Pointers to the identifier helpers.
Definition: FCS_StepInfoSD.h:124
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:194
LArHEC_Base_ID::channel_id
Identifier channel_id(const ExpandedIdentifier &exp_id) const
channel identifier for a channel from ExpandedIdentifier
CaloDetDescrElement::x
float x() const
cell x
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:363
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
Identifier::getString
std::string getString() const
Provide a string form of the identifier - hexadecimal.
Definition: Identifier.cxx:25
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
ILArCalculatorSvc.h
CaloSwCorrections.time
def time(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:242
LArEM_Base_ID::is_em_barrel
bool is_em_barrel(const Identifier id) const
test if the id belongs to the EM barrel
CaloDetDescrElement::z
float z() const
cell z
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:367
CxxUtils::CachedPointer::get
pointer_t get() const
Return the current value of the element.
FCS_StepInfoSD
Common sensitive detector class for LAr systems.
Definition: FCS_StepInfoSD.h:93
FCS_StepInfoSD::m_config
FCS_Param::Config m_config
Definition: FCS_StepInfoSD.h:122
LArFCS_StepInfoSD::ProcessHits
G4bool ProcessHits(G4Step *a_step, G4TouchableHistory *) override
Main processing method.
Definition: LArFCS_StepInfoSD.cxx:31
FCS_Param::Config
Definition: FCS_StepInfoSD.h:42
Trk::StepLength
@ StepLength
Definition: MaterialAssociationType.h:17
FCS_Param::Config::shorten_lar_step
bool shorten_lar_step
Definition: FCS_StepInfoSD.h:46
FCS_Param::Config::verboseLevel
int verboseLevel
Helper to keep the same verbosity everywhere.
Definition: FCS_StepInfoSD.h:44
G4StepHelper::preStepPosition
G4ThreeVector preStepPosition(const G4Step *theStep)
TODO.
Definition: StepHelper.cxx:14
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:25
LArID_Exception
Exception class for LAr Identifiers.
Definition: LArID_Exception.h:20
G4StepHelper::postStepPosition
G4ThreeVector postStepPosition(const G4Step *theStep)
TODO.
Definition: StepHelper.cxx:19
description
std::string description
glabal timer - how long have I taken so far?
Definition: hcg.cxx:88
LArFCS_StepInfoSD::~LArFCS_StepInfoSD
virtual ~LArFCS_StepInfoSD()
Destructor.
Definition: LArFCS_StepInfoSD.cxx:27
FCS_StepInfoSD::m_larFcalID
const LArFCAL_ID * m_larFcalID
Definition: FCS_StepInfoSD.h:125