ATLAS Offline Software
Loading...
Searching...
No Matches
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
bool msgLvl (const MSG::Level lvl) const
 Test the output level.
MsgStream & msg () const
 The standard message stream.
MsgStream & msg (const MSG::Level lvl) const
 The standard message stream.
void setLevel (MSG::Level lvl)
 Change the current logging level.

Private Member Functions

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

Private Attributes

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

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"),
37 m_config(config)
38 {}
AthMessaging()
Default constructor:
Config m_config
configuration data

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 }
void DumpGeometry() const
wrapper function for the gdml dump

◆ 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 }
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
std::string printVolume(const G4VPhysicalVolume *pv, const std::string &delim="") const
bool recursiveCheck(G4VPhysicalVolume *pv) const
Returns true if there were overlaps.
void PullVolumes(G4LogicalVolume *v) const
volume filter

◆ 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 // If user did not set an explicit level, set a default
43 if (m_lvl == MSG::NIL) {
44 m_lvl = m_imsg ?
45 static_cast<MSG::Level>( m_imsg.load()->outputLevel(m_nm) ) :
46 MSG::INFO;
47 }
48}
std::string m_nm
Message source name.
std::atomic< IMessageSvc * > m_imsg
MessageSvc pointer.
std::atomic< MSG::Level > m_lvl
Current logging level.
IMessageSvc * getMessageSvc(bool quiet=false)

◆ 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 163 of file AthMessaging.h.

164{
165 MsgStream* ms = m_msg_tls.get();
166 if (!ms) {
167 if (!m_initialized.test_and_set()) initMessaging();
168 ms = new MsgStream(m_imsg,m_nm);
169 m_msg_tls.reset( ms );
170 }
171
172 ms->setLevel (m_lvl);
173 return *ms;
174}
boost::thread_specific_ptr< MsgStream > m_msg_tls
MsgStream instance (a std::cout like with print-out levels)
void initMessaging() const
Initialize our message level and MessageSvc.

◆ 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 178 of file AthMessaging.h.

179{ return msg() << lvl; }
MsgStream & msg() const
The standard message stream.

◆ 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_lvl <= lvl) {
154 msg() << lvl;
155 return true;
156 } else {
157 return false;
158 }
159}

◆ 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 }
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.

◆ 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 //
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 }
#define ATH_MSG_ERROR(x)

◆ 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.

135{ nullptr };

◆ m_lvl

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

Current logging level.

Definition at line 138 of file AthMessaging.h.

138{ MSG::NIL };

◆ 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: