File indexing completed on 2026-10-05 08:17:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/Printout.h>
0016 #include <DD4hep/Primitives.h>
0017 #include <DD4hep/InstanceCount.h>
0018
0019 #include <DDG4/Geant4Kernel.h>
0020 #include <DDG4/Geant4Mapping.h>
0021 #include <DDG4/Geant4StepHandler.h>
0022 #include <DDG4/Geant4SensDetAction.h>
0023 #include <DDG4/Geant4VolumeManager.h>
0024 #include <DDG4/Geant4MonteCarloTruth.h>
0025
0026
0027 #include <G4Step.hh>
0028 #include <G4SDManager.hh>
0029 #include <G4VSensitiveDetector.hh>
0030
0031
0032 #include <stdexcept>
0033
0034 #include "G4OpticalParameters.hh"
0035 #include "G4OpticalPhoton.hh"
0036
0037 #ifdef DD4HEP_USE_GEANT4_UNITS
0038 #define MM_2_CM 1.0
0039 #else
0040 #define MM_2_CM 0.1
0041 #endif
0042
0043 namespace dd4hep {
0044 namespace sim {
0045
0046 void _print_volumeid(const std::string& tag, const IDDescriptor& id, DDSegmentation::VolumeID volID) {
0047 if( id.isValid() ) {
0048 std::string value = id.str(volID);
0049 printout(ALWAYS, tag, "Volume ID: %016llX -> %s", volID, value.c_str());
0050 return;
0051 }
0052 printout(ALWAYS, tag, "Volume ID: %016llX [no ID descriptor]", volID);
0053 }
0054
0055
0056 void _print_volumeid(const Geant4Sensitive* action, const char* tag, DDSegmentation::VolumeID volID, double ene=-1e0) {
0057 SensitiveDetector sensitive = action->sensitiveDetector();
0058 char text[64];
0059 text[0] = 0;
0060 if( ene > 0e0 ) {
0061 ::snprintf(text, sizeof(text), "Deposit: %12.3e GeV", ene/1e9);
0062 }
0063 if( sensitive.isValid() ) {
0064 Readout readout = sensitive.readout();
0065 if( readout.isValid() ) {
0066 IDDescriptor id = readout.idSpec();
0067 if( id.isValid() ) {
0068 std::string value = id.str(volID);
0069 action->always("%-16s %016llX -> %s %s", tag, volID, value.c_str(), text);
0070 return;
0071 }
0072 action->always("%-16s %016llX -> Readout: %s [no ID descriptor] %s", tag, volID, readout.name(), text);
0073 return;
0074 }
0075 action->always("%-16s %016llX -> Sensitive: %s [no readout] %s", volID, sensitive.name(), text);
0076 return;
0077 }
0078 action->always("%-16s %016llX [internal error: no sensitive detectector] %s", volID, text);
0079 }
0080 }
0081 }
0082
0083 using namespace dd4hep::sim;
0084
0085 namespace {
0086
0087 #if 0
0088 Geant4ActionSD* _getSensitiveDetector(const std::string& name) {
0089 G4SDManager* mgr = G4SDManager::GetSDMpointer();
0090 G4VSensitiveDetector* sd = mgr->FindSensitiveDetector(name);
0091 if (0 == sd) {
0092 dd4hep::except("Geant4Sensitive", "DDG4: You requested to configure actions "
0093 "for the sensitive detector %s,\nDDG4: which is not known to Geant4. "
0094 "Are you sure you already converted the geometry?", name.c_str());
0095 }
0096 Geant4ActionSD* action_sd = dynamic_cast<Geant4ActionSD*>(sd);
0097 if (0 == action_sd) {
0098 throw dd4hep::except("Geant4Sensitive", "DDG4: You may only configure actions "
0099 "for sensitive detectors of type Geant4ActionSD.\n"
0100 "DDG4: The sensitive detector of %s is of type %s, which is incompatible.", name.c_str(),
0101 typeName(typeid(*sd)).c_str());
0102 }
0103 return action_sd;
0104 }
0105 #endif
0106 }
0107
0108
0109 Geant4ActionSD::Geant4ActionSD(const std::string& nam)
0110 : Geant4Action(0, nam) {
0111 InstanceCount::increment(this);
0112 }
0113
0114
0115 Geant4ActionSD::~Geant4ActionSD() {
0116 InstanceCount::decrement(this);
0117 }
0118
0119
0120 Geant4Filter::Geant4Filter(Geant4Context* ctxt, const std::string& nam)
0121 : Geant4Action(ctxt, nam) {
0122 InstanceCount::increment(this);
0123 }
0124
0125
0126 Geant4Filter::~Geant4Filter() {
0127 InstanceCount::decrement(this);
0128 }
0129
0130
0131 bool Geant4Filter::operator()(const G4Step*) const {
0132 return true;
0133 }
0134
0135
0136 bool Geant4Filter::operator()(const Geant4FastSimSpot*) const {
0137 except("The filter action %s does not support the GFLASH/FastSim interface for Geant4.", c_name());
0138 return false;
0139 }
0140
0141
0142 Geant4Sensitive::Geant4Sensitive(Geant4Context* ctxt, const std::string& nam, DetElement det, Detector& det_ref)
0143 : Geant4Action(ctxt, nam), m_detDesc(det_ref), m_detector(det)
0144 {
0145 InstanceCount::increment(this);
0146 if (!det.isValid()) {
0147 except("DDG4: Detector element for %s is invalid.", nam.c_str());
0148 }
0149 declareProperty("UseVolumeManager", m_useVolumeManager = true);
0150 declareProperty("HitCreationMode", m_hitCreationMode = SIMPLE_MODE);
0151 declareProperty("DebugVolumeID", m_debugVolumeID = false);
0152 m_sequence = context()->kernel().sensitiveAction(m_detector.name());
0153 m_sensitive = m_detDesc.sensitiveDetector(det.name());
0154 m_readout = m_sensitive.readout();
0155 m_segmentation = m_readout.segmentation();
0156 }
0157
0158
0159 Geant4Sensitive::~Geant4Sensitive() {
0160 m_filters(&Geant4Filter::release);
0161 m_filters.clear();
0162 InstanceCount::decrement(this);
0163 }
0164
0165
0166 int Geant4Sensitive::id() const {
0167 return this->m_detector.id();
0168 }
0169
0170
0171 void Geant4Sensitive::adoptFilter(Geant4Action* action) {
0172 Geant4Filter* filter = dynamic_cast<Geant4Filter*>(action);
0173 adopt(filter);
0174 }
0175
0176
0177 void Geant4Sensitive::adopt(Geant4Filter* filter) {
0178 if (filter) {
0179 filter->addRef();
0180 m_filters.add(filter);
0181 return;
0182 }
0183 except("Attempt to add invalid sensitive filter!");
0184 }
0185
0186
0187 void Geant4Sensitive::adoptFilter_front(Geant4Action* action) {
0188 Geant4Filter* filter = dynamic_cast<Geant4Filter*>(action);
0189 adopt_front(filter);
0190 }
0191
0192
0193 void Geant4Sensitive::adopt_front(Geant4Filter* filter) {
0194 if (filter) {
0195 filter->addRef();
0196 m_filters.add_front(filter);
0197 return;
0198 }
0199 except("Attempt to add invalid sensitive filter!");
0200 }
0201
0202
0203 bool Geant4Sensitive::accept(const G4Step* step) const {
0204 bool (Geant4Filter::*filter)(const G4Step*) const = &Geant4Filter::operator();
0205 bool result = m_filters.filter(filter, step);
0206 return result;
0207 }
0208
0209
0210 bool Geant4Sensitive::accept(const Geant4FastSimSpot* spot) const {
0211 bool (Geant4Filter::*filter)(const Geant4FastSimSpot*) const = &Geant4Filter::operator();
0212 bool result = m_filters.filter(filter, spot);
0213 return result;
0214 }
0215
0216
0217 void Geant4Sensitive::setDetector(Geant4ActionSD* sens_det) {
0218 m_sensitiveDetector = sens_det;
0219 }
0220
0221
0222 Geant4ActionSD& Geant4Sensitive::detector() const {
0223 if (m_sensitiveDetector)
0224 return *m_sensitiveDetector;
0225
0226
0227 except("DDG4: The sensitive detector for action %s was not properly configured.", name().c_str());
0228 throw std::runtime_error("Geant4Sensitive::detector");
0229 }
0230
0231
0232 Geant4SensDetActionSequence& Geant4Sensitive::sequence() const {
0233 return *m_sequence;
0234 }
0235
0236
0237 dd4hep::Detector& Geant4Sensitive::detectorDescription() const {
0238 return m_detDesc;
0239 }
0240
0241
0242 const std::string& Geant4Sensitive::hitCollectionName(std::size_t which) const {
0243 return sequence().hitCollectionName(which);
0244 }
0245
0246
0247 Geant4HitCollection* Geant4Sensitive::collection(std::size_t which) {
0248 return sequence().collection(which);
0249 }
0250
0251
0252 Geant4HitCollection* Geant4Sensitive::collectionByID(std::size_t id) {
0253 return sequence().collectionByID(id);
0254 }
0255
0256
0257 void Geant4Sensitive::defineCollections() {
0258 }
0259
0260
0261 void Geant4Sensitive::begin(G4HCofThisEvent* ) {
0262 }
0263
0264
0265 void Geant4Sensitive::end(G4HCofThisEvent* ) {
0266 }
0267
0268
0269 bool Geant4Sensitive::process(const G4Step* , G4TouchableHistory* ) {
0270 return false;
0271 }
0272
0273
0274 bool Geant4Sensitive::processFastSim(const Geant4FastSimSpot* , G4TouchableHistory* ) {
0275 except("The sensitive action %s does not support the GFLASH/FastSim interface for Geant4.", c_name());
0276 return false;
0277 }
0278
0279
0280 void Geant4Sensitive::clear(G4HCofThisEvent* ) {
0281 }
0282
0283
0284 void Geant4Sensitive::mark(const G4Track* track) const {
0285 Geant4MonteCarloTruth* truth = context()->event().extension<Geant4MonteCarloTruth>(false);
0286 if ( truth ) truth->mark(track);
0287 }
0288
0289
0290 void Geant4Sensitive::mark(const G4Step* step) const {
0291 Geant4MonteCarloTruth* truth = context()->event().extension<Geant4MonteCarloTruth>(false);
0292 if ( truth ) truth->mark(step);
0293 }
0294
0295
0296 long long int Geant4Sensitive::volumeID(const G4Step* step) {
0297 VolumeID volID = m_detector.id();
0298 if( this->useVolumeManager() ) {
0299 Geant4StepHandler stepH(step);
0300 Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager();
0301 volID = volMgr.volumeID(stepH.preTouchable());
0302 if( this->m_debugVolumeID ) {
0303 _print_volumeid(this, "Volume ID", volID, step->GetTotalEnergyDeposit());
0304 }
0305 }
0306 return volID;
0307 }
0308
0309
0310 long long int Geant4Sensitive::volumeID(const G4VTouchable* touchable) {
0311 VolumeID volID = m_detector.id();
0312 if( this->useVolumeManager() ) {
0313 Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager();
0314 volID= volMgr.volumeID(touchable);
0315 if( this->m_debugVolumeID ) {
0316 _print_volumeid(this, "Volume ID", volID);
0317 }
0318 }
0319 return volID;
0320 }
0321
0322
0323 long long int Geant4Sensitive::cellID(const G4Step* step) {
0324 VolumeID volID = m_detector.id();
0325 if( this->useVolumeManager() ) {
0326 Geant4StepHandler h(step);
0327 Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager();
0328 bool UsePostStepOnly = G4OpticalParameters::Instance() &&
0329 G4OpticalParameters::Instance()->GetBoundaryInvokeSD() &&
0330 (step->GetTrack()->GetDefinition() == G4OpticalPhoton::Definition());
0331
0332 volID = volMgr.volumeID(UsePostStepOnly? h.postTouchable() : h.preTouchable());
0333 if ( m_segmentation.isValid() ) {
0334 std::exception_ptr eptr;
0335 G4ThreeVector global = UsePostStepOnly? h.postPosG4() : 0.5 * (h.prePosG4()+h.postPosG4());
0336 G4ThreeVector local = UsePostStepOnly? h.postTouchable()->GetHistory()->GetTopTransform().TransformPoint(global) :
0337 h.preTouchable()->GetHistory()->GetTopTransform().TransformPoint(global);
0338 Position loc(local.x()*MM_2_CM, local.y()*MM_2_CM, local.z()*MM_2_CM);
0339 Position glob(global.x()*MM_2_CM, global.y()*MM_2_CM, global.z()*MM_2_CM);
0340 try {
0341 VolumeID cID = m_segmentation.cellID(loc, glob, volID);
0342 if( this->m_debugVolumeID ) {
0343 _print_volumeid(this, "Cell ID", cID, step->GetTotalEnergyDeposit());
0344 }
0345 return cID;
0346 }
0347 catch(const std::exception& e) {
0348 eptr = std::current_exception();
0349 error("cellID: failed to access segmentation for VolumeID: %016lX [%ld] [%s]", volID, volID, e.what());
0350 error("....... G4-local: (%f, %f, %f) G4-global: (%f, %f, %f)",
0351 local.x(), local.y(), local.z(), global.x(), global.y(), global.z());
0352 error("....... TGeo-local: (%f, %f, %f) TGeo-global: (%f, %f, %f)",
0353 loc.x(), loc.y(), loc.z(), glob.x(), glob.y(), glob.z());
0354 error("....... Pre-step: %s SD: %s", h.volName(h.pre), h.sdName(h.pre).c_str());
0355 if ( h.post )
0356 error("....... Post-step: %s SD: %s", h.volName(h.post), h.sdName(h.post).c_str());
0357 std::rethrow_exception(std::move(eptr));
0358 }
0359 }
0360 else if( this->m_debugVolumeID ) {
0361 _print_volumeid(this, "Volume ID", volID, step->GetTotalEnergyDeposit());
0362 }
0363 }
0364 return volID;
0365 }
0366
0367
0368 long long int Geant4Sensitive::cellID(const G4VTouchable* touchable, const G4ThreeVector& global) {
0369 VolumeID volID = m_detector.id();
0370 if( this->useVolumeManager() ) {
0371 Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager();
0372
0373 volID = volMgr.volumeID(touchable);
0374 if ( m_segmentation.isValid() ) {
0375 std::exception_ptr eptr;
0376 G4ThreeVector local = touchable->GetHistory()->GetTopTransform().TransformPoint(global);
0377 Position loc (local.x()*MM_2_CM, local.y()*MM_2_CM, local.z()*MM_2_CM);
0378 Position glob(global.x()*MM_2_CM, global.y()*MM_2_CM, global.z()*MM_2_CM);
0379 try {
0380 VolumeID cID = m_segmentation.cellID(loc, glob, volID);
0381 if( this->m_debugVolumeID ) {
0382 _print_volumeid(this, "Cell ID", cID);
0383 }
0384 return cID;
0385 }
0386 catch(const std::exception& e) {
0387 auto* pvol = touchable->GetVolume();
0388 auto* vol = pvol->GetLogicalVolume();
0389 auto* sd = vol->GetSensitiveDetector();
0390 eptr = std::current_exception();
0391 error("cellID: failed to access segmentation for VolumeID: %016lX [%ld] [%s]", volID, volID, e.what());
0392 error("....... G4-local: (%f, %f, %f) G4-global: (%f, %f, %f)",
0393 local.x(), local.y(), local.z(), global.x(), global.y(), global.z());
0394 error("....... TGeo-local: (%f, %f, %f) TGeo-global: (%f, %f, %f)",
0395 loc.x(), loc.y(), loc.z(), glob.x(), glob.y(), glob.z());
0396 error("....... Touchable: %s SD: %s", vol->GetName().c_str(), sd ? sd->GetName().c_str() : "???");
0397 std::rethrow_exception(std::move(eptr));
0398 }
0399 }
0400 else if( this->m_debugVolumeID ) {
0401 _print_volumeid(this, "Volume ID", volID);
0402 }
0403 }
0404 return volID;
0405 }
0406
0407
0408 Geant4SensDetActionSequence::Geant4SensDetActionSequence(Geant4Context* ctxt, const std::string& nam)
0409 : Geant4Action(ctxt, nam), m_hce(0), m_detector(0)
0410 {
0411 m_needsControl = true;
0412 context()->sensitiveActions().insert(name(), this);
0413
0414 m_sensitive = context()->detectorDescription().sensitiveDetector(nam);
0415 m_sensitiveType = m_sensitive.type();
0416 declareProperty("SensitiveType", m_sensitiveType);
0417 InstanceCount::increment(this);
0418 }
0419
0420
0421 Geant4SensDetActionSequence::~Geant4SensDetActionSequence() {
0422 m_filters(&Geant4Filter::release);
0423 m_actors(&Geant4Sensitive::release);
0424 m_filters.clear();
0425 m_actors.clear();
0426 InstanceCount::decrement(this);
0427 }
0428
0429
0430 void Geant4SensDetActionSequence::updateContext(Geant4Context* ctxt) {
0431 m_context = ctxt;
0432 m_actors.updateContext(ctxt);
0433 m_filters.updateContext(ctxt);
0434 }
0435
0436
0437 void Geant4SensDetActionSequence::adoptFilter(Geant4Action* action) {
0438 Geant4Filter* filter = dynamic_cast<Geant4Filter*>(action);
0439 adopt(filter);
0440 }
0441
0442
0443 void Geant4SensDetActionSequence::adopt(Geant4Sensitive* sensitive) {
0444 if (sensitive) {
0445 sensitive->addRef();
0446 m_actors.add(sensitive);
0447 return;
0448 }
0449 except("Attempt to add invalid sensitive actor!");
0450 }
0451
0452
0453 void Geant4SensDetActionSequence::adopt(Geant4Filter* filter) {
0454 if (filter) {
0455 filter->addRef();
0456 m_filters.add(filter);
0457 return;
0458 }
0459 except("Attempt to add invalid sensitive filter!");
0460 }
0461
0462
0463 std::size_t Geant4SensDetActionSequence::defineCollection(Geant4Sensitive* owner, const std::string& collection_name, create_t func) {
0464 m_collections.emplace_back(collection_name, make_pair(owner,func));
0465 return m_collections.size() - 1;
0466 }
0467
0468
0469 std::size_t Geant4SensDetActionSequence::Geant4SensDetActionSequence::defineCollections(Geant4ActionSD* sens_det) {
0470 std::size_t count = 0;
0471 m_detector = sens_det;
0472 m_actors(&Geant4Sensitive::setDetector, sens_det);
0473 m_actors(&Geant4Sensitive::defineCollections);
0474 for (HitCollections::const_iterator i = m_collections.begin(); i != m_collections.end(); ++i) {
0475 sens_det->defineCollection((*i).first);
0476 ++count;
0477 }
0478 return count;
0479 }
0480
0481
0482 const std::string& Geant4SensDetActionSequence::hitCollectionName(std::size_t which) const {
0483 if (which < m_collections.size()) {
0484 return m_collections[which].first;
0485 }
0486 static std::string blank = "";
0487 except("The collection name index for subdetector %s is out of range!", c_name());
0488 return blank;
0489 }
0490
0491
0492 Geant4HitCollection* Geant4SensDetActionSequence::collection(std::size_t which) const {
0493 if (which < m_collections.size()) {
0494 int hc_id = m_detector->GetCollectionID(which);
0495 Geant4HitCollection* c = (Geant4HitCollection*) m_hce->GetHC(hc_id);
0496 if (c)
0497 return c;
0498 except("The collection index for subdetector %s is wrong!", c_name());
0499 }
0500 except("The collection name index for subdetector %s is out of range!", c_name());
0501 return 0;
0502 }
0503
0504
0505 Geant4HitCollection* Geant4SensDetActionSequence::collectionByID(std::size_t id) const {
0506 Geant4HitCollection* c = (Geant4HitCollection*) m_hce->GetHC(id);
0507 if (c)
0508 return c;
0509 except("The collection index for subdetector %s is wrong!", c_name());
0510 return 0;
0511 }
0512
0513
0514 bool Geant4SensDetActionSequence::accept(const G4Step* step) const {
0515 bool (Geant4Filter::*filter)(const G4Step*) const = &Geant4Filter::operator();
0516 bool result = m_filters.filter(filter, step);
0517 return result;
0518 }
0519
0520
0521 bool Geant4SensDetActionSequence::accept(const Geant4FastSimSpot* spot) const {
0522 bool (Geant4Filter::*filter)(const Geant4FastSimSpot*) const = &Geant4Filter::operator();
0523 bool result = m_filters.filter(filter, spot);
0524 return result;
0525 }
0526
0527
0528 bool Geant4SensDetActionSequence::process(const G4Step* step, G4TouchableHistory* history) {
0529 bool result = false;
0530 for (Geant4Sensitive* sensitive : m_actors) {
0531 if ( sensitive->accept(step) )
0532 result |= sensitive->process(step, history);
0533 }
0534 m_process(step, history);
0535 return result;
0536 }
0537
0538
0539 bool Geant4SensDetActionSequence::processFastSim(const Geant4FastSimSpot* spot, G4TouchableHistory* history) {
0540 bool result = false;
0541 for (Geant4Sensitive* sensitive : m_actors) {
0542 if ( sensitive->accept(spot) )
0543 result |= sensitive->processFastSim(spot, history);
0544 }
0545 m_process(spot, history);
0546 return result;
0547 }
0548
0549
0550
0551
0552
0553 void Geant4SensDetActionSequence::begin(G4HCofThisEvent* hce) {
0554 m_hce = hce;
0555 for (std::size_t count = 0; count < m_collections.size(); ++count) {
0556 const HitCollection& cr = m_collections[count];
0557 Geant4HitCollection* col = (*cr.second.second)(name(), cr.first, cr.second.first);
0558 int id = m_detector->GetCollectionID(count);
0559 m_hce->AddHitsCollection(id, col);
0560 }
0561 m_actors(&Geant4Sensitive::begin, m_hce);
0562 m_begin (m_hce);
0563 }
0564
0565
0566 void Geant4SensDetActionSequence::end(G4HCofThisEvent* hce) {
0567 m_end(hce);
0568 m_actors(&Geant4Sensitive::end, hce);
0569
0570 }
0571
0572
0573
0574
0575
0576
0577
0578 void Geant4SensDetActionSequence::clear() {
0579 m_clear (m_hce);
0580 m_actors(&Geant4Sensitive::clear, m_hce);
0581 }
0582
0583
0584 Geant4SensDetSequences::~Geant4SensDetSequences() {
0585 detail::releaseObjects(m_sequences);
0586 m_sequences.clear();
0587 }
0588
0589
0590 Geant4SensDetActionSequence* Geant4SensDetSequences::operator[](const std::string& nam) const {
0591 std::string n = "SD_Seq_" + nam;
0592 Members::const_iterator i = m_sequences.find(n);
0593 if (i != m_sequences.end())
0594 return (*i).second;
0595 except("Attempt to access undefined SensDetActionSequence: %s ", nam.c_str());
0596 return nullptr;
0597 }
0598
0599
0600 Geant4SensDetActionSequence* Geant4SensDetSequences::find(const std::string& name) const {
0601 std::string nam = "SD_Seq_" + name;
0602 Members::const_iterator i = m_sequences.find(nam);
0603 if (i != m_sequences.end())
0604 return (*i).second;
0605 return 0;
0606 }
0607
0608
0609 void Geant4SensDetSequences::insert(const std::string& name, Geant4SensDetActionSequence* seq) {
0610 if (seq) {
0611 std::string nam = "SD_Seq_" + name;
0612 seq->addRef();
0613 m_sequences[nam] = seq;
0614 return;
0615 }
0616 except("Attempt to add invalid sensitive sequence with name:%s", name.c_str());
0617 }
0618
0619
0620 void Geant4SensDetSequences::clear() {
0621 m_sequences.clear();
0622 }