Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// $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",
"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);
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() ) {
Geant4Mapping::PlacementPath path;
path.reserve(nodes.size());
for(Chain::const_reverse_iterator i=nodes.rbegin(); i != nodes.rend(); ++i) {
const TGeoNode* node = *i;
PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(node);
if ( g4pit != m_geo.g4Placements.end() ) {
path.push_back((*g4pit).second);
}
}
if ( m_geo.g4Paths.find(path) != m_geo.g4Paths.end() ) {
printout(ERROR,"VolumeManager","populate: Severe error: Duplicated Geant4 path!!!!");
}
m_geo.g4Paths[path] = code;
m_entries.insert(code);
}
else {
printout(ERROR,"VolumeManager","populate: Severe error: Duplicated Volume entry: %X",code);
118
119
120
121
122
123
124
125
126
127
128
129
130
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
}
}
};
}
/// 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);
}