diff --git a/DDG4/include/DDG4/Geant4GeometryInfo.h b/DDG4/include/DDG4/Geant4GeometryInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..01f248497d805ebffaa3ac98dccf4b88aeb4d5ea --- /dev/null +++ b/DDG4/include/DDG4/Geant4GeometryInfo.h @@ -0,0 +1,98 @@ +// $Id: Geant4Geometryinfo.h 513 2013-04-05 14:31:53Z gaede $ +//==================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== +#ifndef DD4HEP_DDG4_GEANT4GEOMETRYINFO_H +#define DD4HEP_DDG4_GEANT4GEOMETRYINFO_H + +// Framework include files +#include "DD4hep/GeoHandler.h" +#include "DDG4/Geant4Primitives.h" + +// C/C++ include files +#include <map> +#include <vector> + +// Forward declarations (TGeo) +class TGeoElement; +class TGeoMedium; +class TGeoVolume; +class TGeoShape; +class TGeoNode; +// Forward declarations (Geant4) +class G4Element; +class G4Material; +class G4VSolid; +class G4LogicalVolume; +class G4Region; +class G4UserLimits; +class G4VisAttributes; +class G4VPhysicalVolume; +class G4AssemblyVolume; + +/* + * DD4hep namespace declaration + */ +namespace DD4hep { + + /* + * Simulation namespace declaration + */ + namespace Simulation { + + // Forward declarations + class Geant4Mapping; + class Geant4SensitiveDetector; + + struct Geant4GeometryInfo : public TNamed, public Geometry::GeoHandlerTypes::GeometryInfo { + public: + typedef std::vector<const G4VPhysicalVolume*> PlacementPath; + typedef std::vector<std::pair<size_t,const TGeoNode*> > AssemblyChildren; + typedef std::map<const TGeoElement*, G4Element*> ElementMap; + typedef std::map<const TGeoMedium*, G4Material*> MaterialMap; + typedef std::map<const TNamed*, G4UserLimits*> LimitMap; + typedef std::map<const TGeoNode*, G4VPhysicalVolume*> PlacementMap; + typedef std::map<const G4AssemblyVolume*,AssemblyChildren> AssemblyChildMap; + typedef std::map<const TNamed*, G4Region*> RegionMap; + typedef std::map<const TNamed*, Geant4SensitiveDetector*> SensDetMap; + typedef std::map<const TGeoVolume*, G4LogicalVolume*> VolumeMap; + typedef std::map<const TGeoShape*, G4VSolid*> SolidMap; + typedef std::map<const TNamed*, G4VisAttributes*> VisMap; + typedef std::map<PlacementPath, VolumeID> PathMap; + + typedef Geometry::GeoHandlerTypes::SensitiveVolumes SensitiveVolumes; + typedef Geometry::GeoHandlerTypes::RegionVolumes RegionVolumes; + typedef Geometry::GeoHandlerTypes::LimitVolumes LimitVolumes; + + ElementMap g4Elements; + MaterialMap g4Materials; + SolidMap g4Solids; + VolumeMap g4Volumes; + PlacementMap g4Placements; + AssemblyChildMap g4AssemblyChildren; + RegionMap g4Regions; + VisMap g4Vis; + LimitMap g4Limits; + SensDetMap g4SensDets; + PathMap g4Paths; + + SensitiveVolumes sensitives; + RegionVolumes regions; + LimitVolumes limits; + bool valid; + private: + friend class Geant4Mapping; + /// Default constructor + Geant4GeometryInfo(); + /// Default destructor + virtual ~Geant4GeometryInfo(); + }; + + } // End namespace Simulation +} // End namespace DD4hep + +#endif // DD4HEP_DDG4_GEANT4GEOMETRYINFO_H diff --git a/DDG4/include/DDG4/Geant4Mapping.h b/DDG4/include/DDG4/Geant4Mapping.h index 0b996b0d091e309cce8f861b7c2b15612661f4f3..060b31d10bfd5682a68c28ba661058c22bbaae43 100644 --- a/DDG4/include/DDG4/Geant4Mapping.h +++ b/DDG4/include/DDG4/Geant4Mapping.h @@ -10,32 +10,10 @@ #define DD4HEP_GEANT4MAPPING_H // Framework include files -#include "DD4hep/GeoHandler.h" #include "DD4hep/LCDD.h" - -// C/C++ include files -#include <set> -#include <map> -#include <vector> - -// Forward declarations -class TGeoVolume; -class TGeoElement; -class TGeoShape; -class TGeoMedium; -class TGeoNode; - -class G4Element; -class G4Material; -class G4VSolid; -class G4LogicalVolume; -class G4PVPlacement; -class G4Region; -class G4Field; -class G4FieldManager; -class G4UserLimits; -class G4VisAttributes; -class G4VPhysicalVolume; +#include "DD4hep/GeoHandler.h" +#include "DDG4/Geant4GeometryInfo.h" +#include "DDG4/Geant4VolumeManager.h" /* * DD4hep namespace declaration @@ -47,8 +25,6 @@ namespace DD4hep { */ namespace Simulation { - class Geant4SensitiveDetector; - /** @class Geant4Mapping Geant4Mapping.h DDG4/Geant4Mapping.h * * Geometry mapping from DD4hep to Geant 4. @@ -67,60 +43,56 @@ namespace DD4hep { typedef Geometry::Material Material; typedef Geometry::Region Region; - typedef std::map<const TGeoElement*,G4Element*> ElementMap; - typedef std::map<const TGeoMedium*, G4Material*> MaterialMap; - typedef std::map<const TNamed*, G4UserLimits*> LimitMap; - typedef std::map<const TGeoNode*, G4PVPlacement*> PlacementMap; - typedef std::map<const TNamed*, G4Region*> RegionMap; - typedef std::map<const TNamed*, Geant4SensitiveDetector*> SensDetMap; - typedef std::map<const TGeoVolume*, G4LogicalVolume*> VolumeMap; - typedef std::map<const TGeoShape*, G4VSolid*> SolidMap; - typedef std::map<const TNamed*, G4VisAttributes*> VisMap; - struct G4GeometryInfo : public GeometryInfo { - ElementMap g4Elements; - MaterialMap g4Materials; - SolidMap g4Solids; - VolumeMap g4Volumes; - PlacementMap g4Placements; - RegionMap g4Regions; - VisMap g4Vis; - LimitMap g4Limits; - SensDetMap g4SensDets; - - SensitiveVolumes sensitives; - RegionVolumes regions; - LimitVolumes limits; - }; + typedef Geant4GeometryInfo::PlacementPath PlacementPath; + typedef Geant4GeometryInfo::AssemblyChildren AssemblyChildren; + typedef Geant4GeometryInfo::ElementMap ElementMap; + typedef Geant4GeometryInfo::MaterialMap MaterialMap; + typedef Geant4GeometryInfo::LimitMap LimitMap; + typedef Geant4GeometryInfo::PlacementMap PlacementMap; + typedef Geant4GeometryInfo::AssemblyChildMap AssemblyChildMap; + typedef Geant4GeometryInfo::RegionMap RegionMap; + typedef Geant4GeometryInfo::SensDetMap SensDetMap; + typedef Geant4GeometryInfo::VolumeMap VolumeMap; + typedef Geant4GeometryInfo::SolidMap SolidMap; + typedef Geant4GeometryInfo::VisMap VisMap; + typedef Geant4GeometryInfo::PathMap PathMap; + protected: - LCDD& m_lcdd; - G4GeometryInfo* m_dataPtr; + LCDD& m_lcdd; + Geant4GeometryInfo* m_dataPtr; /// When resolving pointers, we must check for the validity of the data block void checkValidity() const; public: - /// Access to the data pointer - G4GeometryInfo& data() const { return *m_dataPtr; } - /// Release data and pass over the ownership - G4GeometryInfo* detach(); - /// Set a new data block - void attach(G4GeometryInfo* data); /// Initializing Constructor - Geant4Mapping(LCDD& lcdd, G4GeometryInfo* data); + Geant4Mapping(LCDD& lcdd); + /// Standard destructor virtual ~Geant4Mapping(); + /// Possibility to define a singleton instance static Geant4Mapping& instance(); /// Accesor to the LCDD instance LCDD& lcdd() const { return m_lcdd; } - /// Accessor to resolve G4 placements - G4PVPlacement* g4Placement(const TGeoNode* node) const; - /// Accessor to resolve geometry placements - PlacedVolume placement(const G4VPhysicalVolume* node) const; + /// Access to the data pointer + Geant4GeometryInfo& data() const { return *m_dataPtr; } + /// Create and attach new data block. Delete old data block if present. + Geant4GeometryInfo& init(); + /// Release data and pass over the ownership + Geant4GeometryInfo* detach(); + /// Set a new data block + void attach(Geant4GeometryInfo* data); + + /// Access the volume manager + Geant4VolumeManager volumeManager() const; + + /// Accessor to resolve geometry placements + PlacedVolume placement(const G4VPhysicalVolume* node) const; }; } // End namespace Simulation } // End namespace DD4hep diff --git a/DDG4/include/DDG4/Geant4SensitiveDetector.h b/DDG4/include/DDG4/Geant4SensitiveDetector.h index db8f41aa6f1496fd6b65f6f500095aee4b67e71e..ef91e5dbb2a730359e68b090deea7dac8c555992 100644 --- a/DDG4/include/DDG4/Geant4SensitiveDetector.h +++ b/DDG4/include/DDG4/Geant4SensitiveDetector.h @@ -115,6 +115,9 @@ namespace DD4hep { /// G4VSensitiveDetector interface: Method for generating hit(s) using the information of G4Step object. virtual G4bool ProcessHits(G4Step* step,G4TouchableHistory* history); + /// G4VSensitiveDetector interface: Method for generating hit(s) using the information of G4Step object. + virtual G4bool process(G4Step* step,G4TouchableHistory* history); + /// G4VSensitiveDetector interface: Method invoked if the event was aborted. /** Hits collections created but not beibg set to G4HCofThisEvent * at the event should be deleted. diff --git a/DDG4/include/DDG4/Geant4StepHandler.h b/DDG4/include/DDG4/Geant4StepHandler.h index a7f82167807564f6bda2f1a67bfb2abffd0e162f..739ce4c55a1ce52ce9a643a7fda55b2345079ad5 100644 --- a/DDG4/include/DDG4/Geant4StepHandler.h +++ b/DDG4/include/DDG4/Geant4StepHandler.h @@ -79,33 +79,41 @@ namespace DD4hep { const G4VTouchable* postTouchable() const { return post->GetTouchable(); } - const char* volName(G4StepPoint* p, const char* undefined="") const { + const char* volName(const G4StepPoint* p, const char* undefined="") const { G4VPhysicalVolume* v = volume(p); return v ? v->GetName().c_str() : undefined; } - G4VPhysicalVolume* volume(G4StepPoint* p) const { + G4VPhysicalVolume* volume(const G4StepPoint* p) const { return p->GetTouchableHandle()->GetVolume(); } - G4VPhysicalVolume* physvol(G4StepPoint* p) const { + G4VPhysicalVolume* physvol(const G4StepPoint* p) const { return p->GetPhysicalVolume(); } - G4LogicalVolume* logvol(G4StepPoint* p) const { + G4LogicalVolume* logvol(const G4StepPoint* p) const { G4VPhysicalVolume* pv = physvol(p); return pv ? pv->GetLogicalVolume() : 0; } - G4VSensitiveDetector* sd(G4StepPoint* p) const { + G4VSensitiveDetector* sd(const G4StepPoint* p) const { G4LogicalVolume* lv = logvol(p); return lv ? lv->GetSensitiveDetector() : 0; } - const char* sdName(G4StepPoint* p, const char* undefined="") const { + const char* sdName(const G4StepPoint* p, const char* undefined="") const { G4VSensitiveDetector* s = sd(p); return s ? s->GetName().c_str() : undefined; } - - G4VPhysicalVolume* preVolume() const { return volume(pre); } - G4VSensitiveDetector* preSD() const { return sd(pre); } - G4VPhysicalVolume* postVolume() const { return volume(post); } - G4VSensitiveDetector* postSD() const { return sd(post); } + bool isSensitive(const G4LogicalVolume* lv) const { + return lv ? (0 != lv->GetSensitiveDetector()) : false; + } + bool isSensitive(const G4VPhysicalVolume* pv) const { + return pv ? isSensitive(pv->GetLogicalVolume()) : false; + } + bool isSensitive(const G4StepPoint* point) const { + return point ? isSensitive(volume(point)) : false; + } + G4VPhysicalVolume* preVolume() const { return volume(pre); } + G4VSensitiveDetector* preSD() const { return sd(pre); } + G4VPhysicalVolume* postVolume() const { return volume(post); } + G4VSensitiveDetector* postSD() const { return sd(post); } }; } // End namespace Simulation diff --git a/DDG4/include/DDG4/Geant4VolumeManager.h b/DDG4/include/DDG4/Geant4VolumeManager.h new file mode 100644 index 0000000000000000000000000000000000000000..028288da65b89382f62b720374a3677ac4d15ed6 --- /dev/null +++ b/DDG4/include/DDG4/Geant4VolumeManager.h @@ -0,0 +1,97 @@ +// $Id: Geant4VolumeManager.h 603 2013-06-13 21:15:14Z markus.frank $ +//==================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== +#ifndef DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H +#define DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H + +// Framework include files +#include "DD4hep/LCDD.h" +#include "DD4hep/IDDescriptor.h" +#include "DDG4/Geant4Primitives.h" +#include "DDG4/Geant4GeometryInfo.h" + +// Geant4 forward declarations +class G4VTouchable; + +/* + * DD4hep namespace declaration + */ +namespace DD4hep { + + /* + * Simulation namespace declaration + */ + namespace Simulation { + + // Forward declarations + class Geant4VolumeManager; + class Geant4GeometryInfo; + + /** @class Geant4VolumeManager Geant4VolumeManager.h DDG4/Geant4VolumeManager.h + * + * @author M.Frank + * @version 1.0 + */ + struct Geant4VolumeManager : public Geometry::Handle<Geant4GeometryInfo> { + public: + // Forward declarations + typedef Geometry::Handle<Geant4GeometryInfo> Base; + typedef Geometry::PlacedVolume PlacedVolume; + typedef Geometry::IDDescriptor IDDescriptor; + typedef IDDescriptor::VolIDFields VolIDFields; + typedef std::pair<VolumeID, VolIDFields> VolIDDescriptor; + typedef Geant4GeometryInfo::PlacementPath PlacementPath; + typedef Geant4GeometryInfo Object; + + protected: + /// Optimization flag to shortcut object checks + mutable bool m_isValid; + + /// Check the validity of the information before accessing it. + bool checkValidity() const; + + public: + static const VolumeID InvalidPath = VolumeID(-1LL); + static const VolumeID Insensitive = VolumeID(-2LL); + static const VolumeID NonExisting = 0ULL; + + /// Initializing constructor. The tree will automatically be built if possible + Geant4VolumeManager(Geometry::LCDD& lcdd, Geant4GeometryInfo* info); + /// Default constructor + Geant4VolumeManager() : Base(), m_isValid(false) {} + /// Constructor to be used when reading the already parsed object + Geant4VolumeManager(const Base& e) : Base(e), m_isValid(false) {} + /// Constructor to be used when reading the already parsed object + Geant4VolumeManager(const Geant4VolumeManager& e) : Base(e), m_isValid(false) {} + /// Constructor to be used when reading the already parsed object + template <typename Q> Geant4VolumeManager(const Geometry::Handle<Q>& e) : Base(e), m_isValid(false) {} + + /// Helper: Generate placement path from touchable object + PlacementPath placementPath(const G4VTouchable* touchable, bool exception=true) const; + + /// Accessor to resolve TGeo geometry placements from Geant4 placements + PlacedVolume placement(const G4VPhysicalVolume* node) const; + /// Accessor to resolve Geant4 geometry placements from TGeo placements + G4VPhysicalVolume* placement(const TGeoNode* node) const; + /// Accessor to resolve Geant4 geometry placements from TGeo placements + G4VPhysicalVolume* placement(const PlacedVolume& node) const + { return placement(node.ptr()); } + /// Access CELLID by placement path + VolumeID volumeID(const PlacementPath& path) const; + /// Access CELLID by Geant4 touchable object + VolumeID volumeID(const G4VTouchable* touchable) const; + + /// Accessfully decoded volume fields by placement path + void volumeDescriptor(const PlacementPath& path, VolIDDescriptor& volume_desc) const; + /// Access fully decoded volume fields by Geant4 touchable object + void volumeDescriptor(const G4VTouchable* touchable, VolIDDescriptor& volume_desc) const; + }; + + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp index 079d7c53efe3cfd893ae5bbe041d29615bbf0053..85e08cf0dcf797958095845a711049ece9c182eb 100644 --- a/DDG4/src/Geant4Converter.cpp +++ b/DDG4/src/Geant4Converter.cpp @@ -44,7 +44,6 @@ #include "G4Element.hh" #include "G4SDManager.hh" #include "G4Assembly.hh" -#include "G4AssemblyVolume.hh" #include "G4Box.hh" #include "G4Trd.hh" #include "G4Tubs.hh" @@ -72,6 +71,8 @@ #include "G4ElectroMagneticField.hh" #include "G4FieldManager.hh" +#include "G4ReflectionFactory.hh" + #include <iostream> #include <iomanip> #include <sstream> @@ -81,6 +82,112 @@ using namespace DD4hep::Geometry; using namespace DD4hep; using namespace std; +#define private public +#include "G4AssemblyVolume.hh" +#undef private + +struct Geant4AssemblyVolume : public G4AssemblyVolume { + Geant4AssemblyVolume() {} + size_t placeVolume(G4LogicalVolume* pPlacedVolume, + G4Transform3D& transformation) { + size_t id = fTriplets.size(); + this->AddPlacedVolume(pPlacedVolume,transformation); + return id; + } + void imprint( std::vector<G4VPhysicalVolume*>& nodes, + G4LogicalVolume* pMotherLV, + G4Transform3D& transformation, + G4int copyNumBase, + G4bool surfCheck ); + +}; + +void Geant4AssemblyVolume::imprint( std::vector<G4VPhysicalVolume*>& nodes, + G4LogicalVolume* pMotherLV, + G4Transform3D& transformation, + G4int copyNumBase, + G4bool surfCheck ) +{ + G4AssemblyVolume* pAssembly = this; + unsigned int numberOfDaughters; + if( copyNumBase == 0 ) { + numberOfDaughters = pMotherLV->GetNoDaughters(); + } + else { + numberOfDaughters = copyNumBase; + } + // We start from the first available index + numberOfDaughters++; + ImprintsCountPlus(); + + std::vector<G4AssemblyTriplet> triplets = pAssembly->fTriplets; + for( unsigned int i = 0; i < triplets.size(); i++ ) { + G4Transform3D Ta( *(triplets[i].GetRotation()), + triplets[i].GetTranslation() ); + if ( triplets[i].IsReflection() ) { Ta = Ta * G4ReflectZ3D(); } + + G4Transform3D Tfinal = transformation * Ta; + + if ( triplets[i].GetVolume() ) + { + // Generate the unique name for the next PV instance + // The name has format: + // + // av_WWW_impr_XXX_YYY_ZZZ + // where the fields mean: + // WWW - assembly volume instance number + // XXX - assembly volume imprint number + // YYY - the name of a log. volume we want to make a placement of + // ZZZ - the log. volume index inside the assembly volume + // + std::stringstream pvName; + pvName << "av_" + << GetAssemblyID() + << "_impr_" + << GetImprintsCount() + << "_" + << triplets[i].GetVolume()->GetName().c_str() + << "_pv_" + << i + << std::ends; + + // Generate a new physical volume instance inside a mother + // (as we allow 3D transformation use G4ReflectionFactory to + // take into account eventual reflection) + // + G4PhysicalVolumesPair pvPlaced + = G4ReflectionFactory::Instance()->Place( Tfinal, + pvName.str().c_str(), + triplets[i].GetVolume(), + pMotherLV, + false, + numberOfDaughters + i, + surfCheck ); + + // Register the physical volume created by us so we can delete it later + // + fPVStore.push_back( pvPlaced.first ); + nodes.push_back(pvPlaced.first); + if ( pvPlaced.second ) { // Supported by G4, but not by TGeo! + fPVStore.push_back( pvPlaced.second ); + G4Exception("G4AssemblyVolume::MakeImprint(..)", + "GeomVol0003", FatalException, + "Fancy construct popping new mother from the stack!"); + } + } + else if ( triplets[i].GetAssembly() ) { + // Place volumes in this assembly with composed transformation + G4Exception("G4AssemblyVolume::MakeImprint(..)", + "GeomVol0003", FatalException, + "Assemblies within assembliesare not supported."); + } + else { + G4Exception("G4AssemblyVolume::MakeImprint(..)", + "GeomVol0003", FatalException, + "Triplet has no volume and no assembly"); + } + } +} namespace { static TGeoNode* s_topPtr; @@ -117,8 +224,9 @@ namespace { /// Initializing Constructor Geant4Converter::Geant4Converter( LCDD& lcdd ) - : Geant4Mapping(lcdd,new G4GeometryInfo()), m_checkOverlaps(true) + : Geant4Mapping(lcdd), m_checkOverlaps(true) { + this->Geant4Mapping::init(); } /// Standard destructor @@ -343,7 +451,7 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape) /// Dump logical volume in GDML format to output stream void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume) const { - G4GeometryInfo& info = data(); + Geant4GeometryInfo& info = data(); G4LogicalVolume* vol = info.g4Volumes[volume]; if ( !vol ) { const TGeoVolume* v = volume; @@ -431,7 +539,7 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume /// Dump logical volume in GDML format to output stream void* Geant4Converter::collectVolume(const string& /* name */, const TGeoVolume* volume) const { - G4GeometryInfo& info = data(); + Geant4GeometryInfo& info = data(); const TGeoVolume* v = volume; Volume _v = Ref_t(v); Region reg = _v.region(); @@ -446,128 +554,82 @@ void* Geant4Converter::collectVolume(const string& /* name */, const TGeoVolume* /// Dump volume placement in GDML format to output stream void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) const { - G4GeometryInfo& info = data(); - G4PVPlacement* g4 = info.g4Placements[node]; + static Double_t identity_rot[] = { 1., 0., 0., 0., 1., 0., 0., 0., 1. }; + Geant4GeometryInfo& info = data(); + PlacementMap::const_iterator g4it = info.g4Placements.find(node); + G4VPhysicalVolume* g4 = (g4it == info.g4Placements.end()) ? 0 : (*g4it).second; if ( !g4 ) { TGeoVolume* mot_vol = node->GetMotherVolume(); TGeoVolume* vol = node->GetVolume(); TGeoMatrix* trafo = node->GetMatrix(); - int copy = node->GetNumber(); - - //fg: this is not needed any more - the cellIDs are taken from the VolumIDs - // set for the placed volumes ... - // // if the CellID0 volID is defined for the volume we - // // use it to overwrite the copy number - // // this is then used in the sensitive detector to fill the CellID0 - // // of the SimTrackerHits - // if ( dynamic_cast<const PlacedVolume::Object*>(node) ) { - // PlacedVolume p = Ref_t(node); - // const PlacedVolume::VolIDs& ids = p.volIDs(); - // // copy = ids[ "CellID0" ] ; - // PlacedVolume::VolIDs::const_iterator it = ids.find("CellID0") ; - // if( it != ids.end() ) - // copy = it->second ; - // } - //-------------------------------------------------------- - G4LogicalVolume* g4vol = info.g4Volumes[vol]; - G4LogicalVolume* g4mot = info.g4Volumes[mot_vol]; - G4AssemblyVolume* ass_mot = (G4AssemblyVolume*)g4mot; - G4AssemblyVolume* ass_dau = (G4AssemblyVolume*)g4vol; - bool daughter_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class(); - bool mother_is_assembly = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false; - if ( trafo ) { - const Double_t* trans = trafo->GetTranslation(); - bool is_rot = trafo->IsRotation(); - if ( 0 == vol ) { - printout(FATAL,"Geant4Converter","++ Unknown G4 volume:%p %s of type %s vol:%s ptr:%s", - node,node->GetName(),node->IsA()->GetName(),vol->IsA()->GetName(),vol); - } - else if ( is_rot ) { - const Double_t* rot = trafo->GetRotationMatrix(); - MyTransform3D transform(rot[0],rot[1],rot[2],trans[0]*CM_2_MM, - rot[3],rot[4],rot[5],trans[1]*CM_2_MM, - rot[6],rot[7],rot[8],trans[2]*CM_2_MM); - CLHEP::HepRotation rotmat=transform.getRotation(); - if ( mother_is_assembly ) { // Mother is an assembly: - printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s " - "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", - ass_mot,g4vol->GetName().c_str(), - transform.dx(),transform.dy(),transform.dz(), - rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi()); - ass_mot->AddPlacedVolume(g4vol,transform); - return 0; - } - else if ( daughter_is_assembly ) { - printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s " - "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", - ass_dau,g4mot->GetName().c_str(), - transform.dx(),transform.dy(),transform.dz(), - rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi()); - ass_dau->MakeImprint(g4mot,transform,copy,m_checkOverlaps); - return 0; - } - g4 = new G4PVPlacement(transform, // no rotation - g4vol, // its logical volume - name, // its name - g4mot, // its mother (logical) volume - false, // no boolean operations - copy, // its copy number - m_checkOverlaps); - } - else { - G4ThreeVector pos(trans[0]*CM_2_MM,trans[1]*CM_2_MM,trans[2]*CM_2_MM); - if ( mother_is_assembly ) { // Mother is an assembly: - ass_mot->AddPlacedVolume(g4vol,pos,0); - printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s " - "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", - ass_mot,g4vol->GetName().c_str(), - pos.x(),pos.y(),pos.z(),0,0,0); - return 0; - } - else if ( daughter_is_assembly ) { - printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s " - "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", - ass_dau,g4mot->GetName().c_str(), - pos.x(),pos.y(),pos.z(),0,0,0); - ass_dau->MakeImprint(g4mot,pos,0,copy,m_checkOverlaps); - return 0; - } - g4 = new G4PVPlacement(0, // no rotation - pos, // translation position - g4vol, // its logical volume - name, // its name - g4mot, // its mother (logical) volume - false, // no boolean operations - copy, // its copy number - m_checkOverlaps); - } - data().g4Placements[node] = g4; - } - else if ( node == s_topPtr ) { - G4ThreeVector pos(0,0,0); + if ( !trafo ) { + printout(FATAL,"Geant4Converter","++ Attempt to handle placement without transformation:%p %s of type %s vol:%p", + node,node->GetName(),node->IsA()->GetName(),vol); + } + else if ( 0 == vol ) { + printout(FATAL,"Geant4Converter","++ Unknown G4 volume:%p %s of type %s vol:%s ptr:%p", + node,node->GetName(),node->IsA()->GetName(),vol->IsA()->GetName(),vol); + } + else { + int copy = node->GetNumber(); + G4LogicalVolume* g4vol = info.g4Volumes[vol]; + G4LogicalVolume* g4mot = info.g4Volumes[mot_vol]; + Geant4AssemblyVolume* ass_mot = (Geant4AssemblyVolume*)g4mot; + Geant4AssemblyVolume* ass_dau = (Geant4AssemblyVolume*)g4vol; + const Double_t* trans = trafo->GetTranslation(); + const Double_t* rot = trafo->IsRotation() ? trafo->GetRotationMatrix() : identity_rot; + bool daughter_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class(); + bool mother_is_assembly = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false; + MyTransform3D transform(rot[0],rot[1],rot[2],trans[0]*CM_2_MM, + rot[3],rot[4],rot[5],trans[1]*CM_2_MM, + rot[6],rot[7],rot[8],trans[2]*CM_2_MM); + CLHEP::HepRotation rotmat=transform.getRotation(); + if ( mother_is_assembly ) { // Mother is an assembly: - ass_mot->AddPlacedVolume(g4vol,pos,0); + printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s " + "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", + ass_mot,g4vol ? g4vol->GetName().c_str() : "---", + transform.dx(),transform.dy(),transform.dz(), + rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi()); + size_t id = ass_mot->placeVolume(g4vol,transform); + info.g4AssemblyChildren[ass_mot].push_back(make_pair(id,node)); return 0; } else if ( daughter_is_assembly ) { - ass_dau->MakeImprint(g4mot,pos,0,copy,m_checkOverlaps); + printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s " + "Tr:x=%8.3f y=%8.3f z=%8.3f Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n", + ass_dau,g4mot ? g4mot->GetName().c_str() : "---", + transform.dx(),transform.dy(),transform.dz(), + rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi()); + std::vector<G4VPhysicalVolume*> phys_volumes; + AssemblyChildMap::iterator i = info.g4AssemblyChildren.find(ass_dau); + if ( i == info.g4AssemblyChildren.end() ) { + printout(ERROR, "Geant4Converter", "++ Non-existing assembly [%p]",ass_dau); + } + const AssemblyChildren& v = (*i).second; + ass_dau->imprint(phys_volumes,g4mot,transform,copy,m_checkOverlaps); + if ( v.size() != phys_volumes.size() ) { + printout(ERROR, "Geant4Converter", "++ Unexpected number of placements in assembly: %ld <> %ld.", + v.size(), phys_volumes.size()); + } + for(size_t j=0; j<v.size(); ++j) { + info.g4Placements[v[j].second] = phys_volumes[j]; + } return 0; } - g4 = new G4PVPlacement(0, // no rotation - pos, // translation position + g4 = new G4PVPlacement(transform, // no rotation g4vol, // its logical volume name, // its name g4mot, // its mother (logical) volume false, // no boolean operations copy, // its copy number m_checkOverlaps); - data().g4Placements[node] = g4; - printout(ERROR, "Geant4Converter", "++ Attempt to convert TOP Detector node failed."); } + info.g4Placements[node] = g4; } else { - printout(ERROR, "Geant4Converter", "++ Attempt to DOUBLE-place physical volume: %s No:%d", - name.c_str(),node->GetNumber()); + printout(ERROR, "Geant4Converter", "++ Attempt to DOUBLE-place physical volume: %s No:%d", + name.c_str(),node->GetNumber()); } return g4; } @@ -643,7 +705,7 @@ void* Geant4Converter::handleLimitSet(const TNamed* limitset, const set<const TG /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s). void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const TGeoVolume*>& /* volumes */) const { - G4GeometryInfo& info = data(); + Geant4GeometryInfo& info = data(); Geant4SensitiveDetector* g4 = info.g4SensDets[sens_det]; if ( !g4 ) { SensitiveDetector sd = Ref_t(sens_det); @@ -651,8 +713,14 @@ void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const T g4 = ROOT::Reflex::PluginService::Create<Geant4SensitiveDetector*>(type,name,&m_lcdd); if ( !g4 ) { - throw runtime_error("Geant4Converter<SensitiveDetector>: FATAL Failed to " - "create Geant4 sensitive detector "+name+" of type "+type+"."); + string tmp = type; + tmp[0] = ::toupper(tmp[0]); + type = "Geant4"+tmp; + g4 = ROOT::Reflex::PluginService::Create<Geant4SensitiveDetector*>(type,name,&m_lcdd); + if ( !g4 ) { + throw runtime_error("Geant4Converter<SensitiveDetector>: FATAL Failed to " + "create Geant4 sensitive detector "+name+" of type "+type+"."); + } } g4->Activate(true); g4->defineCollection(sd.hitsCollection()); @@ -664,7 +732,7 @@ void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const T /// Convert the geometry visualisation attributes to the corresponding Geant4 object(s). void* Geant4Converter::handleVis(const string& /* name */, const TNamed* vis) const { - G4GeometryInfo& info = data(); + Geant4GeometryInfo& info = data(); G4VisAttributes* g4 = info.g4Vis[vis]; if ( !g4 ) { float r=0, g=0, b=0; @@ -732,7 +800,7 @@ void Geant4Converter::handleProperties(LCDD::Properties& prp) const { /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s). void* Geant4Converter::printSensitive(const TNamed* sens_det, const set<const TGeoVolume*>& /* volumes */) const { - G4GeometryInfo& info = data(); + Geant4GeometryInfo& info = data(); Geant4SensitiveDetector* g4 = info.g4SensDets[sens_det]; ConstVolumeSet& volset = info.sensitives[sens_det]; SensitiveDetector sd = Ref_t(sens_det); @@ -777,12 +845,12 @@ string printSolid(G4VSolid* sol) { /// Print G4 placement void* Geant4Converter::printPlacement(const string& name, const TGeoNode* node) const { - G4GeometryInfo& info = data(); - G4PVPlacement* g4 = info.g4Placements[node]; - G4LogicalVolume* vol = info.g4Volumes[node->GetVolume()]; - G4LogicalVolume* mot = info.g4Volumes[node->GetMotherVolume()]; - G4VSolid* sol = vol->GetSolid(); - G4ThreeVector tr = g4->GetObjectTranslation(); + Geant4GeometryInfo& info = data(); + G4VPhysicalVolume* g4 = info.g4Placements[node]; + G4LogicalVolume* vol = info.g4Volumes[node->GetVolume()]; + G4LogicalVolume* mot = info.g4Volumes[node->GetMotherVolume()]; + G4VSolid* sol = vol->GetSolid(); + G4ThreeVector tr = g4->GetObjectTranslation(); G4VSensitiveDetector* sd = vol->GetSensitiveDetector(); if ( !sd ) return g4; @@ -827,7 +895,7 @@ template <typename O, typename C, typename F> void handleRMap(const O* o, const /// Create geometry conversion Geant4Converter& Geant4Converter::create(DetElement top) { - G4GeometryInfo& geo = *(m_dataPtr=new G4GeometryInfo); + Geant4GeometryInfo& geo = this->init(); m_data->clear(); collect(top, geo); s_topPtr = top.placement().ptr(); @@ -861,5 +929,6 @@ Geant4Converter& Geant4Converter::create(DetElement top) { //handleMap(this, geo.sensitives, &Geant4Converter::printSensitive); //handleRMap(this, *m_data, &Geant4Converter::printPlacement); + geo.valid = true; return *this; } diff --git a/DDG4/src/Geant4DetectorConstruction.cpp b/DDG4/src/Geant4DetectorConstruction.cpp index f1478c882974c5972800a31b7d4fc398d0398167..b8945e6667e563ea5001eb87f002b74a6ff7c372 100644 --- a/DDG4/src/Geant4DetectorConstruction.cpp +++ b/DDG4/src/Geant4DetectorConstruction.cpp @@ -26,9 +26,10 @@ G4VPhysicalVolume* DD4hep::Simulation::Geant4DetectorConstruction::Construct() { Geant4Mapping& g4map = Geant4Mapping::instance(); DetElement world = m_lcdd.world(); Geant4Converter conv(m_lcdd); - Geant4Converter::G4GeometryInfo* info = conv.create(world).detach(); + Geant4GeometryInfo* info = conv.create(world).detach(); g4map.attach(info); - m_world = g4map.g4Placement(top); + Geant4VolumeManager mgr = g4map.volumeManager(); + m_world = mgr.placement(top); m_lcdd.apply("DD4hepVolumeManager",0,0); //Geant4HierarchyDump dmp(m_lcdd); //dmp.dump("",m_world); diff --git a/DDG4/src/Geant4GeometryInfo.cpp b/DDG4/src/Geant4GeometryInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97d044c1eb56e343de8efe3124ecc4f1f0f2d3ef --- /dev/null +++ b/DDG4/src/Geant4GeometryInfo.cpp @@ -0,0 +1,21 @@ +// $Id: Geant4Mapping.cpp 588 2013-06-03 11:41:35Z markus.frank $ +//==================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== + +#include "DDG4/Geant4GeometryInfo.h" +using namespace DD4hep::Simulation; + +/// Default constructor +Geant4GeometryInfo::Geant4GeometryInfo() +: TNamed("Geant4GeometryInfo","Geant4GeometryInfo"), valid(false) +{ +} + +/// Default destructor +Geant4GeometryInfo::~Geant4GeometryInfo() { +} diff --git a/DDG4/src/Geant4Mapping.cpp b/DDG4/src/Geant4Mapping.cpp index 2f2376c1b3a1c3d67e87dfa74c87ec2ace814dea..18bfab246c3a140cb4943f242924e67a0a3439ef 100644 --- a/DDG4/src/Geant4Mapping.cpp +++ b/DDG4/src/Geant4Mapping.cpp @@ -7,6 +7,7 @@ // //==================================================================== +#include "DD4hep/Printout.h" #include "DDG4/Geant4Mapping.h" #include "G4PVPlacement.hh" #include <stdexcept> @@ -16,8 +17,7 @@ using namespace DD4hep::Geometry; using namespace std; /// Initializing Constructor -Geant4Mapping::Geant4Mapping( LCDD& lcdd, G4GeometryInfo* data) - : m_lcdd(lcdd), m_dataPtr(data) +Geant4Mapping::Geant4Mapping(LCDD& lcdd) : m_lcdd(lcdd), m_dataPtr(0) { } @@ -29,7 +29,7 @@ Geant4Mapping::~Geant4Mapping() { /// Possibility to define a singleton instance Geant4Mapping& Geant4Mapping::instance() { - static Geant4Mapping inst(LCDD::getInstance(),0); + static Geant4Mapping inst(LCDD::getInstance()); return inst; } @@ -39,25 +39,35 @@ void Geant4Mapping::checkValidity() const { throw runtime_error("Geant4Mapping: Attempt to access an invalid data block!"); } +/// Create new data block. Delete old data block if present. +Geant4GeometryInfo& Geant4Mapping::init() { + Geant4GeometryInfo* p = detach(); + if ( p ) delete p; + attach(new Geant4GeometryInfo()); + return data(); +} + /// Release data and pass over the ownership -Geant4Mapping::G4GeometryInfo* Geant4Mapping::detach() { - G4GeometryInfo* p = m_dataPtr; +Geant4GeometryInfo* Geant4Mapping::detach() { + Geant4GeometryInfo* p = m_dataPtr; m_dataPtr = 0; return p; } /// Set a new data block -void Geant4Mapping::attach(G4GeometryInfo* data) { +void Geant4Mapping::attach(Geant4GeometryInfo* data) { m_dataPtr = data; } -/// Accessor to resolve G4 placements -G4PVPlacement* Geant4Mapping::g4Placement(const TGeoNode* node) const { - checkValidity(); - const PlacementMap& m = m_dataPtr->g4Placements; - PlacementMap::const_iterator i = m.find(node); - if ( i != m.end() ) return (*i).second; - return 0; +/// Access the volume manager +Geant4VolumeManager Geant4Mapping::volumeManager() const { + if ( m_dataPtr ) { + if ( m_dataPtr->g4Paths.empty() ) { + return Geant4VolumeManager(m_lcdd,m_dataPtr); + } + return Geant4VolumeManager(Geometry::Handle<Geant4GeometryInfo>(m_dataPtr)); + } + throw runtime_error(format("Geant4Mapping","Cannot create volume manager without Geant4 geometry info [Invalid-Info]")); } /// Accessor to resolve geometry placements diff --git a/DDG4/src/Geant4SensitiveDetector.cpp b/DDG4/src/Geant4SensitiveDetector.cpp index b1c40872219462ea0be682a71672af5bc858cb19..9132bb6428f382bec45f61d8633a0cd4051dddc8 100644 --- a/DDG4/src/Geant4SensitiveDetector.cpp +++ b/DDG4/src/Geant4SensitiveDetector.cpp @@ -95,6 +95,11 @@ void Geant4SensitiveDetector::EndOfEvent(G4HCofThisEvent* /* HCE */) { /// Method for generating hit(s) using the information of G4Step object. G4bool Geant4SensitiveDetector::ProcessHits(G4Step* step,G4TouchableHistory* hist) { + return process(step,hist); +} + +/// Method for generating hit(s) using the information of G4Step object. +G4bool Geant4SensitiveDetector::process(G4Step* step,G4TouchableHistory* hist) { double ene_cut = m_sensitive.energyCutoff(); if ( step->GetTotalEnergyDeposit() > ene_cut ) { if ( !Geant4Hit::isGeantino(step->GetTrack()) ) { @@ -155,7 +160,7 @@ void Geant4SensitiveDetector::dumpStep(G4Step* st, G4TouchableHistory* /* histor const Places& places = cnv.data().g4Placements; for(Places::const_iterator i=places.begin(); i!=places.end();++i) { - const G4PVPlacement* pl = (*i).second; + const G4VPhysicalVolume* pl = (*i).second; const G4VPhysicalVolume* qv = pl; if ( qv == pv ) { diff --git a/DDG4/src/Geant4VolumeManager.cpp b/DDG4/src/Geant4VolumeManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57fdb518a3dbe642c23f28e15c1da11b875cac39 --- /dev/null +++ b/DDG4/src/Geant4VolumeManager.cpp @@ -0,0 +1,245 @@ +// $Id: Geant4VolumeManager.cpp 513 2013-04-05 14:31:53Z gaede $ +//==================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== + +// Framework include files +#include "DD4hep/Printout.h" +#include "DD4hep/Volumes.h" +#include "DD4hep/Detector.h" +#include "DDG4/Geant4VolumeManager.h" +#include "DDG4/Geant4Mapping.h" + +// Geant4 include files +#include "G4VTouchable.hh" +#include "G4LogicalVolume.hh" +#include "G4VPhysicalVolume.hh" + +using namespace DD4hep::Simulation; +using namespace DD4hep::Geometry; +using namespace DD4hep; +using namespace std; + +typedef Geant4GeometryInfo::PathMap PathMap; +typedef Geant4GeometryInfo::PlacementMap PlacementMap; + +namespace { + + struct Populator { + typedef vector<const TGeoNode*> Chain; + typedef DD4hep::Geometry::LCDD LCDD; + typedef DD4hep::Geometry::Readout Readout; + typedef DD4hep::Geometry::DetElement DetElement; + + /// Reference to the LCDD instance + LCDD& m_lcdd; + /// Set of already added entries + set<VolumeID> m_entries; + /// Reference to Geant4 translation information + Geant4GeometryInfo& m_geo; + + /// Default constructor + Populator(LCDD& lcdd, Geant4GeometryInfo& g) : m_lcdd(lcdd), m_geo(g) { + } + + /// Populate the Volume manager + void populate(DetElement e) { + const DetElement::Children& c = e.children(); + for(DetElement::Children::const_iterator i=c.begin(); i!=c.end(); ++i) { + DetElement de = (*i).second; + PlacedVolume pv = de.placement(); + if ( pv.isValid() ) { + Chain chain; + SensitiveDetector sd; + PlacedVolume::VolIDs ids; + m_entries.clear(); + scanPhysicalVolume(pv.ptr(), ids, sd, chain); + continue; + } + printout(WARNING,"VolumeManager","++ Detector element %s of type %s has no placement.", + de.name(),de.type().c_str()); + } + } + + /// Scan a single physical volume and look for sensitive elements below + void scanPhysicalVolume(const TGeoNode* node, PlacedVolume::VolIDs ids, SensitiveDetector& sd, Chain& chain) { + PlacedVolume pv = Ref_t(node); + Volume vol = pv.volume(); + PlacedVolume::VolIDs pv_ids = pv.volIDs(); + + chain.push_back(node); + ids.PlacedVolume::VolIDs::Base::insert(ids.end(),pv_ids.begin(),pv_ids.end()); + if ( vol.isSensitive() ) { + sd = vol.sensitiveDetector(); + if ( sd.readout().isValid() ) { + add_entry(sd, node, ids, chain); + } + else { + printout(WARNING,"VolumeManager", + "Strange constellation volume %s is sensitive, but has no readout! sd:%p", + pv.volume().name(), sd.ptr()); + } + } + for(Int_t idau=0, ndau=node->GetNdaughters(); idau<ndau; ++idau) { + TGeoNode* daughter = node->GetDaughter(idau); + if ( dynamic_cast<const PlacedVolume::Object*>(daughter) ) { + scanPhysicalVolume(daughter, ids, sd, chain); + } + } + chain.pop_back(); + } + + void add_entry(SensitiveDetector sd, const TGeoNode* n, const PlacedVolume::VolIDs& ids, const Chain& nodes) { + Readout ro = sd.readout(); + IDDescriptor iddesc = ro.idSpec(); + VolumeID code = iddesc.encode(ids); + if ( m_entries.find(code) == m_entries.end() ) { + PlacedVolume place = Ref_t(n); + Geant4Mapping::PlacementPath path; + path.reserve(nodes.size()); + for(Chain::const_reverse_iterator i=nodes.rbegin(); i != nodes.rend(); ++i) { + const TGeoNode* n = *i; + PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(n); + if ( g4pit != m_geo.g4Placements.end() ) { + path.push_back((*g4pit).second); + } + } + if ( m_geo.g4Paths.find(path) != m_geo.g4Paths.end() ) { + cout << "Severe error: Duplicated Geant4 path!!!!" << endl; + } + m_geo.g4Paths[path] = code; + m_entries.insert(code); + } + else { + cout << "Severe error: Duplicated Volume entry:" << (void*)code << endl; + } + } + }; +} + +/// Initializing constructor. The tree will automatically be built if possible +Geant4VolumeManager::Geant4VolumeManager(LCDD& lcdd, Geant4GeometryInfo* info) +: Base(info), m_isValid(false) +{ + if ( info && info->valid && info->g4Paths.empty() ) { + Populator p(lcdd,*info); + p.populate(lcdd.world()); + return; + } + throw runtime_error(format("Geant4VolumeManager","Attempt populate from invalid Geant4 geometry info [Invalid-Info]")); +} + +/// Helper: Generate placement path from touchable object +Geant4VolumeManager::PlacementPath +Geant4VolumeManager::placementPath(const G4VTouchable* touchable, bool exception) const +{ + Geant4Mapping::PlacementPath path; + if ( touchable ) { + for(int i=0, n=touchable->GetHistoryDepth(); i<n; ++i) { + G4VPhysicalVolume* pv = touchable->GetVolume(i); + path.push_back(pv); + } + } + else if ( exception ) { + throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 touchable [Invalid-Touchable]")); + } + return path; +} + +/// Check the validity of the information before accessing it. +bool Geant4VolumeManager::checkValidity() const { + if ( m_isValid ) { + return true; + } + else if ( !isValid() ) { + throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 volume manager [Invalid-Handle]")); + } + else if ( !ptr()->valid ) { + throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 geometry info [Invalid-Info]")); + } + m_isValid = true; + return m_isValid; +} + +/// Accessor to resolve G4 placements +G4VPhysicalVolume* Geant4VolumeManager::placement(const TGeoNode* node) const { + if ( node && checkValidity() ) { + const PlacementMap& m = ptr()->g4Placements; + PlacementMap::const_iterator i = m.find(node); + if ( i != m.end() ) return (*i).second; + return 0; + } + throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 volume manager [Invalid-Handle]")); +} + +/// Accessor to resolve geometry placements +PlacedVolume Geant4VolumeManager::placement(const G4VPhysicalVolume* node) const { + if ( node && checkValidity() ) { + const PlacementMap& m = ptr()->g4Placements; + for(PlacementMap::const_iterator i = m.begin(); i != m.end(); ++i) { + if ( (*i).second == node ) return PlacedVolume((*i).first); + } + return PlacedVolume(0); + } + throw runtime_error(format("Geant4VolumeManager","Attempt to lookup invalid TGeo placement [Null-Pointer]")); +} + +/// Access CELLID by placement path +VolumeID Geant4VolumeManager::volumeID(const PlacementPath& path) const { + if ( !path.empty() && checkValidity() ) { + const PathMap& m = ptr()->g4Paths; + PathMap::const_iterator i=m.find(path); + if ( i != m.end() ) return (*i).second; + if ( !path[0] ) + return InvalidPath; + else if ( !path[0]->GetLogicalVolume()->GetSensitiveDetector() ) + return Insensitive; + return NonExisting; + } + return NonExisting; +} + +/// Access CELLID by Geant4 touchable object +VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const { + return volumeID(placementPath(touchable)); +} + +/// Accessfully decoded volume fields by placement path +void Geant4VolumeManager::volumeDescriptor(const PlacementPath& path, VolIDDescriptor& vol_desc) const { + vol_desc.second.clear(); + vol_desc.first = NonExisting; + if ( !path.empty() && checkValidity() ) { + const PathMap& m = ptr()->g4Paths; + PathMap::const_iterator i=m.find(path); + if ( i != m.end() ) { + VolumeID vid = (*i).second; + G4LogicalVolume* lvol = path[0]->GetLogicalVolume(); + if ( lvol->GetSensitiveDetector() ) { + PlacedVolume pv = placement(path[0]); + Geometry::SensitiveDetector sd = pv.volume().sensitiveDetector(); + Geometry::IDDescriptor dsc = sd.readout().idSpec(); + vol_desc.first = vid; + dsc.decodeFields(vid,vol_desc.second); + return; + } + vol_desc.first = Insensitive; + return; + } + if ( !path[0] ) + vol_desc.first = InvalidPath; + else if ( !path[0]->GetLogicalVolume()->GetSensitiveDetector() ) + vol_desc.first = Insensitive; + else + vol_desc.first = NonExisting; + } +} + +/// Access fully decoded volume fields by Geant4 touchable object +void Geant4VolumeManager::volumeDescriptor(const G4VTouchable* touchable, VolIDDescriptor& vol_desc) const { + volumeDescriptor(placementPath(touchable),vol_desc); +} +