Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/management/src/G4GeometryManager.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /geometry/management/src/G4GeometryManager.cc (Version 11.3.0) and /geometry/management/src/G4GeometryManager.cc (Version 1.0)


                                                   >>   1 // This code implementation is the intellectual property of
                                                   >>   2 // the GEANT4 collaboration.
  1 //                                                  3 //
  2 // ******************************************* <<   4 // By copying, distributing or modifying the Program (or any work
  3 // * License and Disclaimer                    <<   5 // based on the Program) you indicate your acceptance of this statement,
  4 // *                                           <<   6 // and all its terms.
  5 // * The  Geant4 software  is  copyright of th << 
  6 // * the Geant4 Collaboration.  It is provided << 
  7 // * conditions of the Geant4 Software License << 
  8 // * LICENSE and available at  http://cern.ch/ << 
  9 // * include a list of copyright holders.      << 
 10 // *                                           << 
 11 // * Neither the authors of this software syst << 
 12 // * institutes,nor the agencies providing fin << 
 13 // * work  make  any representation or  warran << 
 14 // * regarding  this  software system or assum << 
 15 // * use.  Please see the license in the file  << 
 16 // * for the full disclaimer and the limitatio << 
 17 // *                                           << 
 18 // * This  code  implementation is the result  << 
 19 // * technical work of the GEANT4 collaboratio << 
 20 // * By using,  copying,  modifying or  distri << 
 21 // * any work based  on the software)  you  ag << 
 22 // * use  in  resulting  scientific  publicati << 
 23 // * acceptance of all terms of the Geant4 Sof << 
 24 // ******************************************* << 
 25 //                                                  7 //
 26 // Class G4GeometryManager implementation      <<   8 // $Id: G4GeometryManager.cc,v 1.1.12.1 1999/12/07 20:48:13 gunter Exp $
                                                   >>   9 // GEANT4 tag $Name: geant4-01-00 $
 27 //                                                 10 //
 28 // 26.07.95, P.Kent - Initial version, includi <<  11 // class G4GeometryManager
 29 // 12.06.24, J.Apostolakis - Added parallel op << 
 30 // ------------------------------------------- << 
 31                                                << 
 32 #include <iomanip>                             << 
 33                                                << 
 34 #include "G4ios.hh"                            << 
 35 #include "G4Timer.hh"                          << 
 36 #include "G4GeometryManager.hh"                << 
 37 #include "G4SystemOfUnits.hh"                  << 
 38 #include "G4Threading.hh"                      << 
 39                                                << 
 40 // Needed for building optimisations           << 
 41 //                                                 12 //
 42 #include "G4LogicalVolumeStore.hh"             <<  13 // Implementation
 43 #include "G4VPhysicalVolume.hh"                << 
 44 #include "G4SmartVoxelHeader.hh"               << 
 45 #include "voxeldefs.hh"                        << 
 46                                                << 
 47 // Needed for setting the extent for tolerance << 
 48 //                                             << 
 49 #include "G4GeometryTolerance.hh"              << 
 50 #include "G4SolidStore.hh"                     << 
 51 #include "G4VSolid.hh"                         << 
 52                                                << 
 53 // Needed for parallel optimisation            << 
 54 #include "G4AutoLock.hh"                       << 
 55                                                << 
 56 namespace  // Data structures / mutexes for pa << 
 57 {                                              << 
 58   // Mutex to obtain a volume to optimise      << 
 59   G4Mutex obtainVolumeMutex = G4MUTEX_INITIALI << 
 60                                                << 
 61   // Mutex to lock saving of voxel statistics  << 
 62   G4Mutex voxelStatsMutex = G4MUTEX_INITIALIZE << 
 63                                                << 
 64   // Mutex to provide Statistics Results       << 
 65   G4Mutex statResultsMutex = G4MUTEX_INITIALIZ << 
 66                                                << 
 67   // Mutex to start wall clock (global) timer  << 
 68   G4Mutex wallClockTimerMutex = G4MUTEX_INITIA << 
 69                                                << 
 70   // Mutex to write debug output               << 
 71   G4Mutex outputDbgMutex = G4MUTEX_INITIALIZER << 
 72 }                                              << 
 73                                                << 
 74 // ******************************************* << 
 75 // Static class data                           << 
 76 // ******************************************* << 
 77 //                                                 14 //
 78 G4ThreadLocal G4GeometryManager* G4GeometryMan <<  15 // History:
                                                   >>  16 // 26.07.95 P.Kent Initial version, incuding optimisation Build
 79                                                    17 
 80 // Static *global* class data                  <<  18 #include "G4GeometryManager.hh"
 81 G4bool G4GeometryManager::fParallelVoxelOptimi << 
 82   // Records User choice to use parallel voxel << 
 83                                                << 
 84 G4bool  G4GeometryManager::fOptimiseInParallel << 
 85   // Configured = requested && available (ie i << 
 86   // Value calculated during each effort to op << 
 87                                                << 
 88 std::vector<G4LogicalVolume*> G4GeometryManage << 
 89 std::vector<G4LogicalVolume*>::const_iterator  << 
 90                                                << 
 91 std::vector<G4SmartVoxelStat> G4GeometryManage << 
 92 // Container for statistics                    << 
 93                                                << 
 94 // Derived state                               << 
 95 G4bool G4GeometryManager::fVerboseParallel = f << 
 96 G4bool G4GeometryManager::fParallelVoxelOptimi << 
 97 G4bool G4GeometryManager::fParallelVoxelOptimi << 
 98 G4double G4GeometryManager::fSumVoxelTime = 0. << 
 99                                                << 
