ATLAS Offline Software
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 
26 namespace
27 {
28  std::once_flag VolumeDebugger_DumpGeometryOnce;
29 }
30 
31 namespace G4UA
32 {
33 
35  : AthMessaging(Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc" ),
36  "VolumeDebugger"),
37  m_config(config)
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  //
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
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
python.CaloScaleNoiseConfig.parser
parser
Definition: CaloScaleNoiseConfig.py:75
G4UA::VolumeDebugger::Config
Definition: VolumeDebugger.h:42
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
G4UA::VolumeDebugger::Config::dumpGDML
bool dumpGDML
Definition: VolumeDebugger.h:50
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
G4UA
for nSW
Definition: CalibrationDefaultProcessing.h:19
JetTiledMap::W
@ W
Definition: TiledEtaPhiMap.h:44
hist_file_dump.d
d
Definition: hist_file_dump.py:137
G4UA::VolumeDebugger::Config::res
int res
Definition: VolumeDebugger.h:45
VolumeDebugger.h
G4UA::VolumeDebugger::printVolume
std::string printVolume(const G4VPhysicalVolume *pv, const std::string &delim="") const
Definition: VolumeDebugger.cxx:190
G4UA::VolumeDebugger::recursiveCheck
bool recursiveCheck(G4VPhysicalVolume *pv) const
Returns true if there were overlaps.
Definition: VolumeDebugger.cxx:138
config
Definition: PhysicsAnalysis/AnalysisCommon/AssociationUtils/python/config.py:1
G4UA::VolumeDebugger::Config::tol
float tol
Definition: VolumeDebugger.h:47
G4UA::VolumeDebugger::BeginOfRunAction
virtual void BeginOfRunAction(const G4Run *) override
hook for G4 UA functionality
Definition: VolumeDebugger.cxx:132
G4UA::VolumeDebugger::Config::printGeo
bool printGeo
Definition: VolumeDebugger.h:52
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:92
G4UA::VolumeDebugger::Config::dumpPhysicsRegions
bool dumpPhysicsRegions
Definition: VolumeDebugger.h:51
beamspotman.n
n
Definition: beamspotman.py:731
G4UA::VolumeDebugger::Config::volumeCheck
bool volumeCheck
Definition: VolumeDebugger.h:48
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
G4UA::VolumeDebugger::VolumeDebugger
VolumeDebugger(const Config &config)
Definition: VolumeDebugger.cxx:34
G4UA::VolumeDebugger::Config::targetVolume
std::string targetVolume
Definition: VolumeDebugger.h:44
G4UA::VolumeDebugger::m_config
Config m_config
configuration data
Definition: VolumeDebugger.h:62
G4UA::VolumeDebugger::PullVolumes
void PullVolumes(G4LogicalVolume *v) const
volume filter
Definition: VolumeDebugger.cxx:41
python.PyAthena.v
v
Definition: PyAthena.py:157
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
G4UA::VolumeDebugger::Config::targetMaxCopiesToCheck
double targetMaxCopiesToCheck
Definition: VolumeDebugger.h:49
python.changerun.pv
pv
Definition: changerun.py:81
GeoPrimitivesToStringConverter.h
G4UA::VolumeDebugger::Config::path
std::string path
Definition: VolumeDebugger.h:43
Gaudi
=============================================================================
Definition: CaloGPUClusterAndCellDataMonitorOptions.h:273
G4UA::VolumeDebugger::DumpGeometry
void DumpGeometry() const
wrapper function for the gdml dump
Definition: VolumeDebugger.cxx:63
G4UA::VolumeDebugger::Config::verbose
bool verbose
Definition: VolumeDebugger.h:46
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54