ATLAS Offline Software
Classes | Public Member Functions | Private Member Functions | Private Attributes | List of all members
G4UA::VolumeDebugger Class Reference

a user action to debug G4 geometries More...

#include <VolumeDebugger.h>

Inheritance diagram for G4UA::VolumeDebugger:
Collaboration diagram for G4UA::VolumeDebugger:

Classes

struct  Config
 

Public Member Functions

 VolumeDebugger (const Config &config)
 
virtual void BeginOfRunAction (const G4Run *) override
 hook for G4 UA functionality More...
 
bool msgLvl (const MSG::Level lvl) const
 Test the output level. More...
 
MsgStream & msg () const
 The standard message stream. More...
 
MsgStream & msg (const MSG::Level lvl) const
 The standard message stream. More...
 
void setLevel (MSG::Level lvl)
 Change the current logging level. More...
 

Private Member Functions

void DumpGeometry () const
 wrapper function for the gdml dump More...
 
void PullVolumes (G4LogicalVolume *v) const
 volume filter More...
 
bool recursiveCheck (G4VPhysicalVolume *pv) const
 Returns true if there were overlaps. More...
 
std::string printVolume (const G4VPhysicalVolume *pv, const std::string &delim="") const
 
void initMessaging () const
 Initialize our message level and MessageSvc. More...
 

Private Attributes

Config m_config
 configuration data More...
 
std::string m_nm
 Message source name. More...
 
boost::thread_specific_ptr< MsgStream > m_msg_tls
 MsgStream instance (a std::cout like with print-out levels) More...
 
std::atomic< IMessageSvc * > m_imsg { nullptr }
 MessageSvc pointer. More...
 
std::atomic< MSG::Level > m_lvl { MSG::NIL }
 Current logging level. More...
 
std::atomic_flag m_initialized ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
 Messaging initialized (initMessaging) More...
 

Detailed Description

a user action to debug G4 geometries

It looks for the volume specified by the user in the TargetVolume parameter. (If it does not find it, it prints a very long list of possibilities, and exits without doing a check). The user can specifiy whether or not to make a GDML dump (I found it a waste of time and disk-space). It checks the specified volume, then does a recursive search through all child volumes. But it only enters into each LogVol once (no point in rechecking inside a LogVol over and over again for each PhysVol that points to it), saving quite some time. Furthermore, the user can specify a new parameter, MaxCopiesToCheck, as a double. Setting this to say 1.e20 will check all PhysVols are inside their MotherVol, and do not collide with any sisters. Setting it to say 10. means max. 10 copies of a LogVol checked. The others are skipped. The 10 chosen are spread out through the list of PhysVols that use the LogVol in question. Setting this parameter to say 2.0 gives a very fast check, while still checking every single type of LogVol at least once. Finds most overlaps very fast.

Definition at line 36 of file VolumeDebugger.h.

Constructor & Destructor Documentation

◆ VolumeDebugger()

G4UA::VolumeDebugger::VolumeDebugger ( const Config config)

Definition at line 34 of file VolumeDebugger.cxx.

35  : AthMessaging(Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc" ),
36  "VolumeDebugger"),
38  {}

Member Function Documentation

◆ BeginOfRunAction()

void G4UA::VolumeDebugger::BeginOfRunAction ( const G4Run *  )
overridevirtual

hook for G4 UA functionality

Definition at line 132 of file VolumeDebugger.cxx.

133  {
134  std::call_once(VolumeDebugger_DumpGeometryOnce,
136  }

◆ DumpGeometry()

void G4UA::VolumeDebugger::DumpGeometry ( ) const
private

wrapper function for the gdml dump

Definition at line 63 of file VolumeDebugger.cxx.

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  }

◆ initMessaging()

void AthMessaging::initMessaging ( ) const
privateinherited

Initialize our message level and MessageSvc.

This method should only be called once.

Definition at line 39 of file AthMessaging.cxx.

40 {
42  m_lvl = m_imsg ?
43  static_cast<MSG::Level>( m_imsg.load()->outputLevel(m_nm) ) :
44  MSG::INFO;
45 }

◆ msg() [1/2]

MsgStream & AthMessaging::msg ( ) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 164 of file AthMessaging.h.

165 {
166  MsgStream* ms = m_msg_tls.get();
167  if (!ms) {
168  if (!m_initialized.test_and_set()) initMessaging();
169  ms = new MsgStream(m_imsg,m_nm);
170  m_msg_tls.reset( ms );
171  }
172 
173  ms->setLevel (m_lvl);
174  return *ms;
175 }

◆ msg() [2/2]

MsgStream & AthMessaging::msg ( const MSG::Level  lvl) const
inlineinherited

The standard message stream.

Returns a reference to the default message stream May not be invoked before sysInitialize() has been invoked.

Definition at line 179 of file AthMessaging.h.

