Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4GeometryManager.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// Class G4GeometryManager implementation
27//
28// 26.07.95, P.Kent - Initial version, including optimisation build
29// --------------------------------------------------------------------
30
31#include <iomanip>
32
33#include "G4Timer.hh"
34#include "G4GeometryManager.hh"
35#include "G4SystemOfUnits.hh"
36#include "G4Threading.hh"
37
38#ifdef G4GEOMETRY_VOXELDEBUG
39#include "G4ios.hh"
40#endif
41
42// Needed for building optimisations
43//
45#include "G4VPhysicalVolume.hh"
46#include "G4SmartVoxelHeader.hh"
47#include "voxeldefs.hh"
48
49// Needed for setting the extent for tolerance value
50//
52#include "G4SolidStore.hh"
53#include "G4VSolid.hh"
54
55// ***************************************************************************
56// Static class data
57// ***************************************************************************
58//
59G4ThreadLocal G4GeometryManager* G4GeometryManager::fgInstance = nullptr;
60G4ThreadLocal G4bool G4GeometryManager::fIsClosed = false;
61
62// ***************************************************************************
63// Destructor
64// ***************************************************************************
65//
67{
68 fgInstance = nullptr;
69 fIsClosed = false;
70}
71
72// ***************************************************************************
73// Closes geometry - performs sanity checks and optionally builds optimisation
74// for placed volumes (always built for replicas & parameterised).
75// NOTE: Currently no sanity checks are performed.
76// Applies to just a specific subtree if a physical volume is specified.
77// ***************************************************************************
78//
80 G4VPhysicalVolume* pVolume)
81{
82 if (!fIsClosed && G4Threading::IsMasterThread())
83 {
84 if (pVolume != nullptr)
85 {
86 BuildOptimisations(pOptimise, pVolume);
87 }
88 else
89 {
90 BuildOptimisations(pOptimise, verbose);
91 }
92 fIsClosed = true;
93 }
94 return true;
95}
96
97// ***************************************************************************
98// Opens the geometry and removes optimisations (optionally, related to just
99// the specified logical-volume).
100// Applies to just a specific subtree if a physical volume is specified.
101// ***************************************************************************
102//
104{
105 if (fIsClosed && G4Threading::IsMasterThread())
106 {
107 if (pVolume != nullptr)
108 {
109 DeleteOptimisations(pVolume);
110 }
111 else
112 {
113 DeleteOptimisations();
114 }
115 fIsClosed = false;
116 }
117}
118
119// ***************************************************************************
120// Returns status of geometry
121// ***************************************************************************
122//
124{
125 return fIsClosed;
126}
127
128// ***************************************************************************
129// Returns the instance of the singleton.
130// Creates it in case it's called for the first time.
131// ***************************************************************************
132//
134{
135 if (fgInstance == nullptr)
136 {
137 fgInstance = new G4GeometryManager;
138 }
139 return fgInstance;
140}
141
142// ***************************************************************************
143// Returns the instance of the singleton.
144// ***************************************************************************
145//
147{
148 return fgInstance;
149}
150
151// ***************************************************************************
152// Creates optimisation info. Builds all voxels if allOpts=true
153// otherwise it builds voxels only for replicated volumes.
154// ***************************************************************************
155//
156void G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose)
157{
158 G4Timer timer;
159 G4Timer allTimer;
160 std::vector<G4SmartVoxelStat> stats;
161 if (verbose) { allTimer.Start(); }
162
164 G4LogicalVolume* volume;
165 G4SmartVoxelHeader* head;
166
167 for (size_t n=0; n<Store->size(); ++n)
168 {
169 if (verbose) timer.Start();
170 volume=(*Store)[n];
171 // For safety, check if there are any existing voxels and
172 // delete before replacement
173 //
174 head = volume->GetVoxelHeader();
175 delete head;
176 volume->SetVoxelHeader(nullptr);
177 if ( ( (volume->IsToOptimise())
178 && (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
179 || ( (volume->GetNoDaughters()==1)
180 && (volume->GetDaughter(0)->IsReplicated()==true)
181 && (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) )
182 {
183#ifdef G4GEOMETRY_VOXELDEBUG
184 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
185 << " Examining logical volume name = "
186 << volume->GetName() << G4endl;
187#endif
188 head = new G4SmartVoxelHeader(volume);
189 if (head != nullptr)
190 {
191 volume->SetVoxelHeader(head);
192 }
193 else
194 {
195 std::ostringstream message;
196 message << "VoxelHeader allocation error." << G4endl
197 << "Allocation of new VoxelHeader" << G4endl
198 << " for volume " << volume->GetName() << " failed.";
199 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
200 FatalException, message);
201 }
202 if (verbose)
203 {
204 timer.Stop();
205 stats.push_back( G4SmartVoxelStat( volume, head,
206 timer.GetSystemElapsed(),
207 timer.GetUserElapsed() ) );
208 }
209 }
210 else
211 {
212 // Don't create voxels for this node
213#ifdef G4GEOMETRY_VOXELDEBUG
214 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
215 << " Skipping logical volume name = " << volume->GetName()
216 << G4endl;
217#endif
218 }
219 }
220 if (verbose)
221 {
222 allTimer.Stop();
223 ReportVoxelStats( stats, allTimer.GetSystemElapsed()
224 + allTimer.GetUserElapsed() );
225 }
226}
227
228// ***************************************************************************
229// Creates optimisation info for the specified volumes subtree.
230// ***************************************************************************
231//
232void G4GeometryManager::BuildOptimisations(G4bool allOpts,
233 G4VPhysicalVolume* pVolume)
234{
235 if (pVolume == nullptr) { return; }
236
237 // Retrieve the mother logical volume, if not NULL,
238 // otherwise apply global optimisation for the world volume
239 //
240 G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
241 if (tVolume == nullptr) { return BuildOptimisations(allOpts, false); }
242
243 G4SmartVoxelHeader* head = tVolume->GetVoxelHeader();
244 delete head;
245 tVolume->SetVoxelHeader(nullptr);
246 if ( ( (tVolume->IsToOptimise())
247 && (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
248 || ( (tVolume->GetNoDaughters()==1)
249 && (tVolume->GetDaughter(0)->IsReplicated()==true) ) )
250 {
251 head = new G4SmartVoxelHeader(tVolume);
252 if (head != nullptr)
253 {
254 tVolume->SetVoxelHeader(head);
255 }
256 else
257 {
258 std::ostringstream message;
259 message << "VoxelHeader allocation error." << G4endl
260 << "Allocation of new VoxelHeader" << G4endl
261 << " for volume " << tVolume->GetName() << " failed.";
262 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
263 FatalException, message);
264 }
265 }
266 else
267 {
268 // Don't create voxels for this node
269#ifdef G4GEOMETRY_VOXELDEBUG
270 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
271 << " Skipping logical volume name = " << tVolume->GetName()
272 << G4endl;
273#endif
274 }
275
276 // Scan recursively the associated logical volume tree
277 //
278 tVolume = pVolume->GetLogicalVolume();
279 if (tVolume->GetNoDaughters())
280 {
281 BuildOptimisations(allOpts, tVolume->GetDaughter(0));
282 }
283}
284
285// ***************************************************************************
286// Removes all optimisation info.
287// Loops over all logical volumes, deleting non-null voxels pointers,
288// ***************************************************************************
289//
290void G4GeometryManager::DeleteOptimisations()
291{
292 G4LogicalVolume* tVolume = nullptr;
294 for (size_t n=0; n<Store->size(); ++n)
295 {
296 tVolume=(*Store)[n];
297 delete tVolume->GetVoxelHeader();
298 tVolume->SetVoxelHeader(nullptr);
299 }
300}
301
302// ***************************************************************************
303// Removes optimisation info for the specified subtree.
304// Scans recursively all daughter volumes, deleting non-null voxels pointers.
305// ***************************************************************************
306//
307void G4GeometryManager::DeleteOptimisations(G4VPhysicalVolume* pVolume)
308{
309 if (!pVolume) { return; }
310
311 // Retrieve the mother logical volume, if not NULL,
312 // otherwise global deletion to world volume.
313 //
314 G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
315 if (tVolume == nullptr) { return DeleteOptimisations(); }
316 delete tVolume->GetVoxelHeader();
317 tVolume->SetVoxelHeader(nullptr);
318
319 // Scan recursively the associated logical volume tree
320 //
321 tVolume = pVolume->GetLogicalVolume();
322 if (tVolume->GetNoDaughters())
323 {
324 DeleteOptimisations(tVolume->GetDaughter(0));
325 }
326}
327
328// ***************************************************************************
329// Sets the maximum extent of the world volume. The operation is allowed only
330// if NO solids have been created already.
331// ***************************************************************************
332//
334{
335 if (G4SolidStore::GetInstance()->size())
336 {
337 // Sanity check to assure that extent is fixed BEFORE creating
338 // any geometry object (solids in this case)
339 //
340 G4Exception("G4GeometryManager::SetMaximumExtent()",
341 "GeomMgt0003", FatalException,
342 "Extent can be set only BEFORE creating any geometry object!");
343 }
345}
346
347// ***************************************************************************
348// Reports statistics on voxel optimisation when closing geometry.
349// ***************************************************************************
350//
351void
352G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
353 G4double totalCpuTime )
354{
355 G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics"
356 << G4endl << G4endl;
357
358 //
359 // Get total memory use
360 //
361 G4int i, nStat = (G4int)stats.size();
362 G4long totalMemory = 0;
363
364 for( i=0; i<nStat; ++i ) { totalMemory += stats[i].GetMemoryUse(); }
365
366 G4cout << " Total memory consumed for geometry optimisation: "
367 << totalMemory/1024 << " kByte" << G4endl;
368 G4cout << " Total CPU time elapsed for geometry optimisation: "
369 << std::setprecision(2) << totalCpuTime << " seconds"
370 << std::setprecision(6) << G4endl;
371
372 //
373 // First list: sort by total CPU time
374 //
375 std::sort( stats.begin(), stats.end(),
376 [](const G4SmartVoxelStat& a, const G4SmartVoxelStat& b)
377 {
378 return a.GetTotalTime() > b.GetTotalTime();
379 } );
380
381 G4int nPrint = nStat > 10 ? 10 : nStat;
382
383 if (nPrint)
384 {
385 G4cout << "\n Voxelisation: top CPU users:" << G4endl;
386 G4cout << " Percent Total CPU System CPU Memory Volume\n"
387 << " ------- ---------- ---------- -------- ----------"
388 << G4endl;
389 // 12345678901.234567890123.234567890123.234567890123k .
390 }
391
392 for(i=0; i<nPrint; ++i)
393 {
394 G4double total = stats[i].GetTotalTime();
395 G4double system = stats[i].GetSysTime();
396 G4double perc = 0.0;
397
398 if (system < 0) { system = 0.0; }
399 if ((total < 0) || (totalCpuTime < perMillion))
400 { total = 0; }
401 else
402 { perc = total*100/totalCpuTime; }
403
404 G4cout << std::setprecision(2)
405 << std::setiosflags(std::ios::fixed|std::ios::right)
406 << std::setw(11) << perc
407 << std::setw(13) << total
408 << std::setw(13) << system
409 << std::setw(13) << (stats[i].GetMemoryUse()+512)/1024
410 << "k " << std::setiosflags(std::ios::left)
411 << stats[i].GetVolume()->GetName()
412 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield)
413 << std::setprecision(6)
414 << G4endl;
415 }
416
417 //
418 // Second list: sort by memory use
419 //
420 std::sort( stats.begin(), stats.end(),
421 [](const G4SmartVoxelStat& a, const G4SmartVoxelStat& b)
422 {
423 return a.GetMemoryUse() > b.GetMemoryUse();
424 } );
425
426 if (nPrint)
427 {
428 G4cout << "\n Voxelisation: top memory users:" << G4endl;
429 G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n"
430 << " ------- -------- ------ ------ -------- ---------- ----------"
431 << G4endl;
432 // 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. .
433 }
434
435 for(i=0; i<nPrint; ++i)
436 {
437 G4long memory = stats[i].GetMemoryUse();
438 G4double totTime = stats[i].GetTotalTime();
439 if (totTime < 0) { totTime = 0.0; }
440
441 G4cout << std::setprecision(2)
442 << std::setiosflags(std::ios::fixed|std::ios::right)
443 << std::setw(11) << G4double(memory*100)/G4double(totalMemory)
444 << std::setw(11) << memory/1024 << "k "
445 << std::setw( 9) << stats[i].GetNumberHeads()
446 << std::setw( 9) << stats[i].GetNumberNodes()
447 << std::setw(11) << stats[i].GetNumberPointers()
448 << std::setw(13) << totTime << " "
449 << std::setiosflags(std::ios::left)
450 << stats[i].GetVolume()->GetName()
451 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield)
452 << std::setprecision(6)
453 << G4endl;
454 }
455}
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
double G4double
Definition: G4Types.hh:83
long G4long
Definition: G4Types.hh:87
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
G4GeometryManager()=default
static G4bool IsGeometryClosed()
static G4GeometryManager * GetInstance()
G4bool CloseGeometry(G4bool pOptimise=true, G4bool verbose=false, G4VPhysicalVolume *vol=nullptr)
void SetWorldMaximumExtent(G4double worldExtent)
void OpenGeometry(G4VPhysicalVolume *vol=nullptr)
static G4GeometryManager * GetInstanceIfExist()
void SetSurfaceTolerance(G4double worldExtent)
static G4GeometryTolerance * GetInstance()
static G4LogicalVolumeStore * GetInstance()
void SetVoxelHeader(G4SmartVoxelHeader *pVoxel)
std::size_t GetNoDaughters() const
G4VPhysicalVolume * GetDaughter(const std::size_t i) const
G4bool IsToOptimise() const
const G4String & GetName() const
G4SmartVoxelHeader * GetVoxelHeader() const
static G4SolidStore * GetInstance()
void Stop()
G4double GetSystemElapsed() const
Definition: G4Timer.cc:124
G4double GetUserElapsed() const
Definition: G4Timer.cc:135
void Start()
G4LogicalVolume * GetMotherLogical() const
virtual G4bool IsReplicated() const =0
G4LogicalVolume * GetLogicalVolume() const
virtual G4int GetRegularStructureId() const =0
G4double total(Particle const *const p1, Particle const *const p2)
G4bool IsMasterThread()
Definition: G4Threading.cc:124
#define G4ThreadLocal
Definition: tls.hh:77
const G4int kMinVoxelVolumesLevel1
Definition: voxeldefs.hh:39