File indexing completed on 2024-04-06 12:31:04
0001 #include <iostream> // FIXME: switch to MessagLogger & friends
0002 #include <vector>
0003 #include <string>
0004 #include <cassert>
0005 #include <exception>
0006 #include <tuple>
0007
0008 #include "FWCore/Framework/interface/Event.h"
0009 #include "FWCore/Framework/interface/EventSetup.h"
0010 #include "FWCore/Framework/interface/ESHandle.h"
0011 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0012 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0013
0014 #include "SimG4Core/Notification/interface/BeginOfJob.h"
0015 #include "SimG4Core/Notification/interface/BeginOfEvent.h"
0016 #include "SimG4Core/Notification/interface/BeginOfTrack.h"
0017 #include "SimG4Core/Notification/interface/EndOfTrack.h"
0018
0019 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
0020
0021
0022 #include "G4Step.hh"
0023 #include "G4Track.hh"
0024 #include "G4VSolid.hh"
0025 #include "G4LogicalVolumeStore.hh"
0026 #include "G4TouchableHistory.hh"
0027 #include "G4VPhysicalVolume.hh"
0028 #include "G4AffineTransform.hh"
0029
0030 #include <DD4hep/Filter.h>
0031
0032 #include "TrackingMaterialProducer.h"
0033
0034
0035
0036
0037 #define DEBUG_G4_VOLUMES
0038
0039 using namespace CLHEP;
0040 using edm::LogInfo;
0041
0042
0043 static const G4LogicalVolume* GetVolume(const std::string& name) {
0044 const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
0045
0046 #ifdef DEBUG_G4_VOLUMES
0047 for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume)
0048 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: G4 registered volumes " << (*volume)->GetName()
0049 << std::endl;
0050 #endif
0051
0052 for (G4LogicalVolumeStore::const_iterator volume = lvs->begin(); volume != lvs->end(); ++volume) {
0053 if ((const std::string)(dd4hep::dd::noNamespace((*volume)->GetName())) == name)
0054 return (*volume);
0055 }
0056 return nullptr;
0057 }
0058
0059
0060 static inline const G4AffineTransform& GetTransform(const G4TouchableHistory* touchable, int depth) {
0061 return touchable->GetHistory()->GetTransform(touchable->GetHistory()->GetDepth() - depth);
0062 }
0063
0064
0065
0066
0067
0068
0069
0070 std::tuple<const G4VPhysicalVolume*, int> GetSensitiveVolume(const G4VTouchable* touchable) {
0071 int depth = touchable->GetHistoryDepth();
0072 for (int level = 0; level < depth; ++level) {
0073 const G4VPhysicalVolume* volume = touchable->GetVolume(level);
0074 if (volume->GetLogicalVolume()->GetSensitiveDetector() != nullptr) {
0075 return std::make_tuple(volume, level);
0076 }
0077 }
0078 return std::tuple<const G4VPhysicalVolume*, int>(nullptr, 0);
0079 }
0080
0081
0082 TrackingMaterialProducer::TrackingMaterialProducer(const edm::ParameterSet& iPSet) {
0083 edm::ParameterSet config = iPSet.getParameter<edm::ParameterSet>("TrackingMaterialProducer");
0084 m_selectedNames = config.getParameter<std::vector<std::string> >("SelectedVolumes");
0085 m_primaryTracks = config.getParameter<bool>("PrimaryTracksOnly");
0086 m_txtOutFile = config.getUntrackedParameter<std::string>("txtOutFile");
0087 m_hgcalzfront = config.getParameter<double>("hgcalzfront");
0088 m_tracks = nullptr;
0089 m_track_volume = nullptr;
0090
0091 produces<std::vector<MaterialAccountingTrack> >();
0092 output_file_ = new TFile("radLen_vs_eta_fromProducer.root", "RECREATE");
0093 output_file_->cd();
0094 radLen_vs_eta_ = new TProfile("radLen", "radLen", 250., -5., 5., 0, 10.);
0095
0096
0097 isHGCal = false;
0098
0099 if (std::find(m_selectedNames.begin(), m_selectedNames.end(), "HGCal") != m_selectedNames.end()) {
0100 isHGCal = true;
0101 }
0102
0103 isHFNose = false;
0104 if (std::find(m_selectedNames.begin(), m_selectedNames.end(), "HFNose") != m_selectedNames.end()) {
0105 isHFNose = true;
0106 }
0107 if (isHGCal or isHFNose) {
0108 outVolumeZpositionTxt.open(m_txtOutFile.c_str(), std::ios::out);
0109 }
0110 }
0111
0112
0113 TrackingMaterialProducer::~TrackingMaterialProducer(void) {}
0114
0115
0116 void TrackingMaterialProducer::update(const EndOfJob* event) {
0117 radLen_vs_eta_->Write();
0118 output_file_->Close();
0119 }
0120
0121 void TrackingMaterialProducer::update(const BeginOfJob* event) {
0122
0123 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: List of the selected volumes: " << std::endl;
0124 for (std::vector<std::string>::const_iterator volume_name = m_selectedNames.begin();
0125 volume_name != m_selectedNames.end();
0126 ++volume_name) {
0127 const G4LogicalVolume* volume = GetVolume(*volume_name);
0128 if (volume) {
0129 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: " << *volume_name << std::endl;
0130 m_selectedVolumes.push_back(volume);
0131 } else {
0132
0133 std::cerr << "TrackingMaterialProducer::update(const BeginOfJob*): WARNING: selected volume \"" << *volume_name
0134 << "\" not found in geometry " << std::endl;
0135 }
0136 }
0137 }
0138
0139
0140 void TrackingMaterialProducer::update(const BeginOfEvent* event) {
0141 m_tracks = new std::vector<MaterialAccountingTrack>();
0142 }
0143
0144
0145 void TrackingMaterialProducer::update(const BeginOfTrack* event) {
0146 m_track.reset();
0147 m_track_volume = nullptr;
0148
0149
0150 G4Track* track = const_cast<G4Track*>((*event)());
0151 if (m_primaryTracks and track->GetParentID() != 0) {
0152 track->SetTrackStatus(fStopAndKill);
0153 }
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 if (isHGCal && track->GetTrackStatus() != fStopAndKill && fabs(track->GetMomentum().eta()) > outerHGCalEta &&
0168 fabs(track->GetMomentum().eta()) < innerHGCalEta) {
0169 if (track->GetMomentum().eta() > 0.) {
0170 outVolumeZpositionTxt << "Air " << m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0 << std::endl;
0171 } else if (track->GetMomentum().eta() <= 0.) {
0172 outVolumeZpositionTxt << "Air " << -m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0 << std::endl;
0173 }
0174 }
0175
0176
0177
0178
0179
0180 if (isHFNose && track->GetTrackStatus() != fStopAndKill && fabs(track->GetMomentum().eta()) > outerHFnoseEta &&
0181 fabs(track->GetMomentum().eta()) < innerHFnoseEta) {
0182 if (track->GetMomentum().eta() > 0.) {
0183 outVolumeZpositionTxt << "Polyethylene " << m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0
0184 << std::endl;
0185 } else if (track->GetMomentum().eta() <= 0.) {
0186 outVolumeZpositionTxt << "Polyethylene " << -m_hgcalzfront << " " << 0 << " " << 0 << " " << 0 << " " << 0
0187 << std::endl;
0188 }
0189 }
0190 }
0191
0192 bool TrackingMaterialProducer::isSelectedFast(const G4TouchableHistory* touchable) {
0193 for (int d = touchable->GetHistoryDepth() - 1; d >= 0; --d) {
0194 if (std::find(m_selectedNames.begin(),
0195 m_selectedNames.end(),
0196 (std::string)(dd4hep::dd::noNamespace(touchable->GetVolume(d)->GetName()))) != m_selectedNames.end())
0197 return true;
0198 }
0199 return false;
0200 }
0201
0202
0203 void TrackingMaterialProducer::update(const G4Step* step) {
0204 const G4TouchableHistory* touchable = static_cast<const G4TouchableHistory*>(step->GetTrack()->GetTouchable());
0205 if (not isSelectedFast(touchable)) {
0206 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer:\t[...] skipping "
0207 << touchable->GetVolume()->GetName() << std::endl;
0208 return;
0209 }
0210
0211
0212 const G4Material* material = touchable->GetVolume()->GetLogicalVolume()->GetMaterial();
0213 double length = step->GetStepLength() / cm;
0214 double X0 = material->GetRadlen() / cm;
0215 double Ne = material->GetElectronDensity() * cm3;
0216 double Xi = Ne / 6.0221415e23 * 0.307075 / 2;
0217 double radiationLengths = length / X0;
0218 double energyLoss = length * Xi / 1000.;
0219
0220
0221 G4ThreeVector globalPosPre = step->GetPreStepPoint()->GetPosition();
0222 G4ThreeVector globalPosPost = step->GetPostStepPoint()->GetPosition();
0223 GlobalPoint globalPositionIn(globalPosPre.x() / cm, globalPosPre.y() / cm, globalPosPre.z() / cm);
0224 GlobalPoint globalPositionOut(globalPosPost.x() / cm, globalPosPost.y() / cm, globalPosPost.z() / cm);
0225
0226 G4StepPoint* prePoint = step->GetPreStepPoint();
0227 G4StepPoint* postPoint = step->GetPostStepPoint();
0228 const CLHEP::Hep3Vector& postPos = postPoint->GetPosition();
0229
0230 if (isHGCal or isHFNose) {
0231
0232
0233
0234 if (postPoint->GetStepStatus() == fGeomBoundary && fabs(postPoint->GetMomentum().eta()) > outerHGCalEta &&
0235 fabs(postPoint->GetMomentum().eta()) < innerHGCalEta) {
0236
0237
0238
0239
0240 outVolumeZpositionTxt << prePoint->GetMaterial()->GetName() << " " << postPos.z() << " "
0241 << postPoint->GetMomentum().eta() << " "
0242 << sqrt(postPos.x() * postPos.x() + postPos.y() * postPos.y()) << " " << 0 << " " << 0
0243 << std::endl;
0244 }
0245
0246 if (postPoint->GetStepStatus() == fGeomBoundary && fabs(postPoint->GetMomentum().eta()) > outerHFnoseEta &&
0247 fabs(postPoint->GetMomentum().eta()) < innerHFnoseEta) {
0248 outVolumeZpositionTxt << prePoint->GetMaterial()->GetName() << " " << postPos.z() << " "
0249 << postPoint->GetMomentum().eta() << " "
0250 << sqrt(postPos.x() * postPos.x() + postPos.y() * postPos.y()) << " " << 0 << " " << 0
0251 << std::endl;
0252 }
0253
0254 }
0255
0256
0257 bool enter_sensitive = false;
0258 bool leave_sensitive = false;
0259 double cosThetaPre = 0.0;
0260 double cosThetaPost = 0.0;
0261 int level = 0;
0262 const G4VPhysicalVolume* sensitive = nullptr;
0263 GlobalPoint position;
0264 std::tie(sensitive, level) = GetSensitiveVolume(touchable);
0265 if (sensitive) {
0266 const G4VSolid& solid = *touchable->GetSolid(level);
0267 const G4AffineTransform& transform = GetTransform(touchable, level);
0268 G4ThreeVector pos = transform.Inverse().TransformPoint(G4ThreeVector(0., 0., 0.));
0269 position = GlobalPoint(pos.x() / cm, pos.y() / cm, pos.z() / cm);
0270
0271 G4ThreeVector localPosPre = transform.TransformPoint(globalPosPre);
0272 EInside statusPre = solid.Inside(localPosPre);
0273 if (statusPre == kSurface) {
0274 enter_sensitive = true;
0275 G4ThreeVector globalDirPre = step->GetPreStepPoint()->GetMomentumDirection();
0276 G4ThreeVector localDirPre = transform.TransformAxis(globalDirPre);
0277 G4ThreeVector normalPre = solid.SurfaceNormal(localPosPre);
0278 cosThetaPre = normalPre.cosTheta(-localDirPre);
0279 }
0280
0281 G4ThreeVector localPosPost = transform.TransformPoint(globalPosPost);
0282 EInside statusPost = solid.Inside(localPosPost);
0283 if (statusPost == kSurface) {
0284 leave_sensitive = true;
0285 G4ThreeVector globalDirPost = step->GetPostStepPoint()->GetMomentumDirection();
0286 G4ThreeVector localDirPost = transform.TransformAxis(globalDirPost);
0287 G4ThreeVector normalPost = solid.SurfaceNormal(localPosPost);
0288 cosThetaPost = normalPost.cosTheta(localDirPost);
0289 }
0290 }
0291
0292
0293 if (enter_sensitive) {
0294 if (m_track_volume != nullptr) {
0295 edm::LogWarning("TrackingMaterialProducer") << "Entering volume " << sensitive << " while inside volume "
0296 << m_track_volume << ". Something is inconsistent";
0297 m_track.reset();
0298 }
0299 m_track_volume = sensitive;
0300 m_track.enterDetector(position, cosThetaPre);
0301 }
0302 m_track.step(MaterialAccountingStep(length, radiationLengths, energyLoss, globalPositionIn, globalPositionOut));
0303 if (leave_sensitive) {
0304 if (m_track_volume != sensitive) {
0305 edm::LogWarning("TrackingMaterialProducer") << "Leaving volume " << sensitive << " while inside volume "
0306 << m_track_volume << ". Something is inconsistent";
0307 m_track.reset();
0308 } else
0309 m_track.leaveDetector(cosThetaPost);
0310 m_track_volume = nullptr;
0311 }
0312 if (sensitive)
0313 LogInfo("TrackingMaterialProducer") << "Track was near sensitive volume " << sensitive->GetName() << std::endl;
0314 else
0315 LogInfo("TrackingMaterialProducer") << "Track was near non-sensitive volume " << touchable->GetVolume()->GetName()
0316 << std::endl;
0317 LogInfo("TrackingMaterialProducer") << "Step length: " << length << " cm\n"
0318 << "globalPreStep(r,z): (" << globalPositionIn.perp() << ", "
0319 << globalPositionIn.z() << ") cm\n"
0320 << "globalPostStep(r,z): (" << globalPositionOut.perp() << ", "
0321 << globalPositionOut.z() << ") cm\n"
0322 << "position(r,z): (" << position.perp() << ", " << position.z() << ") cm\n"
0323 << "Radiation lengths: " << radiationLengths << " \t\t(X0: " << X0
0324 << " cm)\n"
0325 << "Energy loss: " << energyLoss << " MeV \t(Xi: " << Xi
0326 << " MeV/cm)\n"
0327 << "Track was " << (enter_sensitive ? "entering " : "in none ")
0328 << "sensitive volume\n"
0329 << "Track was " << (leave_sensitive ? "leaving " : "in none ")
0330 << "sensitive volume\n";
0331 }
0332
0333
0334 void TrackingMaterialProducer::update(const EndOfTrack* event) {
0335 const G4Track* track = (*event)();
0336 if (m_primaryTracks and track->GetParentID() != 0)
0337 return;
0338
0339 radLen_vs_eta_->Fill(track->GetMomentum().eta(), m_track.summary().radiationLengths());
0340 m_tracks->push_back(m_track);
0341
0342
0343 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: this track took " << m_track.steps().size()
0344 << " steps, and passed through " << m_track.detectors().size()
0345 << " sensitive detectors" << std::endl;
0346 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: track length: " << m_track.summary().length()
0347 << " cm" << std::endl;
0348 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: radiation lengths: "
0349 << m_track.summary().radiationLengths() << std::endl;
0350 LogInfo("TrackingMaterialProducer") << "TrackingMaterialProducer: energy loss: "
0351 << m_track.summary().energyLoss() << " MeV" << std::endl;
0352 }
0353
0354
0355 void TrackingMaterialProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0356
0357 std::unique_ptr<std::vector<MaterialAccountingTrack> > tracks(m_tracks);
0358 iEvent.put(std::move(tracks));
0359 m_tracks = nullptr;
0360 }
0361
0362
0363 bool TrackingMaterialProducer::isSelected(const G4VTouchable* touchable) {
0364 for (size_t i = 0; i < m_selectedVolumes.size(); ++i)
0365 if (m_selectedVolumes[i]->IsAncestor(touchable->GetVolume()) or
0366 m_selectedVolumes[i] == touchable->GetVolume()->GetLogicalVolume())
0367 return true;
0368
0369 return false;
0370 }
0371
0372
0373
0374 #include "SimG4Core/Watcher/interface/SimWatcherFactory.h"
0375 #include "FWCore/Framework/interface/MakerMacros.h"
0376 DEFINE_SIMWATCHER(TrackingMaterialProducer);