Skip to content

Commit

Permalink
Handle ganged segmentations.
Browse files Browse the repository at this point in the history
Some segmentations can gang together regions from multiple volumes (such
as the Allegro ECal).  In the calorimeter implementations
of Geant4SensitiveAction, we were finding the hit position by first
getting the local position from the segmentation, then converting
to a global position using the transform obtained from the step.
But if multiple volumes are ganged, this may not be correct:
the volume which actually contains the hit may not be the same one
which the segmentation used for its local coordinate system.
In this case, we need to instead find the volID to use from
the segmentation and get the transformation by looking it up
in the volume manager.

However, not all segmentations properly implement the volumeID method
needed for this, so this has to be opt-in.  We add an isGanged()
method to the Segmentation interface.  If this is overridden with
a method that returns true, then we proceed as described above.
Otherwise, we preserve the present behavior.

Also factor out some duplicated code among the calorimeter implementations.
  • Loading branch information
sss committed Jan 11, 2025
1 parent c532581 commit 37c059f
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 71 deletions.
4 changes: 4 additions & 0 deletions DDCore/include/DD4hep/Segmentations.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ 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 gang together regions
/// from multiple volumes.
/// In that case, a working volumeID() implementation is required.
bool isGanged() const;

/// Access to the base DDSegmentation object. WARNING: Deprecated call!
DDSegmentation::Segmentation* segmentation() const;
Expand Down
6 changes: 6 additions & 0 deletions DDCore/include/DDSegmentation/Segmentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ 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 gang together regions
/// from multiple volumes.
virtual bool isGanged() const
{
return false;
}

protected:
/// Default constructor used by derived classes passing the encoding string
Expand Down
7 changes: 7 additions & 0 deletions DDCore/src/Segmentations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ std::vector<double> Segmentation::cellDimensions(const CellID& cell) const {
return access()->segmentation->cellDimensions(cell);
}

/// Return true if this segmentation can gang together regions
/// from multiple volumes.
bool Segmentation::isGanged() const
{
return access()->segmentation->isGanged();
}

/// Access to the base DDSegmentation object. WARNING: Deprecated call!
DDSegmentation::Segmentation* Segmentation::segmentation() const {
return access()->segmentation;
Expand Down
125 changes: 54 additions & 71 deletions DDG4/plugins/Geant4SDActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,57 @@ 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.isGanged()) {
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);
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>
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Expand Down Expand Up @@ -250,25 +300,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;
}
Expand All @@ -294,24 +326,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;
}
Expand Down Expand Up @@ -462,23 +477,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;
}
Expand All @@ -505,23 +504,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;
}
Expand Down

0 comments on commit 37c059f

Please sign in to comment.