Geant4 Cross Reference |
>> 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