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