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 
31 
32 // Uncomment the following #define directive to have the full list of
33 // volumes known to G4 printed to LogInfo("TrackingMaterialProducer")
34 
35 #define DEBUG_G4_VOLUMES
36 
37 using namespace CLHEP;
38 using edm::LogInfo;
39 
40 // missing from GEANT4 < 9.0 : G4LogicalVolumeStore::GetVolume( name )
41 static const G4LogicalVolume* GetVolume(const std::string& name) {
42  const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
43 
44 #ifdef DEBUG_G4_VOLUMES
45  for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume)
46  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: G4 registered volumes " << (*volume)->GetName()
47  << std::endl;
48 #endif
49 
50  for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume) {
51  if ((const std::string&)(*volume)->GetName() == name)
52  return (*volume);
53  }
54  return nullptr;
55 }
56 
57 // missing from GEANT4 : G4TouchableHistory::GetTransform( depth )
58 static inline const G4AffineTransform& GetTransform(const G4TouchableHistory* touchable, int depth) {
59  return touchable->GetHistory()->GetTransform(touchable->GetHistory()->GetDepth() - depth);
60 }
61 
62 // navigate up the hierarchy of volumes until one with an attached sensitive detector is found
63 // return a tuple holding
64 // - pointer to the first (deepest) sensitive G4VPhysicalVolume
65 // - how may steps up in the hierarchy it is (0 is the starting volume)
66 // if no sensitive detector is found, return a NULL pointer and 0
67 
68 std::tuple<const G4VPhysicalVolume*, int> GetSensitiveVolume(const G4VTouchable* touchable) {
69  int depth = touchable->GetHistoryDepth();
70  for (int level = 0; level < depth; ++level) { // 0 is self
71  const G4VPhysicalVolume* volume = touchable->GetVolume(level);
72  if (volume->GetLogicalVolume()->GetSensitiveDetector() != nullptr) {
73  return std::make_tuple(volume, level);
74  }
75  }
76  return std::tuple<const G4VPhysicalVolume*, int>(nullptr, 0);
77 }
78 
79 //-------------------------------------------------------------------------
81  edm::ParameterSet config = iPSet.getParameter<edm::ParameterSet>("TrackingMaterialProducer");
82  m_selectedNames = config.getParameter<std::vector<std::string> >("SelectedVolumes");
83  m_primaryTracks = config.getParameter<bool>("PrimaryTracksOnly");
84  m_tracks = nullptr;
85 
86  produces<std::vector<MaterialAccountingTrack> >();
87  output_file_ = new TFile("radLen_vs_eta_fromProducer.root", "RECREATE");
88  output_file_->cd();
89  radLen_vs_eta_ = new TProfile("radLen", "radLen", 250., -5., 5., 0, 10.);
90 }
91 
92 //-------------------------------------------------------------------------
94 
95 //-------------------------------------------------------------------------
96 void TrackingMaterialProducer::update(const EndOfJob* event) {
97  radLen_vs_eta_->Write();
98  output_file_->Close();
99 }
100 //-------------------------------------------------------------------------
102  // INFO
103  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: List of the selected volumes: " << std::endl;
104  for (std::vector<std::string>::const_iterator volume_name = m_selectedNames.begin();
105  volume_name != m_selectedNames.end();
106  ++volume_name) {
107  const G4LogicalVolume* volume = GetVolume(*volume_name);
108  if (volume) {
109  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: " << *volume_name << std::endl;
110  m_selectedVolumes.push_back(volume);
111  } else {
112  // FIXME: throw an exception ?
113  std::cerr << "TrackingMaterialProducer::update(const BeginOfJob*): WARNING: selected volume \"" << *volume_name
114  << "\" not found in geometry " << std::endl;
115  }
116  }
117 }
118 
119 //-------------------------------------------------------------------------
121  m_tracks = new std::vector<MaterialAccountingTrack>();
122 }
123 
124 //-------------------------------------------------------------------------
126  m_track.reset();
127 
128  // prevent secondary tracks from propagating
129  G4Track* track = const_cast<G4Track*>((*event)());
130  if (m_primaryTracks and track->GetParentID() != 0) {
131  track->SetTrackStatus(fStopAndKill);
132  }
133 }
134 
135 bool TrackingMaterialProducer::isSelectedFast(const G4TouchableHistory* touchable) {
136  for (int d = touchable->GetHistoryDepth() - 1; d >= 0; --d) {
137  if (std::find(m_selectedNames.begin(), m_selectedNames.end(), touchable->GetVolume(d)->GetName()) !=
138  m_selectedNames.end())
139  return true;
140  }
141  return false;
142 }
143 
144 //-------------------------------------------------------------------------
146  const G4TouchableHistory* touchable = static_cast<const G4TouchableHistory*>(step->GetTrack()->GetTouchable());
147  if (not isSelectedFast(touchable)) {
148  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer:\t[...] skipping "
149  << touchable->GetVolume()->GetName() << std::endl;
150  return;
151  }
152 
153  // material and step proterties
154  const G4Material* material = touchable->GetVolume()->GetLogicalVolume()->GetMaterial();
155  double length = step->GetStepLength() / cm; // mm -> cm
156  double X0 = material->GetRadlen() / cm; // mm -> cm
157  double Ne = material->GetElectronDensity() * cm3; // 1/mm3 -> 1/cm3
158  double Xi = Ne / 6.0221415e23 * 0.307075 / 2; // MeV / cm
159  double radiationLengths = length / X0; //
160  double energyLoss = length * Xi / 1000.; // GeV
161  //double energyLoss = step->GetDeltaEnergy()/MeV; should we use this??
162 
163  G4ThreeVector globalPosPre = step->GetPreStepPoint()->GetPosition();
164  G4ThreeVector globalPosPost = step->GetPostStepPoint()->GetPosition();
165  GlobalPoint globalPositionIn(globalPosPre.x() / cm, globalPosPre.y() / cm, globalPosPre.z() / cm); // mm -> cm
166  GlobalPoint globalPositionOut(globalPosPost.x() / cm, globalPosPost.y() / cm, globalPosPost.z() / cm); // mm -> cm
167 
168  // check for a sensitive detector
169  bool enter_sensitive = false;
170  bool leave_sensitive = false;
171  double cosThetaPre = 0.0;
172  double cosThetaPost = 0.0;
173  int level = 0;
174  const G4VPhysicalVolume* sensitive = nullptr;
176  std::tie(sensitive, level) = GetSensitiveVolume(touchable);
177  if (sensitive) {
178  const G4VSolid& solid = *touchable->GetSolid(level);
179  const G4AffineTransform& transform = GetTransform(touchable, level);
180  G4ThreeVector pos = transform.Inverse().TransformPoint(G4ThreeVector(0., 0., 0.));
181  position = GlobalPoint(pos.x() / cm, pos.y() / cm, pos.z() / cm); // mm -> cm
182 
183  G4ThreeVector localPosPre = transform.TransformPoint(globalPosPre);
184  EInside statusPre = solid.Inside(localPosPre);
185  if (statusPre == kSurface) {
186  enter_sensitive = true;
187  G4ThreeVector globalDirPre = step->GetPreStepPoint()->GetMomentumDirection();
188  G4ThreeVector localDirPre = transform.TransformAxis(globalDirPre);
189  G4ThreeVector normalPre = solid.SurfaceNormal(localPosPre);
190  cosThetaPre = normalPre.cosTheta(-localDirPre);
191  }
192 
193  G4ThreeVector localPosPost = transform.TransformPoint(globalPosPost);
194  EInside statusPost = solid.Inside(localPosPost);
195  if (statusPost == kSurface) {
196  leave_sensitive = true;
197  G4ThreeVector globalDirPost = step->GetPostStepPoint()->GetMomentumDirection();
198  G4ThreeVector localDirPost = transform.TransformAxis(globalDirPost);
199  G4ThreeVector normalPost = solid.SurfaceNormal(localPosPost);
200  cosThetaPost = normalPost.cosTheta(localDirPost);
201  }
202  }
203 
204  // update track accounting
205  if (enter_sensitive)
206  m_track.enterDetector(sensitive, position, cosThetaPre);
207  m_track.step(MaterialAccountingStep(length, radiationLengths, energyLoss, globalPositionIn, globalPositionOut));
208  if (leave_sensitive)
209  m_track.leaveDetector(sensitive, cosThetaPost);
210 
211  if (sensitive)
212  LogInfo("TrackingMaterialProducer") << "Track was near sensitive volume " << sensitive->GetName() << std::endl;
213  else
214  LogInfo("TrackingMaterialProducer") << "Track was near non-sensitive volume " << touchable->GetVolume()->GetName()
215  << std::endl;
216  LogInfo("TrackingMaterialProducer") << "Step length: " << length << " cm\n"
217  << "globalPreStep(r,z): (" << globalPositionIn.perp() << ", "
218  << globalPositionIn.z() << ") cm\n"
219  << "globalPostStep(r,z): (" << globalPositionOut.perp() << ", "
220  << globalPositionOut.z() << ") cm\n"
221  << "position(r,z): (" << position.perp() << ", " << position.z() << ") cm\n"
222  << "Radiation lengths: " << radiationLengths << " \t\t(X0: " << X0
223  << " cm)\n"
224  << "Energy loss: " << energyLoss << " MeV \t(Xi: " << Xi
225  << " MeV/cm)\n"
226  << "Track was " << (enter_sensitive ? "entering " : "in none ")
227  << "sensitive volume\n"
228  << "Track was " << (leave_sensitive ? "leaving " : "in none ")
229  << "sensitive volume\n";
230 }
231 
232 //-------------------------------------------------------------------------
234  const G4Track* track = (*event)();
235  if (m_primaryTracks and track->GetParentID() != 0)
236  return;
237 
238  radLen_vs_eta_->Fill(track->GetMomentum().eta(), m_track.summary().radiationLengths());
239  m_tracks->push_back(m_track);
240 
241  // LogInfo
242  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: this track took " << m_track.steps().size()
243  << " steps, and passed through " << m_track.detectors().size()
244  << " sensitive detectors" << std::endl;
245  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: track length: " << m_track.summary().length()
246  << " cm" << std::endl;
247  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: radiation lengths: "
248  << m_track.summary().radiationLengths() << std::endl;
249  LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: energy loss: "
250  << m_track.summary().energyLoss() << " MeV" << std::endl;
251 }
252 
253 //-------------------------------------------------------------------------
255  // transfer ownership to the Event
256  std::unique_ptr<std::vector<MaterialAccountingTrack> > tracks(m_tracks);
257  iEvent.put(std::move(tracks));
258  m_tracks = nullptr;
259 }
260 
261 //-------------------------------------------------------------------------
262 bool TrackingMaterialProducer::isSelected(const G4VTouchable* touchable) {
263  for (size_t i = 0; i < m_selectedVolumes.size(); ++i)
264  if (m_selectedVolumes[i]->IsAncestor(touchable->GetVolume()) or
265  m_selectedVolumes[i] == touchable->GetVolume()->GetLogicalVolume())
266  return true;
267 
268  return false;
269 }
270 
271 //-------------------------------------------------------------------------
272 // define as a plugin
T getParameter(std::string const &) const
#define DEFINE_SIMWATCHER(type)
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:125
T perp() const
Definition: PV3DBase.h:72
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:20
TrackingMaterialProducer(const edm::ParameterSet &)
static const G4AffineTransform & GetTransform(const G4TouchableHistory *touchable, int depth)
int iEvent
Definition: GenABIO.cc:224
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
T z() const
Definition: PV3DBase.h:64
static const G4LogicalVolume * GetVolume(const std::string &name)
static int position[264][3]
Definition: ReadPGInfo.cc:509
step
Definition: StallMonitor.cc:94
static const double X0
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)