Geant4-11
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
37#ifdef G4GEOMETRY_VOXELDEBUG
38#include "G4ios.hh"
39#endif
40
41// Needed for building optimisations
42//
44#include "G4VPhysicalVolume.hh"
45#include "G4SmartVoxelHeader.hh"
46#include "voxeldefs.hh"
47
48// Needed for setting the extent for tolerance value
49//
51#include "G4SolidStore.hh"
52#include "G4VSolid.hh"
53
54// ***************************************************************************
55// Static class data
56// ***************************************************************************
57//
60
61// ***************************************************************************
62// Destructor
63// ***************************************************************************
64//
66{
67 fgInstance = nullptr;
68 fIsClosed = false;
69}
70
71// ***************************************************************************
72// Closes geometry - performs sanity checks and optionally builds optimisation
73// for placed volumes (always built for replicas & parameterised).
74// NOTE: Currently no sanity checks are performed.
75// Applies to just a specific subtree if a physical volume is specified.
76// ***************************************************************************
77//
79 G4VPhysicalVolume* pVolume)
80{
81 if (!fIsClosed)
82 {
83 if (pVolume != nullptr)
84 {
85 BuildOptimisations(pOptimise, pVolume);
86 }
87 else
88 {
89 BuildOptimisations(pOptimise, verbose);
90 }
91 fIsClosed = true;
92 }
93 return true;
94}
95
96// ***************************************************************************
97// Opens the geometry and removes optimisations (optionally, related to just
98// the specified logical-volume).
99// Applies to just a specific subtree if a physical volume is specified.
100// ***************************************************************************
101//
103{
104 if (fIsClosed)
105 {
106 if (pVolume != nullptr)
107 {
108 DeleteOptimisations(pVolume);
109 }
110 else
111 {
113 }
114 fIsClosed = false;
115 }
116}
117
118// ***************************************************************************
119// Returns status of geometry
120// ***************************************************************************
121//
123{
124 return fIsClosed;
125}
126
127// ***************************************************************************
128// Returns the instance of the singleton.
129// Creates it in case it's called for the first time.
130// ***************************************************************************
131//
133{
134 if (fgInstance == nullptr)
135 {
137 }
138 return fgInstance;
139}
140
141// ***************************************************************************
142// Returns the instance of the singleton.
143// ***************************************************************************
144//
146{
147 return fgInstance;
148}
149
150// ***************************************************************************
151// Creates optimisation info. Builds all voxels if allOpts=true
152// otherwise it builds voxels only for replicated volumes.
153// ***************************************************************************
154//
156{
157 G4Timer timer;
158 G4Timer allTimer;
159 std::vector<G4SmartVoxelStat> stats;
160 if (verbose) { allTimer.Start(); }
161
163 G4LogicalVolume* volume;
164 G4SmartVoxelHeader* head;
165
166 for (size_t n=0; n<Store->size(); ++n)
167 {
168 if (verbose) timer.Start();
169 volume=(*Store)[n];
170 // For safety, check if there are any existing voxels and
171 // delete before replacement
172 //
173 head = volume->GetVoxelHeader();
174 delete head;
175 volume->SetVoxelHeader(nullptr);
176 if ( ( (volume->IsToOptimise())
177 && (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
178 || ( (volume->GetNoDaughters()==1)
179 && (volume->GetDaughter(0)->IsReplicated()==true)
180 && (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) )
181 {
182#ifdef G4GEOMETRY_VOXELDEBUG
183 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
184 << " Examining logical volume name = "
185 << volume->GetName() << G4endl;
186#endif
187 head = new G4SmartVoxelHeader(volume);
188 if (head != nullptr)
189 {
190 volume->SetVoxelHeader(head);
191 }
192 else
193 {
194 std::ostringstream message;
195 message << "VoxelHeader allocation error." << G4endl
196 << "Allocation of new VoxelHeader" << G4endl
197 << " for volume " << volume->GetName() << " failed.";
198 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
199 FatalException, message);
200 }
201 if (verbose)
202 {
203 timer.Stop();
204 stats.push_back( G4SmartVoxelStat( volume, head,
205 timer.GetSystemElapsed(),
206 timer.GetUserElapsed() ) );
207 }
208 }
209 else
210 {
211 // Don't create voxels for this node
212#ifdef G4GEOMETRY_VOXELDEBUG
213 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
214 << " Skipping logical volume name = " << volume->GetName()
215 << G4endl;
216#endif
217 }
218 }
219 if (verbose)
220 {
221 allTimer.Stop();
222 ReportVoxelStats( stats, allTimer.GetSystemElapsed()
223 + allTimer.GetUserElapsed() );
224 }
225}
226
227// ***************************************************************************
228// Creates optimisation info for the specified volumes subtree.
229// ***************************************************************************
230//
232 G4VPhysicalVolume* pVolume)
233{
234 if (pVolume == nullptr) { return; }
235
236 // Retrieve the mother logical volume, if not NULL,
237 // otherwise apply global optimisation for the world volume
238 //
239 G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
240 if (tVolume == nullptr) { return BuildOptimisations(allOpts, false); }
241
242 G4SmartVoxelHeader* head = tVolume->GetVoxelHeader();
243 delete head;
244 tVolume->SetVoxelHeader(nullptr);
245 if ( ( (tVolume->IsToOptimise())
246 && (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
247 || ( (tVolume->GetNoDaughters()==1)
248 && (tVolume->GetDaughter(0)->IsReplicated()==true) ) )
249 {
250 head = new G4SmartVoxelHeader(tVolume);
251 if (head != nullptr)
252 {
253 tVolume->SetVoxelHeader(head);
254 }
255 else
256 {
257 std::ostringstream message;
258 message << "VoxelHeader allocation error." << G4endl
259 << "Allocation of new VoxelHeader" << G4endl
260 << " for volume " << tVolume->GetName() << " failed.";
261 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
262 FatalException, message);
263 }
264 }
265 else
266 {
267 // Don't create voxels for this node
268#ifdef G4GEOMETRY_VOXELDEBUG
269 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
270 << " Skipping logical volume name = " << tVolume->GetName()
271 << G4endl;
272#endif
273 }
274
275 // Scan recursively the associated logical volume tree
276 //
277 tVolume = pVolume->GetLogicalVolume();
278 if (tVolume->GetNoDaughters())
279 {
280 BuildOptimisations(allOpts, tVolume->GetDaughter(0));
281 }
282}
283
284// ***************************************************************************
285// Removes all optimisation info.
286// Loops over all logical volumes, deleting non-null voxels pointers,
287// ***************************************************************************
288//
290{
291 G4LogicalVolume* tVolume = nullptr;
293 for (size_t n=0; n<Store->size(); ++n)
294 {
295 tVolume=(*Store)[n];
296 delete tVolume->GetVoxelHeader();
297 tVolume->SetVoxelHeader(nullptr);
298 }
299}
300
301// ***************************************************************************
302// Removes optimisation info for the specified subtree.
303// Scans recursively all daughter volumes, deleting non-null voxels pointers.
304// ***************************************************************************
305//
307{
308 if (!pVolume) { return; }
309
310 // Retrieve the mother logical volume, if not NULL,
311 // otherwise global deletion to world volume.
312 //
313 G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
314 if (tVolume == nullptr) { return DeleteOptimisations(); }
315 delete tVolume->GetVoxelHeader();
316 tVolume->SetVoxelHeader(nullptr);
317
318 // Scan recursively the associated logical volume tree
319 //
320 tVolume = pVolume->GetLogicalVolume();
321 if (tVolume->GetNoDaughters())
322 {
323 DeleteOptimisations(tVolume->GetDaughter(0));
324 }
325}
326
327// ***************************************************************************
328// Sets the maximum extent of the world volume. The operation is allowed only
329// if NO solids have been created already.
330// ***************************************************************************
331//
333{
334 if (G4SolidStore::GetInstance()->size())
335 {
336 // Sanity check to assure that extent is fixed BEFORE creating
337 // any geometry object (solids in this case)
338 //
339 G4Exception("G4GeometryManager::SetMaximumExtent()",
340 "GeomMgt0003", FatalException,
341 "Extent can be set only BEFORE creating any geometry object!");
342 }
344}
345
346// ***************************************************************************
347// Reports statistics on voxel optimisation when closing geometry.
348// ***************************************************************************
349//
350void
351G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
352 G4double totalCpuTime )
353{
354 G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics"
355 << G4endl << G4endl;
356
357 //
358 // Get total memory use
359 //
360 G4int i, nStat = stats.size();
361 G4long totalMemory = 0;
362
363 for( i=0; i<nStat; ++i ) { totalMemory += stats[i].GetMemoryUse(); }
364
365 G4cout << " Total memory consumed for geometry optimisation: "
366 << totalMemory/1024 << " kByte" << G4endl;
367 G4cout << " Total CPU time elapsed for geometry optimisation: "
368 << std::setprecision(2) << totalCpuTime << " seconds"
369 << std::setprecision(6) << G4endl;
370
371 //
372 // First list: sort by total CPU time
373 //
374 std::sort( stats.begin(), stats.end(),
375 [](const G4SmartVoxelStat& a, const G4SmartVoxelStat& b)
376 {
377 return a.GetTotalTime() > b.GetTotalTime();
378 } );
379
380 G4int nPrint = nStat > 10 ? 10 : nStat;
381
382 if (nPrint)
383 {
384 G4cout << "\n Voxelisation: top CPU users:" << G4endl;
385 G4cout << " Percent Total CPU System CPU Memory Volume\n"
386 << " ------- ---------- ---------- -------- ----------"
387 << G4endl;
388 // 12345678901.234567890123.234567890123.234567890123k .
389 }
390
391 for(i=0; i<nPrint; ++i)
392 {
393 G4double total = stats[i].GetTotalTime();
394 G4double system = stats[i].GetSysTime();
395 G4double perc = 0.0;
396
397 if (system < 0) { system = 0.0; }
398 if ((total < 0) || (totalCpuTime < perMillion))
399 { total = 0; }
400 else
401 { perc = total*100/totalCpuTime; }
402
403 G4cout << std::setprecision(2)
404 << std::setiosflags(std::ios::fixed|std::ios::right)
405 << std::setw(11) << perc
406 << std::setw(13) << total
407 << std::setw(13) << system
408 << std::setw(13) << (stats[i].GetMemoryUse()+512)/1024
409 << "k " << std::setiosflags(std::ios::left)
410 << stats[i].GetVolume()->GetName()
411 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield)
412 << std::setprecision(6)
413 << G4endl;
414 }
415
416 //
417 // Second list: sort by memory use
418 //
419 std::sort( stats.begin(), stats.end(),
420 [](const G4SmartVoxelStat& a, const G4SmartVoxelStat& b)
421 {
422 return a.GetMemoryUse() > b.GetMemoryUse();
423 } );
424
425 if (nPrint)
426 {
427 G4cout << "\n Voxelisation: top memory users:" << G4endl;
428 G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n"
429 << " ------- -------- ------ ------ -------- ---------- ----------"
430 << G4endl;
431 // 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. .
432 }
433
434 for(i=0; i<nPrint; ++i)
435 {
436 G4long memory = stats[i].GetMemoryUse();
437 G4double totTime = stats[i].GetTotalTime();
438 if (totTime < 0) { totTime = 0.0; }
439
440 G4cout << std::setprecision(2)
441 << std::setiosflags(std::ios::fixed|std::ios::right)
442 << std::setw(11) << G4double(memory*100)/G4double(totalMemory)
443 << std::setw(11) << memory/1024 << "k "
444 << std::setw( 9) << stats[i].GetNumberHeads()
445 << std::setw( 9) << stats[i].GetNumberNodes()
446 << std::setw(11) << stats[i].GetNumberPointers()
447 << std::setw(13) << totTime << " "
448 << std::setiosflags(std::ios::left)
449 << stats[i].GetVolume()->GetName()
450 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield)
451 << std::setprecision(6)
452 << G4endl;
453 }
454}
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
static constexpr double perMillion
Definition: G4SIunits.hh:327
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 void ReportVoxelStats(std::vector< G4SmartVoxelStat > &stats, G4double totalCpuTime)
static G4bool IsGeometryClosed()
static G4ThreadLocal G4GeometryManager * fgInstance
static G4GeometryManager * GetInstance()
G4bool CloseGeometry(G4bool pOptimise=true, G4bool verbose=false, G4VPhysicalVolume *vol=nullptr)
void SetWorldMaximumExtent(G4double worldExtent)
void BuildOptimisations(G4bool allOpt, G4bool verbose=false)
static G4ThreadLocal G4bool fIsClosed
void OpenGeometry(G4VPhysicalVolume *vol=nullptr)
static G4GeometryManager * GetInstanceIfExist()
void SetSurfaceTolerance(G4double worldExtent)
static G4GeometryTolerance * GetInstance()
static G4LogicalVolumeStore * GetInstance()
void SetVoxelHeader(G4SmartVoxelHeader *pVoxel)
size_t GetNoDaughters() const
G4VPhysicalVolume * GetDaughter(const G4int i) const
G4bool IsToOptimise() const
const G4String & GetName() const
G4SmartVoxelHeader * GetVoxelHeader() const
static G4SolidStore * GetInstance()
void Stop()
G4double GetSystemElapsed() const
Definition: G4Timer.cc:132
G4double GetUserElapsed() const
Definition: G4Timer.cc:143
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)
#define G4ThreadLocal
Definition: tls.hh:77
const G4int kMinVoxelVolumesLevel1
Definition: voxeldefs.hh:39