Newer
Older
Markus Frank
committed
//==========================================================================
// AIDA Detector description implementation for LCD
Markus Frank
committed
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
Markus Frank
committed
// All rights reserved.
Markus Frank
committed
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
Markus Frank
committed
// Author : M.Frank
//
//==========================================================================
// Framework include files
#include "DD4hep/Printout.h"
#include "DD4hep/Volumes.h"
#include "DD4hep/Detector.h"
#include "DD4hep/DetectorTools.h"
#include "DDG4/Geant4VolumeManager.h"
#include "DDG4/Geant4TouchableHandler.h"
#include "DDG4/Geant4Mapping.h"
// Geant4 include files
#include "G4VTouchable.hh"
#include "G4LogicalVolume.hh"
#include "G4VPhysicalVolume.hh"
// C/C++ include files
#include <sstream>
using namespace DD4hep::Simulation;
using namespace DD4hep::Simulation::Geant4GeometryMaps;
using namespace DD4hep::Geometry;
using namespace DD4hep;
using namespace std;
#include "DDG4/Geant4AssemblyVolume.h"
namespace {
/// Helper class to populate the Geant4 volume manager
struct Populator {
typedef vector<const TGeoNode*> Chain;
typedef DD4hep::Geometry::LCDD LCDD;
typedef DD4hep::Geometry::Readout Readout;
typedef DD4hep::Geometry::DetElement DetElement;
typedef map<VolumeID,Geant4PlacementPath> Registries;
/// Reference to the LCDD instance
/// Set of already added entries
/// Reference to Geant4 translation information
Geant4GeometryInfo& m_geo;
/// Default constructor
Populator(LCDD& lcdd, Geant4GeometryInfo& g)
Markus Frank
committed
: m_lcdd(lcdd), m_geo(g) {
}
/// Populate the Volume manager
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();
Markus Frank
committed
chain.push_back(m_lcdd.world().placement().ptr());
scanPhysicalVolume(pv.ptr(), ids, sd, chain);
continue;
}
printout(WARNING, "Geant4VolumeManager", "++ 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, "Geant4VolumeManager",
Markus Frank
committed
"populate: 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);
Markus Frank
committed
PlacedVolume placement(daughter);
if ( placement.data() ) {
scanPhysicalVolume(daughter, ids, sd, chain);
}
}
chain.pop_back();
}
void add_entry(SensitiveDetector sd, const TGeoNode* /* n */, const PlacedVolume::VolIDs& ids, const Chain& nodes) {
Chain control;
const TGeoNode* node;
Geant4PlacementPath path;
Readout ro = sd.readout();
IDDescriptor iddesc = ro.idSpec();
VolumeID code = iddesc.encode(ids);
Registries::const_iterator i = m_entries.find(code);
PrintLevel print_action = VERBOSE;
PrintLevel print_chain = VERBOSE;
PrintLevel print_res = VERBOSE;
Markus Frank
committed
printout(print_action,"Geant4VolumeManager","+++ Add path:%s vid:%016X",
Markus Frank
committed
DetectorTools::placementPath(nodes,false).c_str(),code);
for (Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k) {
node = *(k);
PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(node);
Markus Frank
committed
if (g4pit != m_geo.g4Placements.end()) {
path.push_back((*g4pit).second);
Markus Frank
committed
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s [%s]",
node->GetName(), (*g4pit).second->GetName().c_str());
continue;
}
control.insert(control.begin(),node);
vol = Volume(node->GetVolume());
VolumeImprintMap::const_iterator iVolImp = m_geo.g4VolumeImprints.find(vol);
if ( iVolImp != m_geo.g4VolumeImprints.end() ) {
const Imprints& imprints = (*iVolImp).second;
//size_t len = kend-k;
for(Imprints::const_iterator iImp=imprints.begin(); iImp != imprints.end(); ++iImp) {
const VolumeChain& c = (*iImp).first;
if ( c.size() <= control.size() && control == c ) {
path.push_back((*iImp).second);
printout(print_chain, "Geant4VolumeManager", "+++ Chain: Node OK: %s %s -> %s",
node->GetName(), DetectorTools::placementPath(c,false).c_str(),
(*iImp).second->GetName().c_str());
control.clear();
break;
}
}
}
}
if ( control.empty() ) {
printout(print_res, "Geant4VolumeManager", "+++ Volume IDs:%s",
DetectorTools::toString(ro.idSpec(),ids,code).c_str());
path.erase(path.begin()+path.size()-1);
printout(print_res, "Geant4VolumeManager", "+++ Map %016X to Geant4 Path:%s",
(void*)code, placementPath(path).c_str());
if (m_geo.g4Paths.find(path) == m_geo.g4Paths.end()) {
m_geo.g4Paths[path] = code;
m_entries.insert(make_pair(code,path));
return;
Markus Frank
committed
printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Geant4 path!!!! %s %s",
" [THIS SHOULD NEVER HAPPEN]",placementPath(path).c_str());
goto Err;
}
printout(INFO, "Geant4VolumeManager", "Control block has still %d entries:%s",
int(control.size()),DetectorTools::placementPath(control,true).c_str());
goto Err;
printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Volume entry: %X"
Markus Frank
committed
" [THIS SHOULD NEVER HAPPEN]", code);
Err:
Markus Frank
committed
if ( i != m_entries.end() )
printout(ERROR,"Geant4VolumeManager"," Known G4 path: %s",placementPath((*i).second).c_str());
Markus Frank
committed
printout(ERROR,"Geant4VolumeManager"," New G4 path: %s",placementPath(path).c_str());
Markus Frank
committed
printout(ERROR,"Geant4VolumeManager"," TGeo path: %s",DetectorTools::placementPath(nodes,false).c_str());
printout(ERROR,"Geant4VolumeManager", " Offend.VolIDs: %s",DetectorTools::toString(ro.idSpec(),ids,code).c_str());
throw runtime_error("Failed to populate Geant4 volume manager!");
}
};
}
/// Initializing constructor. The tree will automatically be built if possible
Geant4VolumeManager::Geant4VolumeManager(LCDD& lcdd, Geant4GeometryInfo* info)
Markus Frank
committed
: 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
Geant4PlacementPath Geant4VolumeManager::placementPath(const G4VTouchable* touchable, bool exception) const {
Geant4TouchableHandler handler(touchable);
return handler.placementPath(exception);
}
/// 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;
}
/// Access CELLID by placement path
VolumeID Geant4VolumeManager::volumeID(const PlacementPath& path) const {
if (!path.empty() && checkValidity()) {
const Geant4PathMap& m = ptr()->g4Paths;
Geant4PathMap::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;
}
Markus Frank
committed
printout(INFO, "Geant4VolumeManager","+++ Bad volume Geant4 Path: %s",
Geant4GeometryMaps::placementPath(path).c_str());
return NonExisting;
}
/// Access CELLID by Geant4 touchable object
VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
Geant4TouchableHandler handler(touchable);
return volumeID(handler.placementPath());
}
/// 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 Geant4PathMap& m = ptr()->g4Paths;
Geant4PathMap::const_iterator i = m.find(path);
VolumeID vid = (*i).second;
G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
if (lvol->GetSensitiveDetector()) {
Markus Frank
committed
const G4VPhysicalVolume* node = path[0];
Markus Frank
committed
const PlacementMap& pm = ptr()->g4Placements;
for (PlacementMap::const_iterator ipm = pm.begin(); ipm != pm.end(); ++ipm) {
if ((*ipm).second == node) {
PlacedVolume pv = (*ipm).first;
Markus Frank
committed
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;
}
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);