180 { return msg() << lvl; }

◆ msgLvl()

bool AthMessaging::msgLvl ( const MSG::Level  lvl) const
inlineinherited

Test the output level.

Parameters
lvlThe message level to test against
Returns
boolean Indicating if messages at given level will be printed
Return values
trueMessages at level "lvl" will be printed

Definition at line 151 of file AthMessaging.h.

152 {
153  if (!m_initialized.test_and_set()) initMessaging();
154  if (m_lvl <= lvl) {
155  msg() << lvl;
156  return true;
157  } else {
158  return false;
159  }
160 }

◆ printVolume()

std::string G4UA::VolumeDebugger::printVolume ( const G4VPhysicalVolume *  pv,
const std::string &  delim = "" 
) const
private

Definition at line 190 of file VolumeDebugger.cxx.

190  {
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  }

◆ PullVolumes()

void G4UA::VolumeDebugger::PullVolumes ( G4LogicalVolume *  v) const
private

volume filter

Definition at line 41 of file VolumeDebugger.cxx.

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  }

◆ recursiveCheck()

bool G4UA::VolumeDebugger::recursiveCheck ( G4VPhysicalVolume *  pv) const
private

Returns true if there were overlaps.

Definition at line 138 of file VolumeDebugger.cxx.

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  }

◆ setLevel()

void AthMessaging::setLevel ( MSG::Level  lvl)
inherited

Change the current logging level.

Use this rather than msg().setLevel() for proper operation with MT.

Definition at line 28 of file AthMessaging.cxx.

29 {
30  m_lvl = lvl;
31 }

Member Data Documentation

◆ ATLAS_THREAD_SAFE

std::atomic_flag m_initialized AthMessaging::ATLAS_THREAD_SAFE = ATOMIC_FLAG_INIT
mutableprivateinherited

Messaging initialized (initMessaging)

Definition at line 141 of file AthMessaging.h.

◆ m_config

Config G4UA::VolumeDebugger::m_config
private

configuration data

Definition at line 62 of file VolumeDebugger.h.

◆ m_imsg

std::atomic<IMessageSvc*> AthMessaging::m_imsg { nullptr }
mutableprivateinherited

MessageSvc pointer.

Definition at line 135 of file AthMessaging.h.

◆ m_lvl

std::atomic<MSG::Level> AthMessaging::m_lvl { MSG::NIL }
mutableprivateinherited

Current logging level.

Definition at line 138 of file AthMessaging.h.

◆ m_msg_tls

boost::thread_specific_ptr<MsgStream> AthMessaging::m_msg_tls
mutableprivateinherited

MsgStream instance (a std::cout like with print-out levels)

Definition at line 132 of file AthMessaging.h.

◆ m_nm

std::string AthMessaging::m_nm
privateinherited

Message source name.

Definition at line 129 of file AthMessaging.h.


The documentation for this class was generated from the following files:
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
AthMessaging::m_lvl
std::atomic< MSG::Level > m_lvl
Current logging level.
Definition: AthMessaging.h:138
python.CaloScaleNoiseConfig.parser
parser
Definition: CaloScaleNoiseConfig.py:75
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
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
AthMessaging::m_imsg
std::atomic< IMessageSvc * > m_imsg
MessageSvc pointer.
Definition: AthMessaging.h:135
python.SystemOfUnits.ms
int ms
Definition: SystemOfUnits.py:132
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
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
config
Definition: PhysicsAnalysis/AnalysisCommon/AssociationUtils/python/config.py:1
G4UA::VolumeDebugger::Config::tol
float tol
Definition: VolumeDebugger.h:47
AthMessaging::AthMessaging
AthMessaging()
Default constructor:
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
TrigConf::MSGTC::Level
Level
Definition: Trigger/TrigConfiguration/TrigConfBase/TrigConfBase/MsgStream.h:21
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
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
AthMessaging::msg
MsgStream & msg() const
The standard message stream.
Definition: AthMessaging.h:164
python.PyAthena.v
v
Definition: PyAthena.py:157
AthMessaging::m_nm
std::string m_nm
Message source name.
Definition: AthMessaging.h:129
G4UA::VolumeDebugger::Config::targetMaxCopiesToCheck
double targetMaxCopiesToCheck
Definition: VolumeDebugger.h:49
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
python.changerun.pv
pv
Definition: changerun.py:81
G4UA::VolumeDebugger::Config::path
std::string path
Definition: VolumeDebugger.h:43
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
AthMessaging::initMessaging
void initMessaging() const
Initialize our message level and MessageSvc.
Definition: AthMessaging.cxx:39
AthMessaging::m_msg_tls
boost::thread_specific_ptr< MsgStream > m_msg_tls
MsgStream instance (a std::cout like with print-out levels)
Definition: AthMessaging.h:132
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