Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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