Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer << 3 // * DISCLAIMER * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th << 5 // * The following disclaimer summarizes all the specific disclaimers * 6 // * the Geant4 Collaboration. It is provided << 6 // * of contributors to this software. The specific disclaimers,which * 7 // * conditions of the Geant4 Software License << 7 // * govern, are listed with their locations in: * 8 // * LICENSE and available at http://cern.ch/ << 8 // * http://cern.ch/geant4/license * 9 // * include a list of copyright holders. << 10 // * 9 // * * 11 // * Neither the authors of this software syst 10 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 11 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 12 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 13 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file << 14 // * use. * 16 // * for the full disclaimer and the limitatio << 17 // * 15 // * * 18 // * This code implementation is the result << 16 // * This code implementation is the intellectual property of the * 19 // * technical work of the GEANT4 collaboratio << 17 // * GEANT4 collaboration. * 20 // * By using, copying, modifying or distri << 18 // * By copying, distributing or modifying the Program (or any work * 21 // * any work based on the software) you ag << 19 // * based on the Program) you indicate your acceptance of this * 22 // * use in resulting scientific publicati << 20 // * statement, and all its terms. * 23 // * acceptance of all terms of the Geant4 Sof << 24 // ******************************************* 21 // ******************************************************************** 25 // 22 // 26 // Class G4GeometryManager implementation << 27 // 23 // 28 // 26.07.95, P.Kent - Initial version, includi << 24 // $Id: G4GeometryManager.cc,v 1.15 2003/11/02 14:01:23 gcosmo Exp $ 29 // 12.06.24, J.Apostolakis - Added parallel op << 25 // GEANT4 tag $Name: geant4-06-00-patch-01 $ >> 26 // >> 27 // class G4GeometryManager >> 28 // >> 29 // Implementation >> 30 // >> 31 // Author: >> 32 // 26.07.95 P.Kent Initial version, including optimisation Build 30 // ------------------------------------------- 33 // -------------------------------------------------------------------- 31 34 32 #include <iomanip> 35 #include <iomanip> 33 << 34 #include "G4ios.hh" << 35 #include "G4Timer.hh" 36 #include "G4Timer.hh" 36 #include "G4GeometryManager.hh" 37 #include "G4GeometryManager.hh" 37 #include "G4SystemOfUnits.hh" << 38 38 #include "G4Threading.hh" << 39 #ifdef G4GEOMETRY_VOXELDEBUG >> 40 #include "G4ios.hh" >> 41 #endif 39 42 40 // Needed for building optimisations 43 // Needed for building optimisations 41 // 44 // 42 #include "G4LogicalVolumeStore.hh" 45 #include "G4LogicalVolumeStore.hh" 43 #include "G4VPhysicalVolume.hh" << 46 #include "G4LogicalVolume.hh" 44 #include "G4SmartVoxelHeader.hh" 47 #include "G4SmartVoxelHeader.hh" 45 #include "voxeldefs.hh" 48 #include "voxeldefs.hh" 46 49 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 // ******************************************* 50 // *************************************************************************** 75 // Static class data << 51 // Static class variable: ptr to single instance of class 76 // ******************************************* 52 // *************************************************************************** 77 // 53 // 78 G4ThreadLocal G4GeometryManager* G4GeometryMan << 54 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 55 107 // ******************************************* 56 // *************************************************************************** 108 // Destructor << 57 // Constructor. Set the geometry to be open 109 // ******************************************* 58 // *************************************************************************** 110 // 59 // 111 G4GeometryManager::~G4GeometryManager() << 60 G4GeometryManager::G4GeometryManager() 112 { 61 { 113 fgInstance = nullptr; << 62 fIsClosed=false; 114 fIsClosed = false; << 115 << 116 if( fWallClockTimer && G4Threading::IsMaster << 117 { << 118 delete fWallClockTimer; << 119 fWallClockTimer= nullptr; << 120 } << 121 } 63 } 122 64 123 // ******************************************* 65 // *************************************************************************** 124 // Closes geometry - performs sanity checks an 66 // Closes geometry - performs sanity checks and optionally builds optimisation 125 // for placed volumes (always built for replic 67 // for placed volumes (always built for replicas & parameterised). 126 // NOTE: Currently no sanity checks are perfor 68 // NOTE: Currently no sanity checks are performed. 127 // Applies to just a specific subtree if a phy << 128 // ******************************************* 69 // *************************************************************************** 129 // 70 // 130 G4bool G4GeometryManager::CloseGeometry(G4bool << 71 G4bool G4GeometryManager::CloseGeometry(G4bool pOptimise, G4bool verbose) 131 G4VPhy << 132 { 72 { 133 if (!fIsClosed && G4Threading::IsMasterThrea << 73 if (!fIsClosed) 134 { 74 { 135 if (pVolume != nullptr) << 75 BuildOptimisations(pOptimise, verbose); 136 { << 76 fIsClosed=true; 137 BuildOptimisations(pOptimise, pVolume); << 138 } << 139 else << 140 { << 141 BuildOptimisations(pOptimise, verbose); << 142 } << 143 fIsClosed = true; << 144 } 77 } 145 return true; 78 return true; 146 } 79 } 147 80 148 // ******************************************* 81 // *************************************************************************** 149 // Opens the geometry and removes optimisation << 82 // Opens the geometry and removes all optimisations. 150 // the specified logical-volume). << 151 // Applies to just a specific subtree if a phy << 152 // ******************************************* 83 // *************************************************************************** 153 // 84 // 154 void G4GeometryManager::OpenGeometry(G4VPhysic << 85 void G4GeometryManager::OpenGeometry() 155 { 86 { 156 if (fIsClosed && G4Threading::IsMasterThread << 87 if (fIsClosed) 157 { 88 { 158 if (pVolume != nullptr) << 89 DeleteOptimisations(); 159 { << 90 fIsClosed=false; 160 DeleteOptimisations(pVolume); << 161 } << 162 else << 163 { << 164 DeleteOptimisations(); << 165 } << 166 fIsClosed = false; << 167 } 91 } 168 } 92 } 169 93 170 // ******************************************* 94 // *************************************************************************** 171 // Returns the instance of the singleton. << 95 // Returns status of geometry 172 // Creates it in case it's called for the firs << 173 // ******************************************* 96 // *************************************************************************** 174 // 97 // 175 G4GeometryManager* G4GeometryManager::GetInsta << 98 G4bool G4GeometryManager::IsGeometryClosed() 176 { 99 { 177 if (fgInstance == nullptr) << 100 return fIsClosed; 178 { << 179 fgInstance = new G4GeometryManager; << 180 << 181 if( (fWallClockTimer == nullptr) && G4Thre << 182 { << 183 fWallClockTimer = new G4Timer; << 184 } << 185 } << 186 return fgInstance; << 187 } 101 } 188 102 189 // ******************************************* 103 // *************************************************************************** 190 // Returns the instance of the singleton. 104 // Returns the instance of the singleton. >> 105 // Creates it in case it's called for the first time. 191 // ******************************************* 106 // *************************************************************************** 192 // 107 // 193 G4GeometryManager* G4GeometryManager::GetInsta << 108 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 { 109 { 238 G4bool finishedOptimisation = false; << 110 static G4GeometryManager worldManager; 239 << 111 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 { 112 { 251 BuildOptimisationsSequential(allOpts, verb << 113 fgInstance = &worldManager; 252 finishedOptimisation= true; << 253 } 114 } 254 << 115 return fgInstance; 255 return finishedOptimisation; << 256 } 116 } 257 117 258 // ******************************************* 118 // *************************************************************************** 259 // Creates optimisation info. Builds all voxel 119 // Creates optimisation info. Builds all voxels if allOpts=true 260 // otherwise it builds voxels only for replica 120 // 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 // ******************************************* << 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 // ******************************************* 121 // *************************************************************************** 372 // 122 // 373 void << 123 void G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose) 374 G4GeometryManager::CreateListOfVolumesToOptimi << 375 { 124 { 376 // Prepare the work - must be called only in << 125 G4Timer timer; 377 << 126 G4Timer allTimer; 378 G4LogicalVolumeStore* Store = G4LogicalVolum << 127 std::vector<G4SmartVoxelStat> stats; 379 << 128 if (verbose) allTimer.Start(); 380 if( !fVolumesToOptimise.empty() ) << 129 381 { << 130 G4LogicalVolumeStore *Store; 382 ResetListOfVolumesToOptimise(); << 131 G4LogicalVolume *volume; 383 } << 132 G4SmartVoxelHeader *head; 384 << 133 G4int nVolumes, n; 385 for (auto & n : *Store) << 134 Store=G4LogicalVolumeStore::GetInstance(); 386 { << 135 nVolumes=Store->size(); 387 G4LogicalVolume* volume=n; << 136 388 << 137 for (n=0; n<nVolumes; n++) 389 if ( ( (volume->IsToOptimise()) << 138 { 390 && (volume->GetNoDaughters()>=kMi << 139 if (verbose) timer.Start(); 391 || ( (volume->GetNoDaughters()==1) << 140 volume=(*Store)[n]; 392 && (volume->GetDaughter(0)->IsRepl << 141 // For safety, check if there are any existing voxels and 393 && (volume->GetDaughter(0)->GetReg << 142 // delete before replacement 394 { << 143 // 395 fVolumesToOptimise.push_back(volume); << 144 head = volume->GetVoxelHeader(); 396 << 145 if (head) 397 // For safety, must check (later) if the << 146 { 398 // delete before replacement: << 147 delete head; 399 // All 'clients' of this code must do th << 148 volume->SetVoxelHeader(0); 400 // delete volume->GetVoxelHeader(); << 149 } 401 // volume->SetVoxelHeader(nullptr); << 150 if ( (volume->IsToOptimise()) 402 << 151 && (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) >> 152 || ( (volume->GetNoDaughters()==1) >> 153 && (volume->GetDaughter(0)->IsReplicated()==true) ) ) >> 154 { 403 #ifdef G4GEOMETRY_VOXELDEBUG 155 #ifdef G4GEOMETRY_VOXELDEBUG 404 G4cout << "- Booking logical volume wit << 156 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 405 << " daughters and name = '" << volume-> << 157 << " Examining logical volume name = " 406 << " -- for optimisation (ie voxels will << 158 << volume->GetName() << G4endl; 407 #endif 159 #endif 408 } << 160 head = new G4SmartVoxelHeader(volume); 409 else << 161 if (head) 410 { << 162 { >> 163 volume->SetVoxelHeader(head); >> 164 } >> 165 else >> 166 { >> 167 G4cerr << "ERROR - Allocation of new VoxelHeader failed." << G4endl; >> 168 G4Exception("G4GeometryManager::BuildOptimisations()", "FatalError", >> 169 FatalException, "VoxelHeader allocation error."); >> 170 } >> 171 if (verbose) >> 172 { >> 173 timer.Stop(); >> 174 stats.push_back( G4SmartVoxelStat( volume, head, >> 175 timer.GetSystemElapsed(), >> 176 timer.GetUserElapsed() ) ); >> 177 } >> 178 } >> 179 else >> 180 { >> 181 // Don't create voxels for this node 411 #ifdef G4GEOMETRY_VOXELDEBUG 182 #ifdef G4GEOMETRY_VOXELDEBUG 412 G4cout << "- Skipping logical volume wit << 183 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 413 << " daughters and name = '" << volume-> << 184 << " Skipping logical volume name = " << volume->GetName() 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 } << 664 } << 665 << 666 // ******************************************* << 667 // Ensure that all logical volumes in list hav << 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; 185 << 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 // ******************************************* << 736 // << 737 void G4GeometryManager::BuildOptimisations(G4b << 738 G4V << 739 { << 740 if (pVolume == nullptr) { 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 << 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 186 #endif >> 187 } 783 } 188 } 784 << 189 if (verbose) 785 // Scan recursively the associated logical v << 786 // << 787 tVolume = pVolume->GetLogicalVolume(); << 788 if (tVolume->GetNoDaughters() != 0) << 789 { 190 { 790 BuildOptimisations(allOpts, tVolume->GetDa << 191 allTimer.Stop(); >> 192 ReportVoxelStats( stats, allTimer.GetSystemElapsed() >> 193 + allTimer.GetUserElapsed() ); 791 } 194 } 792 } 195 } 793 196 794 // ******************************************* 197 // *************************************************************************** 795 // Removes all optimisation info. 198 // Removes all optimisation info. 796 // Loops over all logical volumes, deleting no 199 // Loops over all logical volumes, deleting non-null voxels pointers. 797 // ******************************************* 200 // *************************************************************************** 798 // 201 // 799 void G4GeometryManager::DeleteOptimisations() 202 void G4GeometryManager::DeleteOptimisations() 800 { 203 { 801 G4LogicalVolume* tVolume = nullptr; << 204 G4LogicalVolumeStore* Store=G4LogicalVolumeStore::GetInstance(); 802 G4LogicalVolumeStore* Store = G4LogicalVolum << 205 G4LogicalVolume* volume; 803 for (auto & n : *Store) << 206 G4SmartVoxelHeader* head; 804 { << 207 G4int nVolumes, n; 805 tVolume=n; << 208 nVolumes = Store->size(); 806 delete tVolume->GetVoxelHeader(); << 807 tVolume->SetVoxelHeader(nullptr); << 808 } << 809 } << 810 << 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 << 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 209 828 // Scan recursively the associated logical v << 210 for (n=0; n<nVolumes; n++) 829 // << 830 tVolume = pVolume->GetLogicalVolume(); << 831 if (tVolume->GetNoDaughters() != 0) << 832 { 211 { 833 DeleteOptimisations(tVolume->GetDaughter(0 << 212 volume=(*Store)[n]; 834 } << 213 head=volume->GetVoxelHeader(); 835 } << 214 if (head) 836 << 215 { 837 // ******************************************* << 216 delete head; 838 // Sets the maximum extent of the world volume << 217 volume->SetVoxelHeader(0); 839 // if NO solids have been created already. << 218 } 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 } 219 } 853 G4GeometryTolerance::GetInstance()->SetSurfa << 854 } 220 } 855 221 856 // ******************************************* 222 // *************************************************************************** 857 // Reports statistics on voxel optimisation wh 223 // Reports statistics on voxel optimisation when closing geometry. 858 // ******************************************* 224 // *************************************************************************** 859 // 225 // 860 void 226 void 861 G4GeometryManager::ReportVoxelStats( std::vect 227 G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats, 862 G4double << 228 G4double totalCpuTime ) 863 std::ostr << 864 { 229 { 865 os << "------------------------------------- << 230 G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics" 866 << G4endl; << 867 os << "G4GeometryManager::ReportVoxelStats - << 868 << G4endl << G4endl; 231 << G4endl << G4endl; 869 232 870 // 233 // 871 // Get total memory use 234 // Get total memory use 872 // 235 // 873 G4int i, nStat = (G4int)stats.size(); << 236 G4int i, nStat = stats.size(); 874 G4long totalMemory = 0; 237 G4long totalMemory = 0; 875 238 876 for( i=0; i<nStat; ++i ) { totalMemory += s << 239 for( i=0;i<nStat;++i ) totalMemory += stats[i].GetMemoryUse(); 877 240 878 os << " Total memory consumed for geometr << 241 G4cout << " Total memory consumed for geometry optimisation: " 879 << totalMemory/1024 << " kByte" << G4 242 << totalMemory/1024 << " kByte" << G4endl; 880 os << " Total CPU time elapsed for geomet << 243 G4cout << " Total CPU time elapsed for geometry optimisation: " 881 << std::setprecision(4) << totalCpuTi << 244 << std::setprecision(2) << totalCpuTime << " seconds" << G4endl; 882 << std::setprecision(6) << G4endl; << 883 245 884 // 246 // 885 // First list: sort by total CPU time 247 // First list: sort by total CPU time 886 // 248 // 887 std::sort( stats.begin(), stats.end(), << 249 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByCpu() ); 888 [](const G4SmartVoxelStat& a, const G4Smar << 889 { << 890 return a.GetTotalTime() > b.GetTotalTime() << 891 } ); << 892 250 893 const G4int maxPrint = 20; << 251 G4int nPrint = nStat > 10 ? 10 : nStat; 894 G4int nPrint = std::min ( nStat, maxPrint ); << 895 252 896 if (nPrint != 0) << 253 if (nPrint) 897 { 254 { 898 os << "\n Voxelisation: top CPU users:" << 255 G4cout << "\n Voxelisation: top CPU users:" << G4endl; 899 os << " Percent Total CPU System C << 256 G4cout << " Percent Total CPU System CPU Memory Volume\n" 900 << " ------- ---------- -------- << 257 << " ------- ---------- ---------- -------- ----------" 901 << G4endl; << 258 << G4endl; >> 259 // 12345678901.234567890123.234567890123.234567890123k . 902 } 260 } 903 261 904 for(i=0; i<nPrint; ++i) << 262 for(i=0;i<nPrint;++i) 905 { 263 { 906 G4double total = stats[i].GetTotalTime(); 264 G4double total = stats[i].GetTotalTime(); 907 G4double system = stats[i].GetSysTime(); 265 G4double system = stats[i].GetSysTime(); 908 G4double perc = 0.0; 266 G4double perc = 0.0; 909 267 910 if (system < 0) { system = 0.0; } << 268 if (system < 0) system = 0.0; 911 if ((total < 0) || (totalCpuTime < perMill 269 if ((total < 0) || (totalCpuTime < perMillion)) 912 { total = 0; } << 270 total = 0; 913 else 271 else 914 { perc = total*100/totalCpuTime; } << 272 perc = total*100/totalCpuTime; 915 273 916 os << std::setprecision(2) << 274 G4cout << std::setprecision(2) 917 << std::setiosflags(std::ios::fixed 275 << std::setiosflags(std::ios::fixed|std::ios::right) 918 << std::setw(11) << perc 276 << std::setw(11) << perc 919 << std::setw(13) << total 277 << std::setw(13) << total 920 << std::setw(13) << system 278 << std::setw(13) << system 921 << std::setw(13) << (stats[i].GetMe 279 << std::setw(13) << (stats[i].GetMemoryUse()+512)/1024 922 << "k " << std::setiosflags(std::io 280 << "k " << std::setiosflags(std::ios::left) 923 << stats[i].GetVolume()->GetName() 281 << stats[i].GetVolume()->GetName() 924 << std::resetiosflags(std::ios::flo 282 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 925 << std::setprecision(6) 283 << std::setprecision(6) 926 << G4endl; 284 << G4endl; 927 } 285 } 928 286 929 // 287 // 930 // Second list: sort by memory use 288 // Second list: sort by memory use 931 // 289 // 932 std::sort( stats.begin(), stats.end(), << 290 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByMemory() ); 933 [](const G4SmartVoxelStat& a, const G4Smar << 934 { << 935 return a.GetMemoryUse() > b.GetMemoryUse() << 936 } ); << 937 291 938 if (nPrint != 0) << 292 if (nPrint) 939 { 293 { 940 os << "\n Voxelisation: top memory user << 294 G4cout << "\n Voxelisation: top memory users:" << G4endl; 941 os << " Percent Memory Heads << 295 G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n" 942 << " ------- -------- ------ << 296 << " ------- -------- ------ ------ -------- ---------- ----------" 943 << G4endl; << 297 << G4endl; >> 298 // 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. . 944 } 299 } 945 300 946 for(i=0; i<nPrint; ++i) << 301 for(i=0;i<nPrint;++i) 947 { 302 { 948 G4long memory = stats[i].GetMemoryUse(); 303 G4long memory = stats[i].GetMemoryUse(); 949 G4double totTime = stats[i].GetTotalTime() 304 G4double totTime = stats[i].GetTotalTime(); 950 if (totTime < 0) { totTime = 0.0; } << 305 if (totTime < 0) totTime = 0.0; 951 306 952 os << std::setprecision(2) << 307 G4cout << std::setprecision(2) 953 << std::setiosflags(std::ios::fixed|std << 308 << std::setiosflags(std::ios::fixed|std::ios::right) 954 << std::setw(11) << G4double(memory*100 << 309 << std::setw(11) << G4double(memory*100)/G4double(totalMemory) 955 << std::setw(11) << memory/1024 << "k " << 310 << std::setw(11) << memory/1024 << "k " 956 << std::setw( 9) << stats[i].GetNumberH << 311 << std::setw( 9) << stats[i].GetNumberHeads() 957 << std::setw( 9) << stats[i].GetNumberN << 312 << std::setw( 9) << stats[i].GetNumberNodes() 958 << std::setw(11) << stats[i].GetNumberP << 313 << std::setw(11) << stats[i].GetNumberPointers() 959 << std::setw(13) << totTime << " " << 314 << std::setw(13) << totTime << " " 960 << std::setiosflags(std::ios::left) << 315 << std::setiosflags(std::ios::left) 961 << stats[i].GetVolume()->GetName() << 316 << stats[i].GetVolume()->GetName() 962 << std::resetiosflags(std::ios::floatfi << 317 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 963 << std::setprecision(6) << 318 << std::setprecision(6) 964 << G4endl; << 319 << G4endl; 965 } 320 } 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 } 321 } 987 322