Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // Class G4GeometryManager implementation << 27 // 26 // 28 // 26.07.95, P.Kent - Initial version, includi << 27 // $Id: G4GeometryManager.cc,v 1.18 2006/06/29 18:33:23 gunter Exp $ 29 // 12.06.24, J.Apostolakis - Added parallel op << 28 // GEANT4 tag $Name: geant4-08-03-patch-01 $ >> 29 // >> 30 // class G4GeometryManager >> 31 // >> 32 // Implementation >> 33 // >> 34 // Author: >> 35 // 26.07.95 P.Kent Initial version, including optimisation Build 30 // ------------------------------------------- 36 // -------------------------------------------------------------------- 31 37 32 #include <iomanip> 38 #include <iomanip> 33 << 34 #include "G4ios.hh" << 35 #include "G4Timer.hh" 39 #include "G4Timer.hh" 36 #include "G4GeometryManager.hh" 40 #include "G4GeometryManager.hh" 37 #include "G4SystemOfUnits.hh" << 41 38 #include "G4Threading.hh" << 42 #ifdef G4GEOMETRY_VOXELDEBUG >> 43 #include "G4ios.hh" >> 44 #endif 39 45 40 // Needed for building optimisations 46 // Needed for building optimisations 41 // 47 // 42 #include "G4LogicalVolumeStore.hh" 48 #include "G4LogicalVolumeStore.hh" 43 #include "G4VPhysicalVolume.hh" 49 #include "G4VPhysicalVolume.hh" 44 #include "G4SmartVoxelHeader.hh" 50 #include "G4SmartVoxelHeader.hh" 45 #include "voxeldefs.hh" 51 #include "voxeldefs.hh" 46 52 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 // ******************************************* 53 // *************************************************************************** 75 // Static class data << 54 // Static class variable: ptr to single instance of class 76 // ******************************************* 55 // *************************************************************************** 77 // 56 // 78 G4ThreadLocal G4GeometryManager* G4GeometryMan << 57 G4GeometryManager* G4GeometryManager::fgInstance = 0; 79 << 80 // Static *global* class data << 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 58 107 // ******************************************* 59 // *************************************************************************** 108 // Destructor << 60 // Constructor. Set the geometry to be open 109 // ******************************************* 61 // *************************************************************************** 110 // 62 // 111 G4GeometryManager::~G4GeometryManager() << 63 G4GeometryManager::G4GeometryManager() 112 { 64 { 113 fgInstance = nullptr; << 65 fIsClosed=false; 114 fIsClosed = false; << 115 << 116 if( fWallClockTimer && G4Threading::IsMaster << 117 { << 118 delete fWallClockTimer; << 119 fWallClockTimer= nullptr; << 120 } << 121 } 66 } 122 67 123 // ******************************************* 68 // *************************************************************************** 124 // Closes geometry - performs sanity checks an 69 // Closes geometry - performs sanity checks and optionally builds optimisation 125 // for placed volumes (always built for replic 70 // for placed volumes (always built for replicas & parameterised). 126 // NOTE: Currently no sanity checks are perfor 71 // NOTE: Currently no sanity checks are performed. 127 // Applies to just a specific subtree if a phy 72 // Applies to just a specific subtree if a physical volume is specified. 128 // ******************************************* 73 // *************************************************************************** 129 // 74 // 130 G4bool G4GeometryManager::CloseGeometry(G4bool 75 G4bool G4GeometryManager::CloseGeometry(G4bool pOptimise, G4bool verbose, 131 G4VPhy 76 G4VPhysicalVolume* pVolume) 132 { 77 { 133 if (!fIsClosed && G4Threading::IsMasterThrea << 78 if (!fIsClosed) 134 { 79 { 135 if (pVolume != nullptr) << 80 if (pVolume) 136 { 81 { 137 BuildOptimisations(pOptimise, pVolume); 82 BuildOptimisations(pOptimise, pVolume); 138 } 83 } 139 else 84 else 140 { 85 { 141 BuildOptimisations(pOptimise, verbose); 86 BuildOptimisations(pOptimise, verbose); 142 } 87 } 143 fIsClosed = true; << 88 fIsClosed=true; 144 } 89 } 145 return true; 90 return true; 146 } 91 } 147 92 148 // ******************************************* 93 // *************************************************************************** 149 // Opens the geometry and removes optimisation 94 // Opens the geometry and removes optimisations (optionally, related to just 150 // the specified logical-volume). 95 // the specified logical-volume). 151 // Applies to just a specific subtree if a phy 96 // Applies to just a specific subtree if a physical volume is specified. 152 // ******************************************* 97 // *************************************************************************** 153 // 98 // 154 void G4GeometryManager::OpenGeometry(G4VPhysic 99 void G4GeometryManager::OpenGeometry(G4VPhysicalVolume* pVolume) 155 { 100 { 156 if (fIsClosed && G4Threading::IsMasterThread << 101 if (fIsClosed) 157 { 102 { 158 if (pVolume != nullptr) << 103 if (pVolume) 159 { 104 { 160 DeleteOptimisations(pVolume); 105 DeleteOptimisations(pVolume); 161 } 106 } 162 else 107 else 163 { 108 { 164 DeleteOptimisations(); 109 DeleteOptimisations(); 165 } 110 } 166 fIsClosed = false; << 111 fIsClosed=false; 167 } 112 } 168 } 113 } 169 114 170 // ******************************************* 115 // *************************************************************************** 171 // Returns the instance of the singleton. << 116 // Returns status of geometry 172 // Creates it in case it's called for the firs << 173 // ******************************************* 117 // *************************************************************************** 174 // 118 // 175 G4GeometryManager* G4GeometryManager::GetInsta << 119 G4bool G4GeometryManager::IsGeometryClosed() 176 { 120 { 177 if (fgInstance == nullptr) << 121 return fIsClosed; 178 { << 179 fgInstance = new G4GeometryManager; << 180 << 181 if( (fWallClockTimer == nullptr) && G4Thre << 182 { << 183 fWallClockTimer = new G4Timer; << 184 } << 185 } << 186 return fgInstance; << 187 } 122 } 188 123 189 // ******************************************* 124 // *************************************************************************** 190 // Returns the instance of the singleton. 125 // Returns the instance of the singleton. >> 126 // Creates it in case it's called for the first time. 191 // ******************************************* 127 // *************************************************************************** 192 // 128 // 193 G4GeometryManager* G4GeometryManager::GetInsta << 129 G4GeometryManager* G4GeometryManager::GetInstance() 194 { << 195 return fgInstance; << 196 } << 197 << 198 // ******************************************* << 199 // Simplest user method to request parallel op << 200 // ******************************************* << 201 // << 202 void G4GeometryManager::OptimiseInParallel( G4 << 203 { << 204 RequestParallelOptimisation(val); << 205 } << 206 << 207 // ******************************************* << 208 // Report about Voxel(isation) of a logical vo << 209 // ******************************************* << 210 // << 211 void << 212 G4GeometryManager::ReportVoxelInfo(G4LogicalVo << 213 { << 214 G4SmartVoxelHeader* head = logVolume->GetVox << 215 if( head != nullptr ) << 216 { << 217 os << "** Created optimisations for logica << 218 << std::setw(50) << logVolume->GetName( << 219 << "- Result VoxelInfo - START: " << " << 220 << *head << 221 << "- Result VoxelInfo - END. " << G4 << 222 } << 223 else << 224 { << 225 os << "** No optimisation for log-vol " << << 226 } << 227 os << "*** Report Voxel Info: END " << G4en << 228 } << 229 << 230 // ******************************************* << 231 // Creates optimisation info. Builds all voxel << 232 // otherwise it builds voxels only for replica << 233 // ******************************************* << 234 // Returns whether optimisation is finished << 235 // << 236 G4bool G4GeometryManager::BuildOptimisations(G << 237 { 130 { 238 G4bool finishedOptimisation = false; << 131 static G4GeometryManager worldManager; 239 << 132 if (!fgInstance) 240 fOptimiseInParallelConfigured = fParallelVox << 241 && G4Threading: << 242 << 243 static unsigned int NumCallsBuildOptimisatio << 244 if( fOptimiseInParallelConfigured && (NumCal << 245 { << 246 PrepareParallelOptimisation(allOpts, verbo << 247 ++NumCallsBuildOptimisations; << 248 } << 249 else << 250 { 133 { 251 BuildOptimisationsSequential(allOpts, verb << 134 fgInstance = &worldManager; 252 finishedOptimisation= true; << 253 } 135 } 254 << 136 return fgInstance; 255 return finishedOptimisation; << 256 } 137 } 257 138 258 // ******************************************* 139 // *************************************************************************** 259 // Creates optimisation info. Builds all voxel 140 // Creates optimisation info. Builds all voxels if allOpts=true 260 // otherwise it builds voxels only for replica 141 // otherwise it builds voxels only for replicated volumes. 261 // << 262 // This is the original sequential implementat << 263 // - at first initialisation to create voxels, << 264 // - at re-initialisation if the geometry has << 265 // ******************************************* 142 // *************************************************************************** 266 // 143 // 267 void G4GeometryManager::BuildOptimisationsSequ << 144 void G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose) 268 << 269 { 145 { 270 G4Timer timer; << 146 G4Timer timer; 271 G4Timer allTimer; << 147 G4Timer allTimer; 272 std::vector<G4SmartVoxelStat> stats; << 148 std::vector<G4SmartVoxelStat> stats; 273 << 149 if (verbose) { allTimer.Start(); } 274 if (verbose) { allTimer.Start(); } << 150 275 << 151 G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance(); 276 G4LogicalVolumeStore* Store = G4LogicalVolum << 152 G4LogicalVolume* volume; 277 G4LogicalVolume* volume; << 153 G4SmartVoxelHeader* head; 278 G4SmartVoxelHeader* head; << 154 279 << 155 for (size_t n=0; n<Store->size(); n++) 280 #ifdef G4GEOMETRY_VOXELDEBUG << 156 { 281 G4cout << G4endl << 157 if (verbose) timer.Start(); 282 << "*** G4GeometryManager::BuildOptimisat << 158 volume=(*Store)[n]; 283 << G4Threading::G4GetThreadId() << " all- << 159 // For safety, check if there are any existing voxels and 284 #endif << 160 // delete before replacement 285 << 161 // 286 for (auto & n : *Store) << 162 head = volume->GetVoxelHeader(); 287 { << 163 delete head; 288 if (verbose) timer.Start(); << 164 volume->SetVoxelHeader(0); 289 volume=n; << 165 if ( (volume->IsToOptimise()) 290 // For safety, check if there are any exis << 166 && (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) 291 // delete before replacement << 167 || ( (volume->GetNoDaughters()==1) 292 // << 168 && (volume->GetDaughter(0)->IsReplicated()==true) ) ) 293 head = volume->GetVoxelHeader(); << 169 { 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 170 #ifdef G4GEOMETRY_VOXELDEBUG 303 G4cout << "** G4GeometryManager::BuildOpti << 171 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 304 << " Examining logical volume nam << 172 << " Examining logical volume name = " 305 << "' #daughters= " << volume->Get << 173 << volume->GetName() << G4endl; 306 #endif 174 #endif 307 head = new G4SmartVoxelHeader(volume); << 175 head = new G4SmartVoxelHeader(volume); 308 << 176 if (head) 309 if (head != nullptr) << 177 { 310 { << 178 volume->SetVoxelHeader(head); 311 volume->SetVoxelHeader(head); << 179 } 312 } << 180 else 313 else << 181 { 314 { << 182 G4cerr << "ERROR - Allocation of new VoxelHeader" << G4endl 315 std::ostringstream message; << 183 << " for volume " << volume->GetName() << " failed." 316 message << "VoxelHeader allocation err << 184 << G4endl; 317 << "Allocation of new VoxelHea << 185 G4Exception("G4GeometryManager::BuildOptimisations()", "FatalError", 318 << " for volume '" << v << 186 FatalException, "VoxelHeader allocation error."); 319 G4Exception("G4GeometryManager::BuildO << 187 } 320 FatalException, message); << 188 if (verbose) 321 } << 189 { 322 if (verbose) << 190 timer.Stop(); 323 { << 191 stats.push_back( G4SmartVoxelStat( volume, head, 324 timer.Stop(); << 192 timer.GetSystemElapsed(), 325 stats.emplace_back( volume, head, << 193 timer.GetUserElapsed() ) ); 326 timer.GetSystemElap << 194 } 327 timer.GetUserElapse << 195 } 328 } << 196 else 329 } << 197 { 330 else << 198 // Don't create voxels for this node 331 { << 332 // Don't create voxels for this node << 333 #ifdef G4GEOMETRY_VOXELDEBUG 199 #ifdef G4GEOMETRY_VOXELDEBUG 334 auto numDaughters = volume->GetNoDaughte << 200 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 335 G4cout << "- Skipping logical volume wit << 201 << " Skipping logical volume name = " << volume->GetName() 336 << " daughters and name = '" << v << 202 << G4endl; 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 203 #endif 351 } << 204 } 352 } 205 } 353 if (verbose) 206 if (verbose) 354 { 207 { 355 allTimer.Stop(); << 208 allTimer.Stop(); 356 << 209 ReportVoxelStats( stats, allTimer.GetSystemElapsed() 357 ReportVoxelStats( stats, allTimer.GetSyste << 210 + allTimer.GetUserElapsed() ); 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 << 479 // ******************************************* << 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 } 211 } 664 } 212 } 665 213 666 // ******************************************* 214 // *************************************************************************** 667 // Ensure that all logical volumes in list hav << 215 // Creates optimisation info for the specified volumes subtree. 668 // ******************************************* << 669 // << 670 G4int G4GeometryManager::CheckOptimisation() << 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 // << 690 G4int << 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 << 708 // ******************************************* << 709 // Inform that all work for parallel optimisat << 710 // ******************************************* << 711 // << 712 void G4GeometryManager::InformOptimisationIsFi << 713 { << 714 if(verbose) // G4cout does not work! << 715 { << 716 std::cout << "** G4GeometryManager: All vo << 717 << G4endl; << 718 std::cout << " Total number of volumes o << 719 << fTotalNumberVolumesOptimised << 720 << " of " << fVolumesToOptimise. << 721 std::cout << " Number of workers reporti << 722 << fNumberThreadsReporting << 723 << " of " << G4Threading::GetNum << 724 << " expected\n"; << 725 } << 726 assert ( fTotalNumberVolumesOptimised == fVo << 727 << 728 fParallelVoxelOptimisationFinished = true; << 729 // fParallelVoxelOptimisationRequested = fal << 730 fParallelVoxelOptimisationUnderway = false; << 731 } << 732 << 733 // ******************************************* << 734 // Creates Optimisation info for the specified << 735 // ******************************************* 216 // *************************************************************************** 736 // 217 // 737 void G4GeometryManager::BuildOptimisations(G4b 218 void G4GeometryManager::BuildOptimisations(G4bool allOpts, 738 G4V 219 G4VPhysicalVolume* pVolume) 739 { 220 { 740 if (pVolume == nullptr) { return; } << 221 if (!pVolume) { return; } 741 << 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 222 752 G4SmartVoxelHeader* head = tVolume->GetVoxel << 223 // Retrieve the mother logical volume, if not NULL, 753 delete head; << 224 // otherwise apply global optimisation for the world volume 754 tVolume->SetVoxelHeader(nullptr); << 225 // 755 if ( ( (tVolume->IsToOptimise()) << 226 G4LogicalVolume* tVolume = pVolume->GetMotherLogical(); 756 && (tVolume->GetNoDaughters()>=kMinVo << 227 if (!tVolume) { return BuildOptimisations(allOpts, false); } 757 || ( (tVolume->GetNoDaughters()==1) << 228 758 && (tVolume->GetDaughter(0)->IsReplic << 229 G4SmartVoxelHeader* head = tVolume->GetVoxelHeader(); 759 { << 230 delete head; 760 head = new G4SmartVoxelHeader(tVolume); << 231 tVolume->SetVoxelHeader(0); 761 if (head != nullptr) << 232 if ( (tVolume->IsToOptimise()) 762 { << 233 && (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) 763 tVolume->SetVoxelHeader(head); << 234 || ( (tVolume->GetNoDaughters()==1) 764 } << 235 && (tVolume->GetDaughter(0)->IsReplicated()==true) ) ) 765 else << 236 { 766 { << 237 head = new G4SmartVoxelHeader(tVolume); 767 std::ostringstream message; << 238 if (head) 768 message << "VoxelHeader allocation error << 239 { 769 << "Allocation of new VoxelHeade << 240 tVolume->SetVoxelHeader(head); 770 << " for volume " << tVol << 241 } 771 G4Exception("G4GeometryManager::BuildOpt << 242 else 772 FatalException, message); << 243 { 773 } << 244 G4cerr << "ERROR - Allocation of new VoxelHeader" << G4endl 774 } << 245 << " for volume " << tVolume->GetName() << " failed." 775 else << 246 << G4endl; 776 { << 247 G4Exception("G4GeometryManager::BuildOptimisations()", "FatalError", 777 // Don't create voxels for this node << 248 FatalException, "VoxelHeader allocation error."); >> 249 } >> 250 } >> 251 else >> 252 { >> 253 // Don't create voxels for this node 778 #ifdef G4GEOMETRY_VOXELDEBUG 254 #ifdef G4GEOMETRY_VOXELDEBUG 779 G4cout << "** G4GeometryManager::BuildOpti << 255 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 780 << " Skipping logical volume na << 256 << " Skipping logical volume name = " << volume->GetName() 781 << G4endl; << 257 << G4endl; 782 #endif 258 #endif 783 } << 259 } 784 260 785 // Scan recursively the associated logical v << 261 // Scan recursively the associated logical volume tree 786 // << 262 // 787 tVolume = pVolume->GetLogicalVolume(); 263 tVolume = pVolume->GetLogicalVolume(); 788 if (tVolume->GetNoDaughters() != 0) << 264 if (tVolume->GetNoDaughters()) { BuildOptimisations(allOpts, tVolume->GetDaughter(0)); } 789 { << 790 BuildOptimisations(allOpts, tVolume->GetDa << 791 } << 792 } 265 } 793 266 794 // ******************************************* 267 // *************************************************************************** 795 // Removes all optimisation info. 268 // Removes all optimisation info. 796 // Loops over all logical volumes, deleting no << 269 // Loops over all logical volumes, deleting non-null voxels pointers, 797 // ******************************************* 270 // *************************************************************************** 798 // 271 // 799 void G4GeometryManager::DeleteOptimisations() 272 void G4GeometryManager::DeleteOptimisations() 800 { 273 { 801 G4LogicalVolume* tVolume = nullptr; << 274 G4LogicalVolume* tVolume = 0; 802 G4LogicalVolumeStore* Store = G4LogicalVolum 275 G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance(); 803 for (auto & n : *Store) << 276 for (size_t n=0; n<Store->size(); n++) 804 { 277 { 805 tVolume=n; << 278 tVolume=(*Store)[n]; 806 delete tVolume->GetVoxelHeader(); 279 delete tVolume->GetVoxelHeader(); 807 tVolume->SetVoxelHeader(nullptr); << 280 tVolume->SetVoxelHeader(0); 808 } 281 } 809 } 282 } 810 283 811 // ******************************************* 284 // *************************************************************************** 812 // Removes optimisation info for the specified 285 // Removes optimisation info for the specified subtree. 813 // Scans recursively all daughter volumes, del 286 // Scans recursively all daughter volumes, deleting non-null voxels pointers. 814 // ******************************************* 287 // *************************************************************************** 815 // 288 // 816 void G4GeometryManager::DeleteOptimisations(G4 289 void G4GeometryManager::DeleteOptimisations(G4VPhysicalVolume* pVolume) 817 { 290 { 818 if (pVolume == nullptr) { return; } << 291 if (!pVolume) { return; } 819 292 820 // Retrieve the mother logical volume, if no 293 // Retrieve the mother logical volume, if not NULL, 821 // otherwise global deletion to world volume 294 // otherwise global deletion to world volume. 822 // 295 // 823 G4LogicalVolume* tVolume = pVolume->GetMothe 296 G4LogicalVolume* tVolume = pVolume->GetMotherLogical(); 824 if (tVolume == nullptr) { return DeleteOptim << 297 if (!tVolume) { return DeleteOptimisations(); } 825 delete tVolume->GetVoxelHeader(); 298 delete tVolume->GetVoxelHeader(); 826 tVolume->SetVoxelHeader(nullptr); << 299 tVolume->SetVoxelHeader(0); 827 300 828 // Scan recursively the associated logical v 301 // Scan recursively the associated logical volume tree 829 // 302 // 830 tVolume = pVolume->GetLogicalVolume(); 303 tVolume = pVolume->GetLogicalVolume(); 831 if (tVolume->GetNoDaughters() != 0) << 304 if (tVolume->GetNoDaughters()) { DeleteOptimisations(tVolume->GetDaughter(0)); } 832 { << 833 DeleteOptimisations(tVolume->GetDaughter(0 << 834 } << 835 } << 836 << 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 } 305 } 855 306 856 // ******************************************* 307 // *************************************************************************** 857 // Reports statistics on voxel optimisation wh 308 // Reports statistics on voxel optimisation when closing geometry. 858 // ******************************************* 309 // *************************************************************************** 859 // 310 // 860 void 311 void 861 G4GeometryManager::ReportVoxelStats( std::vect 312 G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats, 862 G4double << 313 G4double totalCpuTime ) 863 std::ostr << 864 { 314 { 865 os << "------------------------------------- << 315 G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics" 866 << G4endl; << 867 os << "G4GeometryManager::ReportVoxelStats - << 868 << G4endl << G4endl; 316 << G4endl << G4endl; 869 317 870 // 318 // 871 // Get total memory use 319 // Get total memory use 872 // 320 // 873 G4int i, nStat = (G4int)stats.size(); << 321 G4int i, nStat = stats.size(); 874 G4long totalMemory = 0; 322 G4long totalMemory = 0; 875 323 876 for( i=0; i<nStat; ++i ) { totalMemory += s << 324 for( i=0;i<nStat;++i ) { totalMemory += stats[i].GetMemoryUse(); } 877 325 878 os << " Total memory consumed for geometr << 326 G4cout << " Total memory consumed for geometry optimisation: " 879 << totalMemory/1024 << " kByte" << G4 327 << totalMemory/1024 << " kByte" << G4endl; 880 os << " Total CPU time elapsed for geomet << 328 G4cout << " Total CPU time elapsed for geometry optimisation: " 881 << std::setprecision(4) << totalCpuTi << 329 << std::setprecision(2) << totalCpuTime << " seconds" << G4endl; 882 << std::setprecision(6) << G4endl; << 883 330 884 // 331 // 885 // First list: sort by total CPU time 332 // First list: sort by total CPU time 886 // 333 // 887 std::sort( stats.begin(), stats.end(), << 334 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByCpu() ); 888 [](const G4SmartVoxelStat& a, const G4Smar << 889 { << 890 return a.GetTotalTime() > b.GetTotalTime() << 891 } ); << 892 335 893 const G4int maxPrint = 20; << 336 G4int nPrint = nStat > 10 ? 10 : nStat; 894 G4int nPrint = std::min ( nStat, maxPrint ); << 895 337 896 if (nPrint != 0) << 338 if (nPrint) 897 { 339 { 898 os << "\n Voxelisation: top CPU users:" << 340 G4cout << "\n Voxelisation: top CPU users:" << G4endl; 899 os << " Percent Total CPU System C << 341 G4cout << " Percent Total CPU System CPU Memory Volume\n" 900 << " ------- ---------- -------- << 342 << " ------- ---------- ---------- -------- ----------" 901 << G4endl; << 343 << G4endl; >> 344 // 12345678901.234567890123.234567890123.234567890123k . 902 } 345 } 903 346 904 for(i=0; i<nPrint; ++i) << 347 for(i=0;i<nPrint;++i) 905 { 348 { 906 G4double total = stats[i].GetTotalTime(); 349 G4double total = stats[i].GetTotalTime(); 907 G4double system = stats[i].GetSysTime(); 350 G4double system = stats[i].GetSysTime(); 908 G4double perc = 0.0; 351 G4double perc = 0.0; 909 352 910 if (system < 0) { system = 0.0; } 353 if (system < 0) { system = 0.0; } 911 if ((total < 0) || (totalCpuTime < perMill 354 if ((total < 0) || (totalCpuTime < perMillion)) 912 { total = 0; } 355 { total = 0; } 913 else 356 else 914 { perc = total*100/totalCpuTime; } 357 { perc = total*100/totalCpuTime; } 915 358 916 os << std::setprecision(2) << 359 G4cout << std::setprecision(2) 917 << std::setiosflags(std::ios::fixed 360 << std::setiosflags(std::ios::fixed|std::ios::right) 918 << std::setw(11) << perc 361 << std::setw(11) << perc 919 << std::setw(13) << total 362 << std::setw(13) << total 920 << std::setw(13) << system 363 << std::setw(13) << system 921 << std::setw(13) << (stats[i].GetMe 364 << std::setw(13) << (stats[i].GetMemoryUse()+512)/1024 922 << "k " << std::setiosflags(std::io 365 << "k " << std::setiosflags(std::ios::left) 923 << stats[i].GetVolume()->GetName() 366 << stats[i].GetVolume()->GetName() 924 << std::resetiosflags(std::ios::flo 367 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 925 << std::setprecision(6) 368 << std::setprecision(6) 926 << G4endl; 369 << G4endl; 927 } 370 } 928 371 929 // 372 // 930 // Second list: sort by memory use 373 // Second list: sort by memory use 931 // 374 // 932 std::sort( stats.begin(), stats.end(), << 375 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByMemory() ); 933 [](const G4SmartVoxelStat& a, const G4Smar << 934 { << 935 return a.GetMemoryUse() > b.GetMemoryUse() << 936 } ); << 937 376 938 if (nPrint != 0) << 377 if (nPrint) 939 { 378 { 940 os << "\n Voxelisation: top memory user << 379 G4cout << "\n Voxelisation: top memory users:" << G4endl; 941 os << " Percent Memory Heads << 380 G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n" 942 << " ------- -------- ------ << 381 << " ------- -------- ------ ------ -------- ---------- ----------" 943 << G4endl; << 382 << G4endl; >> 383 // 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. . 944 } 384 } 945 385 946 for(i=0; i<nPrint; ++i) << 386 for(i=0;i<nPrint;++i) 947 { 387 { 948 G4long memory = stats[i].GetMemoryUse(); 388 G4long memory = stats[i].GetMemoryUse(); 949 G4double totTime = stats[i].GetTotalTime() 389 G4double totTime = stats[i].GetTotalTime(); 950 if (totTime < 0) { totTime = 0.0; } 390 if (totTime < 0) { totTime = 0.0; } 951 391 952 os << std::setprecision(2) << 392 G4cout << std::setprecision(2) 953 << std::setiosflags(std::ios::fixed|std << 393 << std::setiosflags(std::ios::fixed|std::ios::right) 954 << std::setw(11) << G4double(memory*100 << 394 << std::setw(11) << G4double(memory*100)/G4double(totalMemory) 955 << std::setw(11) << memory/1024 << "k " << 395 << std::setw(11) << memory/1024 << "k " 956 << std::setw( 9) << stats[i].GetNumberH << 396 << std::setw( 9) << stats[i].GetNumberHeads() 957 << std::setw( 9) << stats[i].GetNumberN << 397 << std::setw( 9) << stats[i].GetNumberNodes() 958 << std::setw(11) << stats[i].GetNumberP << 398 << std::setw(11) << stats[i].GetNumberPointers() 959 << std::setw(13) << totTime << " " << 399 << std::setw(13) << totTime << " " 960 << std::setiosflags(std::ios::left) << 400 << std::setiosflags(std::ios::left) 961 << stats[i].GetVolume()->GetName() << 401 << stats[i].GetVolume()->GetName() 962 << std::resetiosflags(std::ios::floatfi << 402 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 963 << std::setprecision(6) << 403 << std::setprecision(6) 964 << G4endl; << 404 << G4endl; 965 } 405 } 966 os << "------------------------------------- << 967 << G4endl << G4endl; << 968 } << 969 << 970 // ******************************************* << 971 // Check whether parallel optimisation was req << 972 // ******************************************* << 973 // << 974 G4bool G4GeometryManager::IsParallelOptimisati << 975 { << 976 return fOptimiseInParallelConfigured; << 977 } << 978 << 979 // ******************************************* << 980 // Report whether parallel optimisation is don << 981 // ******************************************* << 982 // << 983 G4bool G4GeometryManager::IsParallelOptimisati << 984 { << 985 return fParallelVoxelOptimisationFinished; << 986 } 406 } 987 407