100 G4int G4GeometryManager::fNumberThreadsReporti << 
101 unsigned int G4GeometryManager::fTotalNumberVo << 
102                                                << 
103 // For Wall clock                              << 
104 G4Timer* G4GeometryManager::fWallClockTimer =  << 
105 G4bool G4GeometryManager::fWallClockStarted =  << 
106                                                << 
107 // ******************************************* << 
108 // Destructor                                  << 
109 // ******************************************* << 
110 //                                             << 
111 G4GeometryManager::~G4GeometryManager()        << 
112 {                                              << 
113   fgInstance = nullptr;                        << 
114   fIsClosed = false;                           << 
115                                                << 
116   if( fWallClockTimer && G4Threading::IsMaster << 
117   {                                            << 
118     delete fWallClockTimer;                    << 
119     fWallClockTimer= nullptr;                  << 
120   }                                            << 
121 }                                              << 
122                                                    19 
123 // ******************************************* <<  20 // Close geometry - perform sanity checks and optionally Build optimisation
124 // Closes geometry - performs sanity checks an <<  21 // for placed volumes (always built for replicas & parameterised)
125 // for placed volumes (always built for replic <<  22 // NOTE: Currently no sanity checks
126 // NOTE: Currently no sanity checks are perfor <<  23 G4bool G4GeometryManager::CloseGeometry(G4bool pOptimise)
127 // Applies to just a specific subtree if a phy <<  24 {
128 // ******************************************* <<  25     if (!fIsClosed)
129 //                                             <<  26   {
130 G4bool G4GeometryManager::CloseGeometry(G4bool <<  27       BuildOptimisations(pOptimise);
131                                         G4VPhy <<  28       fIsClosed=true;
132 {                                              <<  29   }
133   if (!fIsClosed && G4Threading::IsMasterThrea <<  30     return true;
134   {                                            <<  31 }
135     if (pVolume != nullptr)                    <<  32 
136     {                                          <<  33 void G4GeometryManager::OpenGeometry()
137       BuildOptimisations(pOptimise, pVolume);  <<  34 {
138     }                                          <<  35      if (fIsClosed)
139     else                                       <<  36    {
140     {                                          <<  37       DeleteOptimisations();
141       BuildOptimisations(pOptimise, verbose);  <<  38       fIsClosed=false;
142     }                                          <<  39   }
143     fIsClosed = true;                          << 
144   }                                            << 
145   return true;                                 << 
146 }                                                  40 }
147                                                    41 
148 // ******************************************* <<  42 // Static class variable: ptr to single instance of class
149 // Opens the geometry and removes optimisation <<  43 G4GeometryManager* G4GeometryManager::fgInstance = 0;
150 // the specified logical-volume).              << 
151 // Applies to just a specific subtree if a phy << 
152 // ******************************************* << 
153 //                                             << 
154 void G4GeometryManager::OpenGeometry(G4VPhysic << 
155 {                                              << 
156   if (fIsClosed && G4Threading::IsMasterThread << 
157   {                                            << 
158     if (pVolume != nullptr)                    << 
159     {                                          << 
160       DeleteOptimisations(pVolume);            << 
161     }                                          << 
162     else                                       << 
163     {                                          << 
164       DeleteOptimisations();                   << 
165     }                                          << 
166     fIsClosed = false;                         << 
167   }                                            << 
168 }                                              << 
169                                                    44 
170 // ******************************************* << 
171 // Returns the instance of the singleton.      << 
172 // Creates it in case it's called for the firs << 
173 // ******************************************* << 
174 //                                             << 
175 G4GeometryManager* G4GeometryManager::GetInsta     45 G4GeometryManager* G4GeometryManager::GetInstance()
176 {                                                  46 {
177   if (fgInstance == nullptr)                   <<  47     static G4GeometryManager worldManager;
178   {                                            <<  48     if (!fgInstance)
179     fgInstance = new G4GeometryManager;        <<  49   {
180                                                <<  50       fgInstance = &worldManager;
181     if( (fWallClockTimer == nullptr) && G4Thre <<  51   }
182     {                                          <<  52     return fgInstance;    
183       fWallClockTimer = new G4Timer;           <<  53 }
184     }                                          <<  54 
185   }                                            <<  55 
186   return fgInstance;                           <<  56 // Constructor. Set the geometry to be open
187 }                                              <<  57 G4GeometryManager::G4GeometryManager() 
188                                                <<  58 {
189 // ******************************************* <<  59     fIsClosed=false;
190 // Returns the instance of the singleton.      <<  60 }
191 // ******************************************* <<  61 
192 //                                             <<  62 //
193 G4GeometryManager* G4GeometryManager::GetInsta <<  63 // Create optimisation info. Build all voxels if allOpts=true
194 {                                              <<  64 // else only for replicated volumes
195   return fgInstance;                           <<  65 //
196 }                                              <<  66 void G4GeometryManager::BuildOptimisations(const G4bool allOpts)
197                                                <<  67 {
198 // ******************************************* <<  68      G4LogicalVolumeStore *Store;
199 // Simplest user method to request parallel op <<  69      G4LogicalVolume *volume;
200 // ******************************************* <<  70      G4SmartVoxelHeader *head;
201 //                                             <<  71      G4int nVolumes,n;
202 void G4GeometryManager::OptimiseInParallel( G4 <<  72      Store=G4LogicalVolumeStore::GetInstance();
203 {                                              <<  73      nVolumes=Store->entries();
204   RequestParallelOptimisation(val);            <<  74      for (n=0;n<nVolumes;n++)
205 }                                              <<  75    {
206                                                <<  76        volume=Store->operator()(n);
207 // ******************************************* <<  77 // For safety, check if there are any existing voxels and delete before
208 // Report about Voxel(isation) of a logical vo <<  78 // replacement
209 // ******************************************* <<  79        head = volume->GetVoxelHeader();
210 //                                             <<  80        if (head) 
211 void                                           <<  81      {
212 G4GeometryManager::ReportVoxelInfo(G4LogicalVo <<  82          delete head;
213 {                                              <<  83          volume->SetVoxelHeader(0);
214   G4SmartVoxelHeader* head = logVolume->GetVox <<  84      }
215   if( head != nullptr )                        <<  85        if ((volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) ||
216   {                                            <<  86                   (volume->GetNoDaughters()==1&&
217     os << "** Created optimisations for logica <<  87                    volume->GetDaughter(0)->IsReplicated()==true))
218        << std::setw(50) << logVolume->GetName( <<  88      {
219        << "- Result VoxelInfo - START: " << "  <<  89 #ifdef G4GEOMETRY_VOXELDEBUG
220        << *head                                <<  90          G4cout << "**** G4GeometryManager::BuildOptimisations" << endl
221        << "- Result VoxelInfo -   END. " << G4 <<  91         << "     Examining logical volume name = " << volume->GetName() << endl;
222   }                                            <<  92 #endif
223   else                                         <<  93          head = new G4SmartVoxelHeader(volume);
224   {                                            <<  94          if (head)
225     os << "** No optimisation for log-vol " << <<  95        {
226   }                                            <<  96            volume->SetVoxelHeader(head);
227   os << "*** Report Voxel Info: END " <<  G4en <<  97        }
228 }                                              <<  98          else
229                                                <<  99        {
230 // ******************************************* << 100            G4Exception("G4GeometryManager::BuildOptimisations voxelheader new failed");
231 // Creates optimisation info. Builds all voxel << 101        }
232 // otherwise it builds voxels only for replica << 102      }
233 // ******************************************* << 103        else
234 // Returns whether optimisation is finished    << 104      {
235 //                                             << 105 // Don't create voxels for this node
236 G4bool G4GeometryManager::BuildOptimisations(G << 106 #ifdef G4GEOMETRY_VOXELDEBUG
237 {                                              << 107          G4cout << "**** G4GeometryManager::BuildOptimisations"
238   G4bool finishedOptimisation = false;         << 108         << endl
239                                                << 109         << "     Skipping logical volume name = "
240   fOptimiseInParallelConfigured = fParallelVox << 110         << volume->GetName() << endl;
241                                && G4Threading: << 111 #endif
242                                                << 112      }
243   static unsigned int NumCallsBuildOptimisatio << 
244   if( fOptimiseInParallelConfigured && (NumCal << 
245   {                                            << 
246     PrepareParallelOptimisation(allOpts, verbo << 
247     ++NumCallsBuildOptimisations;              << 
248   }                                            << 
249   else                                         << 
250   {                                            << 
251     BuildOptimisationsSequential(allOpts, verb << 
252     finishedOptimisation= true;                << 
253   }                                            << 
254                                                << 
255   return finishedOptimisation;                 << 
256 }                                              << 
257                                                << 
258 // ******************************************* << 
259 // Creates optimisation info. Builds all voxel << 
260 // otherwise it builds voxels only for replica << 
261 //                                             << 
262 // This is the original sequential implementat << 
263 // - at first initialisation to create voxels, << 
264 // - at re-initialisation if the geometry has  << 
265 // ******************************************* << 
266 //                                             << 
267 void G4GeometryManager::BuildOptimisationsSequ << 
268                                                << 
269 {                                              << 
270   G4Timer timer;                               << 
271   G4Timer allTimer;                            << 
272   std::vector<G4SmartVoxelStat> stats;         << 
273                                                << 
274   if (verbose)  { allTimer.Start(); }          << 
275                                                << 
276   G4LogicalVolumeStore* Store = G4LogicalVolum << 
277   G4LogicalVolume* volume;                     << 
278   G4SmartVoxelHeader* head;                    << 
279                                                << 
280 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
281   G4cout << G4endl                             << 
282      << "*** G4GeometryManager::BuildOptimisat << 
283      << G4Threading::G4GetThreadId() << " all- << 
284 #endif                                         << 
285                                                << 
286   for (auto & n : *Store)                      << 
287   {                                            << 
288     if (verbose) timer.Start();                << 
289     volume=n;                                  << 
290     // For safety, check if there are any exis << 
291     // delete before replacement               << 
292     //                                         << 
293     head = volume->GetVoxelHeader();           << 
294     delete head;                               << 
295     volume->SetVoxelHeader(nullptr);           << 
296     if (    ( (volume->IsToOptimise())         << 
297              && (volume->GetNoDaughters()>=kMi << 
298         || ( (volume->GetNoDaughters()==1)     << 
299             && (volume->GetDaughter(0)->IsRepl << 
300             && (volume->GetDaughter(0)->GetReg << 
301     {                                          << 
302 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
303     G4cout << "** G4GeometryManager::BuildOpti << 
304            << "   Examining logical volume nam << 
305            << "'  #daughters= " << volume->Get << 
306 #endif                                         << 
307       head = new G4SmartVoxelHeader(volume);   << 
308                                                << 
309       if (head != nullptr)                     << 
310       {                                        << 
311         volume->SetVoxelHeader(head);          << 
312       }                                        << 
313       else                                     << 
314       {                                        << 
315         std::ostringstream message;            << 
316         message << "VoxelHeader allocation err << 
317                 << "Allocation of new VoxelHea << 
318                 << "        for volume '" << v << 
319         G4Exception("G4GeometryManager::BuildO << 
320                     FatalException, message);  << 
321       }                                        << 
322       if (verbose)                             << 
323       {                                        << 
324         timer.Stop();                          << 
325         stats.emplace_back( volume, head,      << 
326                            timer.GetSystemElap << 
327                            timer.GetUserElapse << 
328       }                                        << 
329     }                                          << 
330     else                                       << 
331     {                                          << 
332       // Don't create voxels for this node     << 
333 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
334       auto numDaughters = volume->GetNoDaughte << 
335       G4cout << "- Skipping logical volume wit << 
336              << " daughters and name = '" << v << 
337       if( numDaughters > 1 )                   << 
338       {                                        << 
339         G4cout << "[Placement]";               << 
340       }                                        << 
341       else                                     << 
342       {                                        << 
343         if( numDaughters == 1 )                << 
344         {                                      << 
345           G4cout << ( volume->GetDaughter(0)-> << 
346                                                << 
347         }                                      << 
348       }                                        << 
349       G4cout << G4endl;                        << 
350 #endif                                         << 
351     }                                          << 
352   }                                            << 
353   if (verbose)                                 << 
354   {                                            << 
355     allTimer.Stop();                           << 
356                                                << 
357     ReportVoxelStats( stats, allTimer.GetSyste << 
358                      + allTimer.GetUserElapsed << 
359   }                                            << 
360 }                                              << 
361                                                << 
362 // ******************************************* << 
363 // Creates a list of logical volumes which wil << 
364 //    if allOpts=true it lists all voxels      << 
365 //    otherwise       it lists only the voxels << 
366 // This list will be used subsequently to buil << 
367 //                                             << 
368 // Note: this method is NOT thread safe!       << 
369 //    It expects to be called only once in eac << 
370 //    i.e. either by master thread or a select << 
371 // ******************************************* << 
372 //                                             << 
373 void                                           << 
374 G4GeometryManager::CreateListOfVolumesToOptimi << 
375 {                                              << 
376   // Prepare the work - must be called only in << 
377                                                << 
378   G4LogicalVolumeStore* Store = G4LogicalVolum << 
379                                                << 
380   if( !fVolumesToOptimise.empty() )            << 
381   {                                            << 
382     ResetListOfVolumesToOptimise();            << 
383   }                                            << 
384                                                << 
385   for (auto & n : *Store)                      << 
386   {                                            << 
387     G4LogicalVolume* volume=n;                 << 
388                                                << 
389     if (    ( (volume->IsToOptimise())         << 
390              && (volume->GetNoDaughters()>=kMi << 
391         || ( (volume->GetNoDaughters()==1)     << 
392             && (volume->GetDaughter(0)->IsRepl << 
393             && (volume->GetDaughter(0)->GetReg << 
394     {                                          << 
395       fVolumesToOptimise.push_back(volume);    << 
396                                                << 
397       // For safety, must check (later) if the << 
398       //     delete before replacement:        << 
399       // All 'clients' of this code must do th << 
400       //   delete volume->GetVoxelHeader();    << 
401       //   volume->SetVoxelHeader(nullptr);    << 
402                                                << 
403 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
404       G4cout << "- Booking  logical volume wit << 
405       << " daughters and name = '" << volume-> << 
406       << " -- for optimisation (ie voxels will << 
407 #endif                                         << 
408     }                                          << 
409     else                                       << 
410     {                                          << 
411 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
412       G4cout << "- Skipping logical volume wit << 
413       << " daughters and name = '" << volume-> << 
414 #endif                                         << 
415     }                                          << 
416   }                                            << 
417                                                << 
418   if(verbose)                                  << 
419     G4cout << "** G4GeometryManager::PrepareOp << 
420            << "  Number of volumes for voxelis << 
421            << fVolumesToOptimise.size() << G4e << 
422                                                << 
423   fLogVolumeIterator = fVolumesToOptimise.cbeg << 
424 }                                              << 
425                                                << 
426 // ******************************************* << 
427 // Obtain a logical volume from the list of vo << 
428 // Must be thread-safe: its role is to be call << 
429 // Critical method for parallel optimisation - << 
430 // ******************************************* << 
431 //                                             << 
432 G4LogicalVolume* G4GeometryManager::ObtainVolu << 
433 {                                              << 
434   G4LogicalVolume* logVolume = nullptr;        << 
435                                                << 
436   G4AutoLock lock(obtainVolumeMutex);          << 
437                                                << 
438   if( fLogVolumeIterator != fVolumesToOptimise << 
439   {                                            << 
440     logVolume = *fLogVolumeIterator;           << 
441     ++fLogVolumeIterator;                      << 
442   }                                            << 
443   return logVolume;                            << 
444 }                                              << 
445                                                << 
446 // ******************************************* << 
447 // Thread-safe method to clear the list of vol << 
448 // ******************************************* << 
449 //                                             << 
450 void G4GeometryManager::ResetListOfVolumesToOp << 
451 {                                              << 
452   G4AutoLock lock(obtainVolumeMutex);          << 
453                                                << 
454   std::vector<G4LogicalVolume*>().swap(fVolume << 
455   // Swapping with an empty vector in order to << 
456   // without calling destructors of logical vo << 
457   // Must not call clear: i.e. fVolumesToOptim << 
458                                                << 
459   assert(fVolumesToOptimise.empty());          << 
460   fLogVolumeIterator = fVolumesToOptimise.cbeg << 
461                                                << 
462   fGlobVoxelStats.clear();                     << 
463   // Reset also the statistics of volumes -- t << 
464 }                                              << 
465                                                << 
466 // ******************************************* << 
467 // Method which user calls to ask for parallel << 
468 // ******************************************* << 
469 //                                             << 
470 void G4GeometryManager::RequestParallelOptimis << 
471 {                                              << 
472   fParallelVoxelOptimisationRequested = flag;  << 
473   if( flag )                                   << 
474   {                                            << 
475     ConfigureParallelOptimisation(verbose);    << 
476   }                                            << 
477 }                                              << 
478                                                   113 
479 // ******************************************* << 114    }
480 // Setup up state to enable parallel optimisat << 
481 // ******************************************* << 
482 //                                             << 
483 void G4GeometryManager::ConfigureParallelOptim << 
484 {                                              << 
485   if(verbose)                                  << 
486   {                                            << 
487     G4cout << "** G4GeometryManager::Configure << 
488     << " LEAVING all the work (of voxel optimi << 
489     << G4endl;                                 << 
490   }                                            << 
491   fParallelVoxelOptimisationRequested = true;  << 
492   fParallelVoxelOptimisationUnderway = false;  << 
493   fParallelVoxelOptimisationFinished = false;  << 
494                                                << 
495   // Keep values of options / verbosity for us << 
496   fVerboseParallel = verbose;                  << 
497                                                << 
498   // New effort -- reset the total time -- and << 
499   fSumVoxelTime = 0.0;                         << 
500   fNumberThreadsReporting = 0;                 << 
501   fTotalNumberVolumesOptimised = 0;   // Numbe << 
502                                                << 
503   fWallClockStarted = false;  // Will need to  << 
504 }                                              << 
505                                                << 
506 // ******************************************* << 
507 // Build voxel optimisation in parallel -- pre << 
508 // ******************************************* << 
509 //                                             << 
510 void                                           << 
511 G4GeometryManager::PrepareParallelOptimisation << 
512 {                                              << 
513   if( verbose )                                << 
514   {                                            << 
515     G4cout << "** G4GeometryManager::PreparePa << 
516            << G4endl;                          << 
517   }                                            << 
518   CreateListOfVolumesToOptimise(allOpts, verbo << 
519   ConfigureParallelOptimisation(verbose);      << 
520 }                                              << 
521                                                << 
522 // ******************************************* << 
523 // Method for a thread/task to contribute dyna << 
524 // ******************************************* << 
525 //                                             << 
526 void G4GeometryManager::UndertakeOptimisation( << 
527 {                                              << 
528   G4bool verbose = fVerboseParallel;           << 
529   G4LogicalVolume* logVolume = nullptr;        << 
530                                                << 
531   fParallelVoxelOptimisationUnderway  = true;  << 
532                                                << 
533   // Start timer - if not already done         << 
534   if( ( !fWallClockStarted ) && verbose )      << 
535   {                                            << 
536     G4AutoLock startTimeLock(wallClockTimerMut << 
537     if( !fWallClockStarted )                   << 
538     {                                          << 
539       fWallClockTimer->Start();                << 
540       fWallClockStarted= true;                 << 
541     }                                          << 
542   }                                            << 
543                                                << 
544   G4Timer fetimer;                             << 
545   unsigned int numVolumesOptimised = 0;        << 
546                                                << 
547   while( (logVolume = ObtainVolumeToOptimise() << 
548   {                                            << 
549     if (verbose) fetimer.Start();              << 
550                                                << 
551     G4SmartVoxelHeader* head = logVolume->GetV << 
552     delete head;                               << 
553     logVolume->SetVoxelHeader(nullptr);        << 
554                                                << 
555     head = new G4SmartVoxelHeader(logVolume);  << 
556     //     *********************************   << 
557     logVolume->SetVoxelHeader(head);           << 
558                                                << 
559     if (head != nullptr)                       << 
560     {                                          << 
561       ++numVolumesOptimised;                   << 
562     }                                          << 
563     else                                       << 
564     {                                          << 
565       G4ExceptionDescription message;          << 
566       message << "VoxelHeader allocation error << 
567               << "Allocation of new VoxelHeade << 
568               << "for logical volume " << logV << 
569       G4Exception("G4GeometryManager::BuildOpt << 
570                   "GeomMgt0003", FatalExceptio << 
571     }                                          << 
572                                                << 
573     if(verbose)                                << 
574     {                                          << 
575       fetimer.Stop();                          << 
576       auto feRealElapsed = fetimer.GetRealElap << 
577       // Must use 'real' elapsed time -- canno << 
578       // (it accounts for all threads)         << 
579                                                << 
580       G4AutoLock lock(voxelStatsMutex);        << 
581       fGlobVoxelStats.emplace_back( logVolume, << 
582                           0.0,             //  << 
583                           feRealElapsed ); //  << 
584       fSumVoxelTime += feRealElapsed;          << 
585     }                                          << 
586   }                                            << 
587                                                << 
588   G4bool allDone = false;                      << 
589   G4int myCount= -1;                           << 
590                                                << 
591   myCount = ReportWorkerIsDoneOptimising(numVo << 
592   allDone = IsParallelOptimisationFinished();  << 
593                                                << 
594   if( allDone && (myCount == G4Threading::GetN << 
595   {                                            << 
596     G4int badVolumes = CheckOptimisation(); // << 
597     if( badVolumes > 0 )                       << 
598     {                                          << 
599       G4ExceptionDescription errmsg;           << 
600       errmsg <<" Expected that all voxelisatio << 
601              << "but found that voxels headers << 
602              << badVolumes << " volumes.";     << 
603       G4Exception("G4GeometryManager::Undertak << 
604                   "GeomMng002", FatalException << 
605     }                                          << 
606                                                << 
607     // Create report                           << 
608                                                << 
609     if( verbose )                              << 
610     {                                          << 
611       fWallClockTimer->Stop();                 << 
612                                                << 
613       std::ostream& report_stream = std::cout; << 
614       report_stream << G4endl                  << 
615         << "G4GeometryManager::UndertakeOptimi << 
616         << " -- Timing for Voxel Optimisation" << 
617       report_stream << "  - Elapsed time (real << 
618         << fWallClockTimer->GetRealElapsed() < << 
619         << ", user " << fWallClockTimer->GetUs << 
620         << ", system " << fWallClockTimer->Get << 
621         << G4endl;                             << 
622       report_stream << "  - Sum voxel time (re << 
623                     << "s.";                   << 
624       report_stream << std::setprecision(6) << << 
625                                                << 
626       ReportVoxelStats( fGlobVoxelStats, fSumV << 
627       report_stream.flush();                   << 
628     }                                          << 
629   }                                            << 
630   else                                         << 
631   {                                            << 
632     WaitForVoxelisationFinish(false);          << 
633   }                                            << 
634 }                                              << 
635                                                << 
636 // ******************************************* << 
637 // Ensure that all the work of voxelisation is << 
638 // Can be called in GeometryManager methods or << 
639 // ******************************************* << 
640 //                                             << 
641 void G4GeometryManager::WaitForVoxelisationFin << 
642 {                                              << 
643   // Must wait until all workers are done ...  << 
644   using namespace std::chrono_literals;        << 
645   unsigned int trials = 0;                     << 
646   auto tid = G4Threading::G4GetThreadId();     << 
647                                                << 
648   std::ostream& out_stream = std::cout; // G4c << 
649   while( ! IsParallelOptimisationFinished() )  << 
650   {                                            << 
651     // Each thread must wait until all are don << 
652     std::this_thread::sleep_for(250ms);        << 
653     ++trials;                                  << 
654   }                                            << 
655                                                << 
656   if( verbose )                                << 
657   {                                            << 
658     G4AutoLock lock(outputDbgMutex);           << 
659     out_stream << G4endl                       << 
660                << "** UndertakeOptimisation do << 
661                <<  " after waiting for " << tr << 
662     out_stream.flush();                        << 
663   }                                            << 
664 }                                                 115 }
665                                                   116 
666 // ******************************************* << 117 // Remove all optimisation info
667 // Ensure that all logical volumes in list hav << 
668 // ******************************************* << 
669 //                                                118 //
670 G4int G4GeometryManager::CheckOptimisation()   << 119 // Process:
671 {                                              << 
672   unsigned int numErrors = 0;                  << 
673   for ( const auto& logical : fVolumesToOptimi << 
674   {                                            << 
675     if( logical->GetVoxelHeader() == nullptr ) << 
676   }                                            << 
677   return numErrors;                            << 
678 }                                              << 
679                                                << 
680 // ******************************************* << 
681 // Report that current thread/task is done opt << 
682 // A thread call this method to reports that i << 
683 // many volumes it optimised. The method:      << 
684 //   - increments the count of workers that ha << 
685 //   - keeps count of number of volumes optimi << 
686 //   - if all works is done (ie all workers ha << 
687 //     in the 'Finished' state.                << 
688 // ******************************************* << 
689 //                                                120 //
690 G4int                                          << 121 // Loop over all logical volumes, deleting non-null voxels ptrs
691 G4GeometryManager::ReportWorkerIsDoneOptimisin << 
692 {                                              << 
693   // Check that all are done and, if so, signa << 
694   G4int orderReporting;                        << 
695                                                << 
696   G4AutoLock lock(statResultsMutex);           << 
697   orderReporting = ++fNumberThreadsReporting;  << 
698   fTotalNumberVolumesOptimised += numVolumesOp << 
699                                                << 
700   if (fNumberThreadsReporting == G4Threading:: << 
701   {                                            << 
702     InformOptimisationIsFinished(fVerboseParal << 
703   }                                            << 
704                                                << 
705   return orderReporting;                       << 
706 }                                              << 
707                                                   122 
708 // ******************************************* << 123 void G4GeometryManager::DeleteOptimisations()
709 // Inform that all work for parallel optimisat << 
710 // ******************************************* << 
711 //                                             << 
712 void G4GeometryManager::InformOptimisationIsFi << 
713 {                                                 124 {
714   if(verbose)   // G4cout does not work!       << 125      G4LogicalVolumeStore *Store=G4LogicalVolumeStore::GetInstance();
715   {                                            << 126      G4LogicalVolume *volume;
716     std::cout << "** G4GeometryManager: All vo << 127      G4SmartVoxelHeader *head;
717               << G4endl;                       << 128      G4int nVolumes,n;
718     std::cout << "   Total number of volumes o << 129      nVolumes=Store->entries();
719               << fTotalNumberVolumesOptimised  << 130      for (n=0;n<nVolumes;n++)
720               << " of " << fVolumesToOptimise. << 131    {
721     std::cout << "   Number of workers reporti << 132        volume=Store->operator()(n);
722               << fNumberThreadsReporting       << 133        head=volume->GetVoxelHeader();
723               << " of " << G4Threading::GetNum << 134        if (head)
724               << " expected\n";                << 135      {
725   }                                            << 136          delete head;
726   assert ( fTotalNumberVolumesOptimised == fVo << 137          volume->SetVoxelHeader(0);
727                                                << 138      }
728   fParallelVoxelOptimisationFinished  = true;  << 139    }
729   // fParallelVoxelOptimisationRequested = fal << 
730   fParallelVoxelOptimisationUnderway  = false; << 
731 }                                                 140 }
732                                                   141 
733 // ******************************************* << 
734 // Creates Optimisation info for the specified << 
735 // ******************************************* << 
736 //                                             << 
737 void G4GeometryManager::BuildOptimisations(G4b << 
738                                            G4V << 
739 {                                              << 
740   if (pVolume == nullptr) { return; }          << 
741                                                   142 
742   // Retrieve the mother logical volume, if no << 
743   // otherwise apply global optimisation for t << 
744   //                                           << 
745   G4LogicalVolume* tVolume = pVolume->GetMothe << 
746   if (tVolume == nullptr)                      << 
747   {                                            << 
748     BuildOptimisations(allOpts, false);        << 
749     return;                                    << 
750   }                                            << 
751                                                << 
752   G4SmartVoxelHeader* head = tVolume->GetVoxel << 
753   delete head;                                 << 
754   tVolume->SetVoxelHeader(nullptr);            << 
755   if (    ( (tVolume->IsToOptimise())          << 
756          && (tVolume->GetNoDaughters()>=kMinVo << 
757        || ( (tVolume->GetNoDaughters()==1)     << 
758          && (tVolume->GetDaughter(0)->IsReplic << 
759   {                                            << 
760     head = new G4SmartVoxelHeader(tVolume);    << 
761     if (head != nullptr)                       << 
762     {                                          << 
763       tVolume->SetVoxelHeader(head);           << 
764     }                                          << 
765     else                                       << 
766     {                                          << 
767       std::ostringstream message;              << 
768       message << "VoxelHeader allocation error << 
769               << "Allocation of new VoxelHeade << 
770               << "        for volume " << tVol << 
771       G4Exception("G4GeometryManager::BuildOpt << 
772                   FatalException, message);    << 
773     }                                          << 
774   }                                            << 
775   else                                         << 
776   {                                            << 
777     // Don't create voxels for this node       << 
778 #ifdef G4GEOMETRY_VOXELDEBUG                   << 
779     G4cout << "** G4GeometryManager::BuildOpti << 
780            << "     Skipping logical volume na << 
781            << G4endl;                          << 
782 #endif                                         << 
783   }                                            << 
784                                                   143 
785   // Scan recursively the associated logical v << 
786   //                                           << 
787   tVolume = pVolume->GetLogicalVolume();       << 
788   if (tVolume->GetNoDaughters() != 0)          << 
789   {                                            << 
790     BuildOptimisations(allOpts, tVolume->GetDa << 
791   }                                            << 
792 }                                              << 
793                                                   144 
794 // ******************************************* << 
795 // Removes all optimisation info.              << 
796 // Loops over all logical volumes, deleting no << 
797 // ******************************************* << 
798 //                                             << 
799 void G4GeometryManager::DeleteOptimisations()  << 
800 {                                              << 
801   G4LogicalVolume* tVolume = nullptr;          << 
802   G4LogicalVolumeStore* Store = G4LogicalVolum << 
803   for (auto & n : *Store)                      << 
804   {                                            << 
805     tVolume=n;                                 << 
806     delete tVolume->GetVoxelHeader();          << 
807     tVolume->SetVoxelHeader(nullptr);          << 
808   }                                            << 
809 }                                              << 
810                                                   145 
811 // ******************************************* << 
812 // Removes optimisation info for the specified << 
813 // Scans recursively all daughter volumes, del << 
814 // ******************************************* << 
815 //                                             << 
816 void G4GeometryManager::DeleteOptimisations(G4 << 
817 {                                              << 
818   if (pVolume == nullptr) { return; }          << 
819                                                   146 
820   // Retrieve the mother logical volume, if no << 
821   // otherwise global deletion to world volume << 
822   //                                           << 
823   G4LogicalVolume* tVolume = pVolume->GetMothe << 
824   if (tVolume == nullptr) { return DeleteOptim << 
825   delete tVolume->GetVoxelHeader();            << 
826   tVolume->SetVoxelHeader(nullptr);            << 
827                                                << 
828   // Scan recursively the associated logical v << 
829   //                                           << 
830   tVolume = pVolume->GetLogicalVolume();       << 
831   if (tVolume->GetNoDaughters() != 0)          << 
832   {                                            << 
833     DeleteOptimisations(tVolume->GetDaughter(0 << 
834   }                                            << 
835 }                                              << 
836                                                   147 
837 // ******************************************* << 
838 // Sets the maximum extent of the world volume << 
839 // if NO solids have been created already.     << 
840 // ******************************************* << 
841 //                                             << 
842 void G4GeometryManager::SetWorldMaximumExtent( << 
843 {                                              << 
844   if (!G4SolidStore::GetInstance()->empty())   << 
845   {                                            << 
846      // Sanity check to assure that extent is  << 
847      // any geometry object (solids in this ca << 
848      //                                        << 
849      G4Exception("G4GeometryManager::SetMaximu << 
850                  "GeomMgt0003", FatalException << 
851                  "Extent can be set only BEFOR << 
852   }                                            << 
853   G4GeometryTolerance::GetInstance()->SetSurfa << 
854 }                                              << 
855                                                   148 
856 // ******************************************* << 
857 // Reports statistics on voxel optimisation wh << 
858 // ******************************************* << 
859 //                                             << 
860 void                                           << 
861 G4GeometryManager::ReportVoxelStats( std::vect << 
862                                      G4double  << 
863                                      std::ostr << 
864 {                                              << 
865   os << "------------------------------------- << 
866      << G4endl;                                << 
867   os << "G4GeometryManager::ReportVoxelStats - << 
868          << G4endl << G4endl;                  << 
869                                                << 
870   //                                           << 
871   // Get total memory use                      << 
872   //                                           << 
873   G4int i, nStat = (G4int)stats.size();        << 
874   G4long totalMemory = 0;                      << 
875                                                << 
876   for( i=0; i<nStat; ++i )  { totalMemory += s << 
877                                                << 
878   os << "    Total memory consumed for geometr << 
879          << totalMemory/1024 << " kByte" << G4 << 
880   os << "    Total CPU time elapsed for geomet << 
881          << std::setprecision(4) << totalCpuTi << 
882          << std::setprecision(6) << G4endl;    << 
883                                                << 
884   //                                           << 
885   // First list: sort by total CPU time        << 
886   //                                           << 
887   std::sort( stats.begin(), stats.end(),       << 
888     [](const G4SmartVoxelStat& a, const G4Smar << 
889   {                                            << 
890     return a.GetTotalTime() > b.GetTotalTime() << 
891   } );                                         << 
892                                                << 
893   const G4int maxPrint = 20;                   << 
894   G4int nPrint = std::min ( nStat, maxPrint ); << 
895                                                << 
896   if (nPrint != 0)                             << 
897   {                                            << 
898     os << "\n    Voxelisation: top CPU users:" << 
899     os << "    Percent   Total CPU    System C << 
900        << "    -------   ----------   -------- << 
901        << G4endl;                              << 
902   }                                            << 
903                                                << 
904   for(i=0; i<nPrint; ++i)                      << 
905   {                                            << 
906     G4double total = stats[i].GetTotalTime();  << 
907     G4double system = stats[i].GetSysTime();   << 
908     G4double perc = 0.0;                       << 
909                                                << 
910     if (system < 0) { system = 0.0; }          << 
911     if ((total < 0) || (totalCpuTime < perMill << 
912       { total = 0; }                           << 
913     else                                       << 
914       { perc = total*100/totalCpuTime; }       << 
915                                                << 
916     os << std::setprecision(2)                 << 
917            << std::setiosflags(std::ios::fixed << 
918            << std::setw(11) << perc            << 
919            << std::setw(13) << total           << 
920            << std::setw(13) << system          << 
921            << std::setw(13) << (stats[i].GetMe << 
922            << "k " << std::setiosflags(std::io << 
923            << stats[i].GetVolume()->GetName()  << 
924            << std::resetiosflags(std::ios::flo << 
925            << std::setprecision(6)             << 
926            << G4endl;                          << 
927   }                                            << 
928                                                << 
929   //                                           << 
930   // Second list: sort by memory use           << 
931   //                                           << 
932   std::sort( stats.begin(), stats.end(),       << 
933     [](const G4SmartVoxelStat& a, const G4Smar << 
934   {                                            << 
935     return a.GetMemoryUse() > b.GetMemoryUse() << 
936   } );                                         << 
937                                                << 
938   if (nPrint != 0)                             << 
939   {                                            << 
940     os << "\n    Voxelisation: top memory user << 
941     os << "    Percent     Memory      Heads   << 
942        << "    -------   --------     ------   << 
943        << G4endl;                              << 
944   }                                            << 
945                                                << 
946   for(i=0; i<nPrint; ++i)                      << 
947   {                                            << 
948     G4long memory = stats[i].GetMemoryUse();   << 
949     G4double totTime = stats[i].GetTotalTime() << 
950     if (totTime < 0) { totTime = 0.0; }        << 
951                                                << 
952     os << std::setprecision(2)                 << 
953        << std::setiosflags(std::ios::fixed|std << 
954        << std::setw(11) << G4double(memory*100 << 
955        << std::setw(11) << memory/1024 << "k " << 
956        << std::setw( 9) << stats[i].GetNumberH << 
957        << std::setw( 9) << stats[i].GetNumberN << 
958        << std::setw(11) << stats[i].GetNumberP << 
959        << std::setw(13) << totTime << "    "   << 
960        << std::setiosflags(std::ios::left)     << 
961        << stats[i].GetVolume()->GetName()      << 
962        << std::resetiosflags(std::ios::floatfi << 
963        << std::setprecision(6)                 << 
964        << G4endl;                              << 
965   }                                            << 
966   os << "------------------------------------- << 
967      << G4endl << G4endl;                      << 
968 }                                              << 
969                                                   149 
970 // ******************************************* << 
971 // Check whether parallel optimisation was req << 
972 // ******************************************* << 
973 //                                             << 
974 G4bool G4GeometryManager::IsParallelOptimisati << 
975 {                                              << 
976   return fOptimiseInParallelConfigured;        << 
977 }                                              << 
978                                                   150 
979 // ******************************************* << 
980 // Report whether parallel optimisation is don << 
981 // ******************************************* << 
982 //                                             << 
983 G4bool G4GeometryManager::IsParallelOptimisati << 
984 {                                              << 
985   return fParallelVoxelOptimisationFinished;   << 
986 }                                              << 
987                                                   151