diff --git a/DDCore/include/DD4hep/Segmentations.h b/DDCore/include/DD4hep/Segmentations.h index 245af1ca227e3cfaedc5ceea4b5aa7642d664a17..c775e39b420104671612f265ef965de7c5ba0c92 100644 --- a/DDCore/include/DD4hep/Segmentations.h +++ b/DDCore/include/DD4hep/Segmentations.h @@ -93,6 +93,11 @@ namespace dd4hep { * \return vector<double> in natural order of dimensions, e.g., dx/dy/dz, or dr/r*dPhi */ std::vector<double> cellDimensions(const CellID& cellID) const; + /// Return true if this segmentation can have cells that span multiple + /// volumes. That is, points from multiple distinct volumes may + /// be assigned to the same cell. + /// In that case, a working volumeID() implementation is required. + bool cellsSpanVolumes() const; /// Access to the base DDSegmentation object. WARNING: Deprecated call! DDSegmentation::Segmentation* segmentation() const; diff --git a/DDCore/include/DDSegmentation/Segmentation.h b/DDCore/include/DDSegmentation/Segmentation.h index b2da572ba3a3dbdb656df6fcc4a4583929e02ce6..e4a39a7dcf9af4dc568446f3127e2eed2d3e0b6a 100644 --- a/DDCore/include/DDSegmentation/Segmentation.h +++ b/DDCore/include/DDSegmentation/Segmentation.h @@ -127,6 +127,14 @@ namespace dd4hep { \return vector<double> in natural order of dimensions, e.g., dx/dy/dz, or dr/r*dPhi */ virtual std::vector<double> cellDimensions(const CellID& cellID) const; + /// Return true if this segmentation can have cells that span multiple + /// volumes. That is, points from multiple distinct volumes may + /// be assigned to the same cell. + /// In that case, a working volumeID() implementation is required. + virtual bool cellsSpanVolumes() const + { + return false; + } protected: /// Default constructor used by derived classes passing the encoding string diff --git a/DDCore/src/Segmentations.cpp b/DDCore/src/Segmentations.cpp index 4d36775dee6185840eacf08e3e9fde17d09526a4..7b1de46fef8f9f949b6a78b77e49b58b439e20b1 100644 --- a/DDCore/src/Segmentations.cpp +++ b/DDCore/src/Segmentations.cpp @@ -95,6 +95,14 @@ std::vector<double> Segmentation::cellDimensions(const CellID& cell) const { return access()->segmentation->cellDimensions(cell); } +/// Return true if this segmentation can have cells that span multiple +/// volumes. That is, points from multiple distinct volumes may +/// be assigned to the same cell. +bool Segmentation::cellsSpanVolumes() const +{ + return access()->segmentation->cellsSpanVolumes(); +} + /// Access to the base DDSegmentation object. WARNING: Deprecated call! DDSegmentation::Segmentation* Segmentation::segmentation() const { return access()->segmentation; diff --git a/DDG4/plugins/Geant4SDActions.cpp b/DDG4/plugins/Geant4SDActions.cpp index c3b734e55c4b79018a173e001c0cb48afc07e5be..0338fb9b15a76529fb1e9eb51e3332afabb57e5a 100644 --- a/DDG4/plugins/Geant4SDActions.cpp +++ b/DDG4/plugins/Geant4SDActions.cpp @@ -27,7 +27,58 @@ namespace dd4hep { namespace { struct Geant4VoidSensitive {}; + + /// Common code to handle the creation of a calorimeter hit. + template <class HANDLER> + void handleCalorimeterHit (VolumeID cell, + const HitContribution& contrib, + Geant4HitCollection& coll, + const HANDLER& h, + const Geant4Sensitive& sd, + const Segmentation& segmentation) + { + typedef Geant4Calorimeter::Hit Hit; + Hit* hit = coll.findByKey<Hit>(cell); + if ( !hit ) { + DDSegmentation::Vector3D pos = segmentation.position(cell); + Position global; + + // Convert the position relative to the local readout volume + // to a global position. + if (!segmentation.cellsSpanVolumes()) { + global = h.localToGlobal(pos); + } + else { + // The segmentation can gang together multiple volumes. + // In this case, we can't use the transformation we get from + // the step --- the volume that actually contains the hit + // may not be the same volume that the segmentation uses + // for the local coordinate system. We need to get the + // actual volID used from the segmentation and then look + // it up the volume manager to get the proper transformation. + VolumeID volID = segmentation.volumeID(cell); + VolumeManager vman = VolumeManager::getVolumeManager(sd.detectorDescription()); + VolumeManagerContext* vc = vman.lookupContext(volID); + // explicit unit conversion; h.localToGlobal does it internally already + global = vc->localToWorld(Position(pos)) / dd4hep::mm; + } + hit = new Hit(global); + hit->cellID = cell; + coll.add(cell, hit); + Geant4TouchableHandler handler(h.touchable()); + sd.printM2("%s> CREATE hit with deposit:%e MeV Pos:%8.2f %8.2f %8.2f %s [%s]", + sd.c_name(),contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str(), + coll.GetName().c_str()); + if ( 0 == hit->cellID ) { // for debugging only! + hit->cellID = cell; + sd.except("+++ Invalid CELL ID for hit!"); + } + } + hit->truth.emplace_back(contrib); + hit->energyDeposit += contrib.deposit; + } } + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Geant4SensitiveAction<Geant4VoidSensitive> // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -250,25 +301,7 @@ namespace dd4hep { return true; } - //Hit* hit = coll->find<Hit>(CellIDCompare<Hit>(cell)); - Hit* hit = coll->findByKey<Hit>(cell); - if ( !hit ) { - Geant4TouchableHandler handler(step); - DDSegmentation::Vector3D pos = m_segmentation.position(cell); - Position global = h.localToGlobal(pos); - hit = new Hit(global); - hit->cellID = cell; - coll->add(cell, hit); - printM2("%s> CREATE hit with deposit:%e MeV Pos:%8.2f %8.2f %8.2f %s [%s]", - c_name(),contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str(), - coll->GetName().c_str()); - if ( 0 == hit->cellID ) { // for debugging only! - hit->cellID = cellID(step); - except("+++ Invalid CELL ID for hit!"); - } - } - hit->truth.emplace_back(contrib); - hit->energyDeposit += contrib.deposit; + handleCalorimeterHit(cell, contrib, *coll, h, *this, m_segmentation); mark(h.track); return true; } @@ -294,24 +327,7 @@ namespace dd4hep { std::cout << out.str(); return true; } - Hit* hit = coll->findByKey<Hit>(cell); - if ( !hit ) { - Geant4TouchableHandler handler(h.touchable()); - DDSegmentation::Vector3D pos = m_segmentation.position(cell); - Position global = h.localToGlobal(pos); - hit = new Hit(global); - hit->cellID = cell; - coll->add(cell, hit); - printM2("%s> CREATE hit with deposit:%e MeV Pos:%8.2f %8.2f %8.2f %s [%s]", - c_name(),contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str(), - coll->GetName().c_str()); - if ( 0 == hit->cellID ) { // for debugging only! - hit->cellID = cellID(h.touchable(), h.avgPositionG4()); - except("+++ Invalid CELL ID for hit!"); - } - } - hit->truth.emplace_back(contrib); - hit->energyDeposit += contrib.deposit; + handleCalorimeterHit(cell, contrib, *coll, h, *this, m_segmentation); mark(h.track); return true; } @@ -462,23 +478,7 @@ namespace dd4hep { std::cout << out.str(); return true; } - Hit* hit = coll->findByKey<Hit>(cell); - if ( !hit ) { - Geant4TouchableHandler handler(step); - DDSegmentation::Vector3D pos = m_segmentation.position(cell); - Position global = h.localToGlobal(pos); - hit = new Hit(global); - hit->cellID = cell; - coll->add(cell, hit); - printM2("CREATE hit with deposit:%e MeV Pos:%8.2f %8.2f %8.2f %s", - contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str()); - if ( 0 == hit->cellID ) { // for debugging only! - hit->cellID = cellID(step); - except("+++ Invalid CELL ID for hit!"); - } - } - hit->truth.emplace_back(contrib); - hit->energyDeposit += contrib.deposit; + handleCalorimeterHit(cell, contrib, *coll, h, *this, m_segmentation); mark(h.track); return true; } @@ -505,23 +505,7 @@ namespace dd4hep { std::cout << out.str(); return true; } - Hit* hit = coll->findByKey<Hit>(cell); - if ( !hit ) { - Geant4TouchableHandler handler(h.touchable()); - DDSegmentation::Vector3D pos = m_segmentation.position(cell); - Position global = h.localToGlobal(pos); - hit = new Hit(global); - hit->cellID = cell; - coll->add(cell, hit); - printM2("CREATE hit with deposit:%e MeV Pos:%8.2f %8.2f %8.2f %s", - contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str()); - if ( 0 == hit->cellID ) { // for debugging only! - hit->cellID = cellID(h.touchable(), h.avgPositionG4()); - except("+++ Invalid CELL ID for hit!"); - } - } - hit->truth.emplace_back(contrib); - hit->energyDeposit += contrib.deposit; + handleCalorimeterHit(cell, contrib, *coll, h, *this, m_segmentation); mark(h.track); return true; }