ATLAS Offline Software
Loading...
Searching...
No Matches
VolumeDebugger.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "VolumeDebugger.h"
6
7#include "G4GDMLParser.hh"
8#include "G4VPhysicalVolume.hh"
9#include "G4LogicalVolume.hh"
10#include "G4LogicalVolumeStore.hh"
11#include "G4TransportationManager.hh"
12#include "G4Navigator.hh"
13#include "G4NistManager.hh"
14#include "G4PVPlacement.hh"
15
16#include <iostream>
17#include <vector>
18
19#include "GaudiKernel/Bootstrap.h"
20#include "GaudiKernel/ISvcLocator.h"
21#include "GaudiKernel/IMessageSvc.h"
22
24
25
26namespace
27{
28 std::once_flag VolumeDebugger_DumpGeometryOnce;
29}
30
31namespace G4UA
32{
33
35 : AthMessaging(Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc" ),
36 "VolumeDebugger"),
38 {}
39
40 // Pull the EMEC
41 void VolumeDebugger::PullVolumes( G4LogicalVolume* v ) const
42 {
43 if (v==0) return;
44 std::vector<G4VPhysicalVolume*> pv_to_remove;
45 for (unsigned int i=0;i<v->GetNoDaughters();++i){
46 G4VPhysicalVolume * n_v = v->GetDaughter(i);
47 if ( n_v->GetName() == "LArMgr::LAr::EMEC::Pos::InnerWheel" ||
48 n_v->GetName() == "LArMgr::LAr::EMEC::Neg::InnerWheel" ||
49 n_v->GetName() == "LArMgr::LAr::EMEC::Pos::OuterWheel" ||
50 n_v->GetName() == "LArMgr::LAr::EMEC::Neg::OuterWheel" ){
51 // This is one to remove
52 pv_to_remove.push_back(n_v);
53 } else {
54 // Recurse
55 PullVolumes( n_v->GetLogicalVolume() );
56 }
57 }
58 for (unsigned int j=0;j<pv_to_remove.size();++j){
59 v->RemoveDaughter( pv_to_remove[j] );
60 }
61 }
62
64 {
65 G4VPhysicalVolume* W =
66 G4TransportationManager::GetTransportationManager()->
67 GetNavigatorForTracking()->GetWorldVolume();
68
69
70 // Clear out the EMEC if necessary
71 PullVolumes( W->GetLogicalVolume() );
72
73 if(m_config.targetVolume!=""){
74 G4LogicalVolumeStore *lvs = G4LogicalVolumeStore::GetInstance();
75 for (unsigned int i=0;i<lvs->size();++i){
76 for (unsigned int j=0;j<(*lvs)[i]->GetNoDaughters();++j){
77 if ( (*lvs)[i]->GetDaughter(j)->GetName().c_str()==m_config.targetVolume ){
78 //Create a World volume for the sub-tree that will be dumped in the GDML file
79 //NB: without a world volume, the dumped geometry will not be properly defined
80 //in Geant4 and in simulation this will lead to segfaults
81 G4NistManager* nist = G4NistManager::Instance();
82 G4Material* world_mat = nist->FindOrBuildMaterial("G4_AIR");
83 G4VSolid* vBox = W->GetLogicalVolume()->GetSolid();
84 G4LogicalVolume* logicWorld = new G4LogicalVolume(vBox,world_mat,"World");
85 W = new G4PVPlacement(0,G4ThreeVector(),logicWorld,"World",0,false,0,false);
86 new G4PVPlacement(0,G4ThreeVector(),(*lvs)[i]->GetDaughter(j)->GetLogicalVolume(),m_config.targetVolume,logicWorld,false,0,false);
87 // FIXME: Remove this goto!!!
88 goto exitLoop;
89 } // If we found the volume
90 } // Loop over PVs in the LV
91 } // Loop over volumes
92
93 // Did not find the volume
94 ATH_MSG_FATAL("Did not find the volume named " << m_config.targetVolume << ". Please set parameter TargetVolume to one of:\n\n");
95
96 for (unsigned int i = 0; i < lvs->size(); ++i) {
97 for (unsigned int j = 0; j < (*lvs)[i]->GetNoDaughters(); ++j) {
98 ATH_MSG_FATAL( (*lvs)[i]->GetDaughter(j)->GetName());
99 } // Loop over PVs in the LV
100 } // Loop over volumes
101 ATH_MSG_FATAL("\n\n ================= E N D O F L I S T ========================\n\n");
102
103 return; // Really no point in doing anything on the entire Atlas volume
104
105 } // Requested a volume
106
107 exitLoop:
108
109 if (m_config.printGeo) {
110 ATH_MSG_INFO("Dump of the Geant4 world "<<std::endl<<printVolume(W));
111 }
112 if (m_config.dumpGDML) {
113 ATH_MSG_INFO( "Writing to GDML volume " << W->GetName() << " to path " << m_config.path );
114 G4GDMLParser parser;
115 parser.SetRegionExport(m_config.dumpPhysicsRegions);
116 parser.Write(m_config.path, W, true);
117 }
118 if(m_config.volumeCheck){
119 ATH_MSG_INFO( "Running overlap test with parameters " << m_config.res << " " << m_config.tol << " " << m_config.verbose );
120
121 bool hasOverlaps = recursiveCheck(W);
122 if (hasOverlaps) {
123 ATH_MSG_INFO("Overlap check: there were problems with the geometry.");
124 }
125 else {
126 ATH_MSG_INFO("Overlap check: All looks good!");
127 }
128 }
129
130 }
131
133 {
134 std::call_once(VolumeDebugger_DumpGeometryOnce,
136 }
137
138 bool VolumeDebugger::recursiveCheck(G4VPhysicalVolume *topPV) const
139 {
140 bool somethingOverlapped = false;
141 bool hasOverlaps = topPV->CheckOverlaps(m_config.res, m_config.tol, m_config.verbose);
142 if (hasOverlaps && m_config.verbose) ATH_MSG_ERROR("Volume " << topPV->GetName() << " has overlaps.");
143 somethingOverlapped |= hasOverlaps;
144 //
145 // Make a list of PVs keyed by their LVs
146 //
147 std::multimap<G4LogicalVolume *, G4VPhysicalVolume *> lv2pvMap;
148 G4LogicalVolume *lv = topPV->GetLogicalVolume();
149 unsigned int nDaughters = lv->GetNoDaughters();
150 for (unsigned int i = 0; i < nDaughters; ++i) {
151 G4VPhysicalVolume *daughterPV = lv->GetDaughter(i);
152 G4LogicalVolume *daughterLV = daughterPV->GetLogicalVolume();
153 lv2pvMap.insert(std::pair<G4LogicalVolume *, G4VPhysicalVolume *>(daughterLV, daughterPV));
154 }
155
156 for (std::multimap<G4LogicalVolume *, G4VPhysicalVolume *>::iterator mapEl = lv2pvMap.begin(); mapEl != lv2pvMap.end(); ) {
157 //
158 // The first of each LV gets checked externally and internally (recursively).
159 //
160 G4VPhysicalVolume *daughterPV = mapEl->second;
161 hasOverlaps = recursiveCheck(daughterPV);
162 somethingOverlapped |= hasOverlaps;
163 if (hasOverlaps && m_config.verbose) ATH_MSG_ERROR("Volume " << daughterPV->GetName() << " has overlaps.");
164 //
165 // Subsequent PVs with the same LV get only external checks
166 //
167 std::pair <std::multimap<G4LogicalVolume *, G4VPhysicalVolume *>::iterator,
168 std::multimap<G4LogicalVolume *, G4VPhysicalVolume *>::iterator> range = lv2pvMap.equal_range(mapEl->first);
169 ++mapEl;
170 //
171 // Sometimes there are huge numbers of the same item, in the same juxtaposition with nearby elements.
172 // Takes too long to check them all, and in typical geometries it is a waste of time.
173 // So we skip some, controlled by m_targetMaxCopiesToCheck
174 //
175 int n = std::distance(range.first, range.second); // n is total number in this group.
176 int checkEveryNth = int(n / m_config.targetMaxCopiesToCheck + 0.5);
177 if (checkEveryNth <= 0) checkEveryNth = 1;
178 for (int i = 1; i < n; ++i) { // "i = 0" already done
179 if (i % checkEveryNth == 0) {
180 hasOverlaps = mapEl->second->CheckOverlaps(m_config.res, m_config.tol, m_config.verbose);
181 somethingOverlapped |= hasOverlaps;
182 if (hasOverlaps && m_config.verbose) ATH_MSG_ERROR("Volume " << mapEl->second->GetLogicalVolume()->GetName() << " has overlaps.");
183 }
184 ++mapEl;
185 }
186 }
187 return somethingOverlapped;
188 }
189
190 std::string VolumeDebugger::printVolume(const G4VPhysicalVolume *pv, const std::string& childDelim) const {
191 std::stringstream sstr{};
192 const G4ThreeVector trans = pv->GetFrameTranslation();
193 const G4RotationMatrix* rot = pv->GetFrameRotation();
194
195 sstr<<"Volume: "<<pv->GetName()<<", location: "<<Amg::toString(trans, 2)<<", ";
196 if (rot) {
197 sstr<<"orientation: {"<<Amg::toString(rot->colX(), 3)<<", ";
198 sstr<<Amg::toString(rot->colY(), 3)<<", ";
199 sstr<<Amg::toString(rot->colZ(), 3)<<"}";
200 }
201 sstr<<std::endl;
202 G4LogicalVolume* log = pv->GetLogicalVolume();
203 for (size_t d= 0; d <log->GetNoDaughters(); ++d){
204 sstr<<childDelim<<(d+1)<<": "<< printVolume(log->GetDaughter(d),
205 childDelim + " ");
206 }
207 return sstr.str();
208 }
209
210
211} // namespace G4UA
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
std::string printVolume(const G4VPhysicalVolume *pv, const std::string &delim="") const
Config m_config
configuration data
virtual void BeginOfRunAction(const G4Run *) override
hook for G4 UA functionality
bool recursiveCheck(G4VPhysicalVolume *pv) const
Returns true if there were overlaps.
VolumeDebugger(const Config &config)
void PullVolumes(G4LogicalVolume *v) const
volume filter
void DumpGeometry() const
wrapper function for the gdml dump
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
=============================================================================