CMS 3D CMS Logo

TrackingMaterialProducer.cc
Go to the documentation of this file.
1 #include <iostream> // FIXME: switch to MessagLogger & friends
2 #include <vector>
3 #include <string>
4 #include <cassert>
5 #include <exception>
6 #include <tuple>
7 
13 
18 
20 
21 // GEANT4
22 #include "G4Step.hh"
23 #include "G4Track.hh"
24 #include "G4VSolid.hh"
25 #include "G4LogicalVolumeStore.hh"
26 #include "G4TouchableHistory.hh"
27 #include "G4VPhysicalVolume.hh"
28 #include "G4AffineTransform.hh"
29 
30 #include <DD4hep/Filter.h>
31 
33 
34 // Uncomment the following #define directive to have the full list of
35 // volumes known to G4 printed to LogInfo("TrackingMaterialProducer")
36 
37 #define DEBUG_G4_VOLUMES
38 
39 using namespace CLHEP;
40 using edm::LogInfo;
41 
42 // missing from GEANT4 < 9.0 : G4LogicalVolumeStore::GetVolume( name )
43 static const G4LogicalVolume* GetVolume(const std::string& name) {
44  const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
45 
46 #ifdef DEBUG_G4_VOLUMES
47  for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume)
48  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: G4 registered volumes " << (*volume)->GetName()
49  << std::endl;
50 #endif
51 
52  for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume) {
53  if ((const std::string)(dd4hep::dd::noNamespace((*volume)->GetName())) == name)
54  return (*volume);
55  }
56  return nullptr;
57 }
58 
59 // missing from GEANT4 : G4TouchableHistory::GetTransform( depth )
60 static inline const G4AffineTransform& GetTransform(const G4TouchableHistory* touchable, int depth) {
61  return touchable->GetHistory()->GetTransform(touchable->GetHistory()->GetDepth() - depth);
62 }
63 
64 // navigate up the hierarchy of volumes until one with an attached sensitive detector is found
65 // return a tuple holding
66 // - pointer to the first (deepest) sensitive G4VPhysicalVolume
67 // - how may steps up in the hierarchy it is (0 is the starting volume)
68 // if no sensitive detector is found, return a NULL pointer and 0
69 
70 std::tuple<const G4VPhysicalVolume*, int> GetSensitiveVolume(const G4VTouchable* touchable) {
71  int depth = touchable->GetHistoryDepth();
72  for (int level = 0; level < depth; ++level) { // 0 is self
73  const G4VPhysicalVolume* volume = touchable->GetVolume(level);
74  if (volume->GetLogicalVolume()->GetSensitiveDetector() != nullptr) {
75  return std::make_tuple(volume, level);
76  }
77  }
78  return std::tuple<const G4VPhysicalVolume*, int>(nullptr, 0);
79 }
80 
81 //-------------------------------------------------------------------------
83  edm::ParameterSet config = iPSet.getParameter<edm::ParameterSet>("TrackingMaterialProducer");
84  m_selectedNames = config.getParameter<std::vector<std::string> >("SelectedVolumes");
85  m_primaryTracks = config.getParameter<bool>("PrimaryTracksOnly");
86  m_txtOutFile = config.getUntrackedParameter<std::string>("txtOutFile");
87  m_hgcalzfront = config.getParameter<double>("hgcalzfront");
88  m_tracks = nullptr;
89  m_track_volume = nullptr;
90 
91  produces<std::vector<MaterialAccountingTrack> >();
92  output_file_ = new TFile("radLen_vs_eta_fromProducer.root", "RECREATE");
93  output_file_->cd();
94  radLen_vs_eta_ = new TProfile("radLen", "radLen", 250., -5., 5., 0, 10.);
95 
96  //Check if HGCal volumes are selected
97  isHGCal = false;
98  //if (std::find(m_selectedNames.begin(), m_selectedNames.end(), "CALOECTSRear") != m_selectedNames.end()) {
99  if (std::find(m_selectedNames.begin(), m_selectedNames.end(), "HGCal") != m_selectedNames.end()) {
100  isHGCal = true;
101  }
102  //Check if HFNose volumes are selected
103  isHFNose = false;
104  if (std::find(m_selectedNames.begin(), m_selectedNames.end(), "HFNose") != m_selectedNames.end()) {
105  isHFNose = true;
106  }
107  if (isHGCal or isHFNose) {
108  outVolumeZpositionTxt.open(m_txtOutFile.c_str(), std::ios::out);
109  }
110 }
111 
112 //-------------------------------------------------------------------------
114 
115 //-------------------------------------------------------------------------
117  radLen_vs_eta_->Write();
118  output_file_->Close();
119 }
120 //-------------------------------------------------------------------------
122  // INFO
123  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: List of the selected volumes: " << std::endl;
124  for (std::vector<std::string>::const_iterator volume_name = m_selectedNames.begin();
125  volume_name != m_selectedNames.end();
126  ++volume_name) {
127  const G4LogicalVolume* volume = GetVolume(*volume_name);
128  if (volume) {
129  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: " << *volume_name << std::endl;
130  m_selectedVolumes.push_back(volume);
131  } else {
132  // FIXME: throw an exception ?
133  std::cerr << "TrackingMaterialProducer::update(const BeginOfJob*): WARNING: selected volume \"" << *volume_name
134  << "\" not found in geometry " << std::endl;
135  }
136  }
137 }
138 
139 //-------------------------------------------------------------------------
141  m_tracks = new std::vector<MaterialAccountingTrack>();
142 }
143 
144 //-------------------------------------------------------------------------
146  m_track.reset();
147  m_track_volume = nullptr;
148 
149  // prevent secondary tracks from propagating
150  G4Track* track = const_cast<G4Track*>((*event)());
151  if (m_primaryTracks and track->GetParentID() != 0) {
152  track->SetTrackStatus(fStopAndKill);
153  }
154 
155  //For the HGCal case:
156  //In the beginning of each track, the track will first hit an HGCAL volume and it will
157  //save the upper z volume boundary. So, the low boundary of the first
158  //volume is never saved. Here we give the low boundary of the first volume.
159  //This can be found by asking first to run not on 'HGCal' volume below but
160  //on 'CALOECTSRear', which at the moment of this writing it contains
161  //HGCalService, HGCal and thermal screen. You should run Fireworks to
162  //check if these naming conventions and volumes are valid in the future.
163  //Then, check the VolumesZPosition.txt file to see where CEService ends and
164  //put that number in hgcalzfront. Keep in mind to run on the desired volume above here:
165  //https://github.com/cms-sw/cmssw/blob/master/SimTracker/TrackerMaterialAnalysis/plugins/TrackingMaterialProducer.cc#L95
166  //and to replace the volume name of the material first hit at the file creation line below
167  if (isHGCal && track->GetTrackStatus() != fStopAndKill && fabs(track->GetMomentum().eta()) > outerHGCalEta &&
168  fabs(track->GetMomentum().eta()) < innerHGCalEta) {
169  if (track->GetMomentum().eta() > 0.) {
170  outVolumeZpositionTxt << "Air " << m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0 << std::endl;
171  } else if (track->GetMomentum().eta() <= 0.) {
172  outVolumeZpositionTxt << "Air " << -m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0 << std::endl;
173  }
174  }
175 
176  //For the HFnose case:
177  //restrict the outher radius to eta 3.3 since there is HGCAL shadowing
178  //restrict the innner radius to eta 4 since it's non projective
179 
180  if (isHFNose && track->GetTrackStatus() != fStopAndKill && fabs(track->GetMomentum().eta()) > outerHFnoseEta &&
181  fabs(track->GetMomentum().eta()) < innerHFnoseEta) {
182  if (track->GetMomentum().eta() > 0.) {
183  outVolumeZpositionTxt << "Polyethylene " << m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0
184  << std::endl;
185  } else if (track->GetMomentum().eta() <= 0.) {
186  outVolumeZpositionTxt << "Polyethylene " << -m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0
187  << std::endl;
188  }
189  }
190 }
191 
192 bool TrackingMaterialProducer::isSelectedFast(const G4TouchableHistory* touchable) {
193  for (int d = touchable->GetHistoryDepth() - 1; d >= 0; --d) {
194  if (std::find(m_selectedNames.begin(),
195  m_selectedNames.end(),
196  (std::string)(dd4hep::dd::noNamespace(touchable->GetVolume(d)->GetName()))) != m_selectedNames.end())
197  return true;
198  }
199  return false;
200 }
201 
202 //-------------------------------------------------------------------------
204  const G4TouchableHistory* touchable = static_cast<const G4TouchableHistory*>(step->GetTrack()->GetTouchable());
205  if (not isSelectedFast(touchable)) {
206  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer:\t[...] skipping "
207  << touchable->GetVolume()->GetName() << std::endl;
208  return;
209  }
210 
211  // material and step proterties
212  const G4Material* material = touchable->GetVolume()->GetLogicalVolume()->GetMaterial();
213  double length = step->GetStepLength() / cm; // mm -> cm
214  double X0 = material->GetRadlen() / cm; // mm -> cm
215  double Ne = material->GetElectronDensity() * cm3; // 1/mm3 -> 1/cm3
216  double Xi = Ne / 6.0221415e23 * 0.307075 / 2; // MeV / cm
217  double radiationLengths = length / X0; //
218  double energyLoss = length * Xi / 1000.; // GeV
219  //double energyLoss = step->GetDeltaEnergy()/MeV; should we use this??
220 
221  G4ThreeVector globalPosPre = step->GetPreStepPoint()->GetPosition();
222  G4ThreeVector globalPosPost = step->GetPostStepPoint()->GetPosition();
223  GlobalPoint globalPositionIn(globalPosPre.x() / cm, globalPosPre.y() / cm, globalPosPre.z() / cm); // mm -> cm
224  GlobalPoint globalPositionOut(globalPosPost.x() / cm, globalPosPost.y() / cm, globalPosPost.z() / cm); // mm -> cm
225 
226  G4StepPoint* prePoint = step->GetPreStepPoint();
227  G4StepPoint* postPoint = step->GetPostStepPoint();
228  const CLHEP::Hep3Vector& postPos = postPoint->GetPosition();
229  //Go below only in HGCal case
230  if (isHGCal or isHFNose) {
231  //A step never spans across boundaries: geometry or physics define the end points
232  //If the step is limited by a boundary, the post-step point stands on the
233  //boundary and it logically belongs to the next volume.
234  if (postPoint->GetStepStatus() == fGeomBoundary && fabs(postPoint->GetMomentum().eta()) > outerHGCalEta &&
235  fabs(postPoint->GetMomentum().eta()) < innerHGCalEta) {
236  //Post point position is the low z edge of the new volume, or the upper for the prepoint volume.
237  //So, premat - postz - posteta - postR - premattotalenergylossEtable - premattotalenergylossEfull
238  //Observe the two zeros at the end which in the past where set to emCalculator.GetDEDX and
239  //emCalculator.ComputeTotalDEDX but decided not to be used. Will save the structure though for the script.
240  outVolumeZpositionTxt << prePoint->GetMaterial()->GetName() << " " << postPos.z() << " "
241  << postPoint->GetMomentum().eta() << " "
242  << sqrt(postPos.x() * postPos.x() + postPos.y() * postPos.y()) << " " << 0 << " " << 0
243  << std::endl;
244  }
245 
246  if (postPoint->GetStepStatus() == fGeomBoundary && fabs(postPoint->GetMomentum().eta()) > outerHFnoseEta &&
247  fabs(postPoint->GetMomentum().eta()) < innerHFnoseEta) {
248  outVolumeZpositionTxt << prePoint->GetMaterial()->GetName() << " " << postPos.z() << " "
249  << postPoint->GetMomentum().eta() << " "
250  << sqrt(postPos.x() * postPos.x() + postPos.y() * postPos.y()) << " " << 0 << " " << 0
251  << std::endl;
252  }
253 
254  } //end of isHGCal or HFnose if
255 
256  // check for a sensitive detector
257  bool enter_sensitive = false;
258  bool leave_sensitive = false;
259  double cosThetaPre = 0.0;
260  double cosThetaPost = 0.0;
261  int level = 0;
262  const G4VPhysicalVolume* sensitive = nullptr;
264  std::tie(sensitive, level) = GetSensitiveVolume(touchable);
265  if (sensitive) {
266  const G4VSolid& solid = *touchable->GetSolid(level);
267  const G4AffineTransform& transform = GetTransform(touchable, level);
268  G4ThreeVector pos = transform.Inverse().TransformPoint(G4ThreeVector(0., 0., 0.));
269  position = GlobalPoint(pos.x() / cm, pos.y() / cm, pos.z() / cm); // mm -> cm
270 
271  G4ThreeVector localPosPre = transform.TransformPoint(globalPosPre);
272  EInside statusPre = solid.Inside(localPosPre);
273  if (statusPre == kSurface) {
274  enter_sensitive = true;
275  G4ThreeVector globalDirPre = step->GetPreStepPoint()->GetMomentumDirection();
276  G4ThreeVector localDirPre = transform.TransformAxis(globalDirPre);
277  G4ThreeVector normalPre = solid.SurfaceNormal(localPosPre);
278  cosThetaPre = normalPre.cosTheta(-localDirPre);
279  }
280 
281  G4ThreeVector localPosPost = transform.TransformPoint(globalPosPost);
282  EInside statusPost = solid.Inside(localPosPost);
283  if (statusPost == kSurface) {
284  leave_sensitive = true;
285  G4ThreeVector globalDirPost = step->GetPostStepPoint()->GetMomentumDirection();
286  G4ThreeVector localDirPost = transform.TransformAxis(globalDirPost);
287  G4ThreeVector normalPost = solid.SurfaceNormal(localPosPost);
288  cosThetaPost = normalPost.cosTheta(localDirPost);
289  }
290  }
291 
292  // update track accounting
293  if (enter_sensitive) {
294  if (m_track_volume != nullptr) {
295  edm::LogWarning("TrackingMaterialProducer") << "Entering volume " << sensitive << " while inside volume "
296  << m_track_volume << ". Something is inconsistent";
297  m_track.reset();
298  }
299  m_track_volume = sensitive;
300  m_track.enterDetector(position, cosThetaPre);
301  }
302  m_track.step(MaterialAccountingStep(length, radiationLengths, energyLoss, globalPositionIn, globalPositionOut));
303  if (leave_sensitive) {
304  if (m_track_volume != sensitive) {
305  edm::LogWarning("TrackingMaterialProducer") << "Leaving volume " << sensitive << " while inside volume "
306  << m_track_volume << ". Something is inconsistent";
307  m_track.reset();
308  } else
309  m_track.leaveDetector(cosThetaPost);
310  m_track_volume = nullptr;
311  }
312  if (sensitive)
313  LogInfo("TrackingMaterialProducer") << "Track was near sensitive volume " << sensitive->GetName() << std::endl;
314  else
315  LogInfo("TrackingMaterialProducer") << "Track was near non-sensitive volume " << touchable->GetVolume()->GetName()
316  << std::endl;
317  LogInfo("TrackingMaterialProducer") << "Step length: " << length << " cm\n"
318  << "globalPreStep(r,z): (" << globalPositionIn.perp() << ", "
319  << globalPositionIn.z() << ") cm\n"
320  << "globalPostStep(r,z): (" << globalPositionOut.perp() << ", "
321  << globalPositionOut.z() << ") cm\n"
322  << "position(r,z): (" << position.perp() << ", " << position.z() << ") cm\n"
323  << "Radiation lengths: " << radiationLengths << " \t\t(X0: " << X0
324  << " cm)\n"
325  << "Energy loss: " << energyLoss << " MeV \t(Xi: " << Xi
326  << " MeV/cm)\n"
327  << "Track was " << (enter_sensitive ? "entering " : "in none ")
328  << "sensitive volume\n"
329  << "Track was " << (leave_sensitive ? "leaving " : "in none ")
330  << "sensitive volume\n";
331 }
332 
333 //-------------------------------------------------------------------------
335  const G4Track* track = (*event)();
336  if (m_primaryTracks and track->GetParentID() != 0)
337  return;
338 
339  radLen_vs_eta_->Fill(track->GetMomentum().eta(), m_track.summary().radiationLengths());
340  m_tracks->push_back(m_track);
341 
342  // LogInfo
343  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: this track took " << m_track.steps().size()
344  << " steps, and passed through " << m_track.detectors().size()
345  << " sensitive detectors" << std::endl;
346  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: track length: " << m_track.summary().length()
347  << " cm" << std::endl;
348  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: radiation lengths: "
349  << m_track.summary().radiationLengths() << std::endl;
350  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: energy loss: "
351  << m_track.summary().energyLoss() << " MeV" << std::endl;
352 }
353 
354 //-------------------------------------------------------------------------
356  // transfer ownership to the Event
357  std::unique_ptr<std::vector<MaterialAccountingTrack> > tracks(m_tracks);
358  iEvent.put(std::move(tracks));
359  m_tracks = nullptr;
360 }
361 
362 //-------------------------------------------------------------------------
363 bool TrackingMaterialProducer::isSelected(const G4VTouchable* touchable) {
364  for (size_t i = 0; i < m_selectedVolumes.size(); ++i)
365  if (m_selectedVolumes[i]->IsAncestor(touchable->GetVolume()) or
366  m_selectedVolumes[i] == touchable->GetVolume()->GetLogicalVolume())
367  return true;
368 
369  return false;
370 }
371 
372 //-------------------------------------------------------------------------
373 // define as a plugin
#define DEFINE_SIMWATCHER(type)
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
T z() const
Definition: PV3DBase.h:61
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
Definition: config.py:1
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
TrackingMaterialProducer(const edm::ParameterSet &)
static const G4AffineTransform & GetTransform(const G4TouchableHistory *touchable, int depth)
int iEvent
Definition: GenABIO.cc:224
T sqrt(T t)
Definition: SSEVec.h:19
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
d
Definition: ztail.py:151
Log< level::Info, false > LogInfo
static const G4LogicalVolume * GetVolume(const std::string &name)
static int position[264][3]
Definition: ReadPGInfo.cc:289
step
Definition: StallMonitor.cc:83
Log< level::Warning, false > LogWarning
void produce(edm::Event &, const edm::EventSetup &) override
void update(const BeginOfJob *) override
This routine will be called when the appropriate signal arrives.
bool isSelected(const G4VTouchable *touch)
def move(src, dest)
Definition: eostools.py:511
bool isSelectedFast(const G4TouchableHistory *touch)
Definition: event.py:1
std::tuple< const G4VPhysicalVolume *, int > GetSensitiveVolume(const G4VTouchable *touchable)
unsigned transform(const HcalDetId &id, unsigned transformCode)