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$ 29 // 12.06.24, J.Apostolakis - Added parallel op << 28 // >> 29 // class G4GeometryManager >> 30 // >> 31 // Implementation >> 32 // >> 33 // Author: >> 34 // 26.07.95 P.Kent Initial version, including optimisation Build 30 // ------------------------------------------- 35 // -------------------------------------------------------------------- 31 36 32 #include <iomanip> 37 #include <iomanip> 33 << 34 #include "G4ios.hh" << 35 #include "G4Timer.hh" 38 #include "G4Timer.hh" 36 #include "G4GeometryManager.hh" 39 #include "G4GeometryManager.hh" 37 #include "G4SystemOfUnits.hh" 40 #include "G4SystemOfUnits.hh" 38 #include "G4Threading.hh" << 41 >> 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 53 // Needed for setting the extent for tolerance value 48 // 54 // 49 #include "G4GeometryTolerance.hh" 55 #include "G4GeometryTolerance.hh" 50 #include "G4SolidStore.hh" 56 #include "G4SolidStore.hh" 51 #include "G4VSolid.hh" 57 #include "G4VSolid.hh" 52 58 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 // ******************************************* 59 // *************************************************************************** 75 // Static class data 60 // Static class data 76 // ******************************************* 61 // *************************************************************************** 77 // 62 // 78 G4ThreadLocal G4GeometryManager* G4GeometryMan << 63 G4ThreadLocal G4GeometryManager* G4GeometryManager::fgInstance = 0; >> 64 G4ThreadLocal G4bool G4GeometryManager::fIsClosed = false; 79 65 80 // Static *global* class data << 66 // *************************************************************************** 81 G4bool G4GeometryManager::fParallelVoxelOptimi << 67 // Constructor. Set the geometry to be open 82 // Records User choice to use parallel voxel << 68 // *************************************************************************** 83 << 69 // 84 G4bool G4GeometryManager::fOptimiseInParallel << 70 G4GeometryManager::G4GeometryManager() 85 // Configured = requested && available (ie i << 71 { 86 // Value calculated during each effort to op << 72 } 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 73 107 // ******************************************* 74 // *************************************************************************** 108 // Destructor 75 // Destructor 109 // ******************************************* 76 // *************************************************************************** 110 // 77 // 111 G4GeometryManager::~G4GeometryManager() 78 G4GeometryManager::~G4GeometryManager() 112 { 79 { 113 fgInstance = nullptr; << 80 fgInstance = 0; 114 fIsClosed = false; 81 fIsClosed = false; 115 << 116 if( fWallClockTimer && G4Threading::IsMaster << 117 { << 118 delete fWallClockTimer; << 119 fWallClockTimer= nullptr; << 120 } << 121 } 82 } 122 83 123 // ******************************************* 84 // *************************************************************************** 124 // Closes geometry - performs sanity checks an 85 // Closes geometry - performs sanity checks and optionally builds optimisation 125 // for placed volumes (always built for replic 86 // for placed volumes (always built for replicas & parameterised). 126 // NOTE: Currently no sanity checks are perfor 87 // NOTE: Currently no sanity checks are performed. 127 // Applies to just a specific subtree if a phy 88 // Applies to just a specific subtree if a physical volume is specified. 128 // ******************************************* 89 // *************************************************************************** 129 // 90 // 130 G4bool G4GeometryManager::CloseGeometry(G4bool 91 G4bool G4GeometryManager::CloseGeometry(G4bool pOptimise, G4bool verbose, 131 G4VPhy 92 G4VPhysicalVolume* pVolume) 132 { 93 { 133 if (!fIsClosed && G4Threading::IsMasterThrea << 94 if (!fIsClosed) 134 { 95 { 135 if (pVolume != nullptr) << 96 if (pVolume) 136 { 97 { 137 BuildOptimisations(pOptimise, pVolume); 98 BuildOptimisations(pOptimise, pVolume); 138 } 99 } 139 else 100 else 140 { 101 { 141 BuildOptimisations(pOptimise, verbose); 102 BuildOptimisations(pOptimise, verbose); 142 } 103 } 143 fIsClosed = true; << 104 fIsClosed=true; 144 } 105 } 145 return true; 106 return true; 146 } 107 } 147 108 148 // ******************************************* 109 // *************************************************************************** 149 // Opens the geometry and removes optimisation 110 // Opens the geometry and removes optimisations (optionally, related to just 150 // the specified logical-volume). 111 // the specified logical-volume). 151 // Applies to just a specific subtree if a phy 112 // Applies to just a specific subtree if a physical volume is specified. 152 // ******************************************* 113 // *************************************************************************** 153 // 114 // 154 void G4GeometryManager::OpenGeometry(G4VPhysic 115 void G4GeometryManager::OpenGeometry(G4VPhysicalVolume* pVolume) 155 { 116 { 156 if (fIsClosed && G4Threading::IsMasterThread << 117 if (fIsClosed) 157 { 118 { 158 if (pVolume != nullptr) << 119 if (pVolume) 159 { 120 { 160 DeleteOptimisations(pVolume); 121 DeleteOptimisations(pVolume); 161 } 122 } 162 else 123 else 163 { 124 { 164 DeleteOptimisations(); 125 DeleteOptimisations(); 165 } 126 } 166 fIsClosed = false; << 127 fIsClosed=false; 167 } 128 } 168 } 129 } 169 130 170 // ******************************************* 131 // *************************************************************************** >> 132 // Returns status of geometry >> 133 // *************************************************************************** >> 134 // >> 135 G4bool G4GeometryManager::IsGeometryClosed() >> 136 { >> 137 return fIsClosed; >> 138 } >> 139 >> 140 // *************************************************************************** 171 // Returns the instance of the singleton. 141 // Returns the instance of the singleton. 172 // Creates it in case it's called for the firs 142 // Creates it in case it's called for the first time. 173 // ******************************************* 143 // *************************************************************************** 174 // 144 // 175 G4GeometryManager* G4GeometryManager::GetInsta 145 G4GeometryManager* G4GeometryManager::GetInstance() 176 { 146 { 177 if (fgInstance == nullptr) << 147 if (!fgInstance) 178 { 148 { 179 fgInstance = new G4GeometryManager; 149 fgInstance = new G4GeometryManager; 180 << 181 if( (fWallClockTimer == nullptr) && G4Thre << 182 { << 183 fWallClockTimer = new G4Timer; << 184 } << 185 } 150 } 186 return fgInstance; 151 return fgInstance; 187 } 152 } 188 153 189 // ******************************************* 154 // *************************************************************************** 190 // Returns the instance of the singleton. 155 // Returns the instance of the singleton. 191 // ******************************************* 156 // *************************************************************************** 192 // 157 // 193 G4GeometryManager* G4GeometryManager::GetInsta 158 G4GeometryManager* G4GeometryManager::GetInstanceIfExist() 194 { 159 { 195 return fgInstance; 160 return fgInstance; 196 } 161 } 197 162 198 // ******************************************* 163 // *************************************************************************** 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 164 // Creates optimisation info. Builds all voxels if allOpts=true 232 // otherwise it builds voxels only for replica 165 // otherwise it builds voxels only for replicated volumes. 233 // ******************************************* 166 // *************************************************************************** 234 // Returns whether optimisation is finished << 235 // 167 // 236 G4bool G4GeometryManager::BuildOptimisations(G << 168 void G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose) 237 { 169 { 238 G4bool finishedOptimisation = false; << 170 G4Timer timer; 239 << 171 G4Timer allTimer; 240 fOptimiseInParallelConfigured = fParallelVox << 172 std::vector<G4SmartVoxelStat> stats; 241 && G4Threading: << 173 if (verbose) { allTimer.Start(); } 242 << 174 243 static unsigned int NumCallsBuildOptimisatio << 175 G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance(); 244 if( fOptimiseInParallelConfigured && (NumCal << 176 G4LogicalVolume* volume; 245 { << 177 G4SmartVoxelHeader* head; 246 PrepareParallelOptimisation(allOpts, verbo << 178 247 ++NumCallsBuildOptimisations; << 179 for (size_t n=0; n<Store->size(); n++) 248 } << 180 { 249 else << 181 if (verbose) timer.Start(); 250 { << 182 volume=(*Store)[n]; 251 BuildOptimisationsSequential(allOpts, verb << 183 // For safety, check if there are any existing voxels and 252 finishedOptimisation= true; << 184 // delete before replacement 253 } << 185 // 254 << 186 head = volume->GetVoxelHeader(); 255 return finishedOptimisation; << 187 delete head; 256 } << 188 volume->SetVoxelHeader(0); 257 << 189 if ( ( (volume->IsToOptimise()) 258 // ******************************************* << 190 && (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) ) 259 // Creates optimisation info. Builds all voxel << 191 || ( (volume->GetNoDaughters()==1) 260 // otherwise it builds voxels only for replica << 192 && (volume->GetDaughter(0)->IsReplicated()==true) 261 // << 193 && (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) ) 262 // This is the original sequential implementat << 194 { 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 195 #ifdef G4GEOMETRY_VOXELDEBUG 303 G4cout << "** G4GeometryManager::BuildOpti << 196 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 304 << " Examining logical volume nam << 197 << " Examining logical volume name = " 305 << "' #daughters= " << volume->Get << 198 << volume->GetName() << G4endl; 306 #endif 199 #endif 307 head = new G4SmartVoxelHeader(volume); << 200 head = new G4SmartVoxelHeader(volume); 308 << 201 if (head) 309 if (head != nullptr) << 202 { 310 { << 203 volume->SetVoxelHeader(head); 311 volume->SetVoxelHeader(head); << 204 } 312 } << 205 else 313 else << 206 { 314 { << 207 std::ostringstream message; 315 std::ostringstream message; << 208 message << "VoxelHeader allocation error." << G4endl 316 message << "VoxelHeader allocation err << 209 << "Allocation of new VoxelHeader" << G4endl 317 << "Allocation of new VoxelHea << 210 << " for volume " << volume->GetName() << " failed."; 318 << " for volume '" << v << 211 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003", 319 G4Exception("G4GeometryManager::BuildO << 212 FatalException, message); 320 FatalException, message); << 213 } 321 } << 214 if (verbose) 322 if (verbose) << 215 { 323 { << 216 timer.Stop(); 324 timer.Stop(); << 217 stats.push_back( G4SmartVoxelStat( volume, head, 325 stats.emplace_back( volume, head, << 218 timer.GetSystemElapsed(), 326 timer.GetSystemElap << 219 timer.GetUserElapsed() ) ); 327 timer.GetUserElapse << 220 } 328 } << 221 } 329 } << 222 else 330 else << 223 { 331 { << 224 // Don't create voxels for this node 332 // Don't create voxels for this node << 333 #ifdef G4GEOMETRY_VOXELDEBUG 225 #ifdef G4GEOMETRY_VOXELDEBUG 334 auto numDaughters = volume->GetNoDaughte << 226 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 335 G4cout << "- Skipping logical volume wit << 227 << " Skipping logical volume name = " << volume->GetName() 336 << " daughters and name = '" << v << 228 << 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 229 #endif 351 } << 230 } 352 } 231 } 353 if (verbose) 232 if (verbose) 354 { 233 { 355 allTimer.Stop(); << 234 allTimer.Stop(); 356 << 235 ReportVoxelStats( stats, allTimer.GetSystemElapsed() 357 ReportVoxelStats( stats, allTimer.GetSyste << 236 + 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 } << 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; << 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 } 237 } 726 assert ( fTotalNumberVolumesOptimised == fVo << 727 << 728 fParallelVoxelOptimisationFinished = true; << 729 // fParallelVoxelOptimisationRequested = fal << 730 fParallelVoxelOptimisationUnderway = false; << 731 } 238 } 732 239 733 // ******************************************* 240 // *************************************************************************** 734 // Creates Optimisation info for the specified << 241 // Creates optimisation info for the specified volumes subtree. 735 // ******************************************* 242 // *************************************************************************** 736 // 243 // 737 void G4GeometryManager::BuildOptimisations(G4b 244 void G4GeometryManager::BuildOptimisations(G4bool allOpts, 738 G4V 245 G4VPhysicalVolume* pVolume) 739 { 246 { 740 if (pVolume == nullptr) { return; } << 247 if (!pVolume) { return; } 741 248 742 // Retrieve the mother logical volume, if no << 249 // Retrieve the mother logical volume, if not NULL, 743 // otherwise apply global optimisation for t << 250 // otherwise apply global optimisation for the world volume 744 // << 251 // 745 G4LogicalVolume* tVolume = pVolume->GetMothe << 252 G4LogicalVolume* tVolume = pVolume->GetMotherLogical(); 746 if (tVolume == nullptr) << 253 if (!tVolume) { return BuildOptimisations(allOpts, false); } 747 { << 254 748 BuildOptimisations(allOpts, false); << 255 G4SmartVoxelHeader* head = tVolume->GetVoxelHeader(); 749 return; << 256 delete head; 750 } << 257 tVolume->SetVoxelHeader(0); 751 << 258 if ( ( (tVolume->IsToOptimise()) 752 G4SmartVoxelHeader* head = tVolume->GetVoxel << 259 && (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) ) 753 delete head; << 260 || ( (tVolume->GetNoDaughters()==1) 754 tVolume->SetVoxelHeader(nullptr); << 261 && (tVolume->GetDaughter(0)->IsReplicated()==true) ) ) 755 if ( ( (tVolume->IsToOptimise()) << 262 { 756 && (tVolume->GetNoDaughters()>=kMinVo << 263 head = new G4SmartVoxelHeader(tVolume); 757 || ( (tVolume->GetNoDaughters()==1) << 264 if (head) 758 && (tVolume->GetDaughter(0)->IsReplic << 265 { 759 { << 266 tVolume->SetVoxelHeader(head); 760 head = new G4SmartVoxelHeader(tVolume); << 267 } 761 if (head != nullptr) << 268 else 762 { << 269 { 763 tVolume->SetVoxelHeader(head); << 270 std::ostringstream message; 764 } << 271 message << "VoxelHeader allocation error." << G4endl 765 else << 272 << "Allocation of new VoxelHeader" << G4endl 766 { << 273 << " for volume " << tVolume->GetName() << " failed."; 767 std::ostringstream message; << 274 G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003", 768 message << "VoxelHeader allocation error << 275 FatalException, message); 769 << "Allocation of new VoxelHeade << 276 } 770 << " for volume " << tVol << 277 } 771 G4Exception("G4GeometryManager::BuildOpt << 278 else 772 FatalException, message); << 279 { 773 } << 280 // Don't create voxels for this node 774 } << 775 else << 776 { << 777 // Don't create voxels for this node << 778 #ifdef G4GEOMETRY_VOXELDEBUG 281 #ifdef G4GEOMETRY_VOXELDEBUG 779 G4cout << "** G4GeometryManager::BuildOpti << 282 G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl 780 << " Skipping logical volume na << 283 << " Skipping logical volume name = " << tVolume->GetName() 781 << G4endl; << 284 << G4endl; 782 #endif 285 #endif 783 } << 286 } 784 287 785 // Scan recursively the associated logical v << 288 // Scan recursively the associated logical volume tree 786 // << 289 // 787 tVolume = pVolume->GetLogicalVolume(); 290 tVolume = pVolume->GetLogicalVolume(); 788 if (tVolume->GetNoDaughters() != 0) << 291 if (tVolume->GetNoDaughters()) 789 { 292 { 790 BuildOptimisations(allOpts, tVolume->GetDa 293 BuildOptimisations(allOpts, tVolume->GetDaughter(0)); 791 } 294 } 792 } 295 } 793 296 794 // ******************************************* 297 // *************************************************************************** 795 // Removes all optimisation info. 298 // Removes all optimisation info. 796 // Loops over all logical volumes, deleting no << 299 // Loops over all logical volumes, deleting non-null voxels pointers, 797 // ******************************************* 300 // *************************************************************************** 798 // 301 // 799 void G4GeometryManager::DeleteOptimisations() 302 void G4GeometryManager::DeleteOptimisations() 800 { 303 { 801 G4LogicalVolume* tVolume = nullptr; << 304 G4LogicalVolume* tVolume = 0; 802 G4LogicalVolumeStore* Store = G4LogicalVolum 305 G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance(); 803 for (auto & n : *Store) << 306 for (size_t n=0; n<Store->size(); n++) 804 { 307 { 805 tVolume=n; << 308 tVolume=(*Store)[n]; 806 delete tVolume->GetVoxelHeader(); 309 delete tVolume->GetVoxelHeader(); 807 tVolume->SetVoxelHeader(nullptr); << 310 tVolume->SetVoxelHeader(0); 808 } 311 } 809 } 312 } 810 313 811 // ******************************************* 314 // *************************************************************************** 812 // Removes optimisation info for the specified 315 // Removes optimisation info for the specified subtree. 813 // Scans recursively all daughter volumes, del 316 // Scans recursively all daughter volumes, deleting non-null voxels pointers. 814 // ******************************************* 317 // *************************************************************************** 815 // 318 // 816 void G4GeometryManager::DeleteOptimisations(G4 319 void G4GeometryManager::DeleteOptimisations(G4VPhysicalVolume* pVolume) 817 { 320 { 818 if (pVolume == nullptr) { return; } << 321 if (!pVolume) { return; } 819 322 820 // Retrieve the mother logical volume, if no 323 // Retrieve the mother logical volume, if not NULL, 821 // otherwise global deletion to world volume 324 // otherwise global deletion to world volume. 822 // 325 // 823 G4LogicalVolume* tVolume = pVolume->GetMothe 326 G4LogicalVolume* tVolume = pVolume->GetMotherLogical(); 824 if (tVolume == nullptr) { return DeleteOptim << 327 if (!tVolume) { return DeleteOptimisations(); } 825 delete tVolume->GetVoxelHeader(); 328 delete tVolume->GetVoxelHeader(); 826 tVolume->SetVoxelHeader(nullptr); << 329 tVolume->SetVoxelHeader(0); 827 330 828 // Scan recursively the associated logical v 331 // Scan recursively the associated logical volume tree 829 // 332 // 830 tVolume = pVolume->GetLogicalVolume(); 333 tVolume = pVolume->GetLogicalVolume(); 831 if (tVolume->GetNoDaughters() != 0) << 334 if (tVolume->GetNoDaughters()) 832 { 335 { 833 DeleteOptimisations(tVolume->GetDaughter(0 336 DeleteOptimisations(tVolume->GetDaughter(0)); 834 } 337 } 835 } 338 } 836 339 837 // ******************************************* 340 // *************************************************************************** 838 // Sets the maximum extent of the world volume 341 // Sets the maximum extent of the world volume. The operation is allowed only 839 // if NO solids have been created already. 342 // if NO solids have been created already. 840 // ******************************************* 343 // *************************************************************************** 841 // 344 // 842 void G4GeometryManager::SetWorldMaximumExtent( 345 void G4GeometryManager::SetWorldMaximumExtent(G4double extent) 843 { 346 { 844 if (!G4SolidStore::GetInstance()->empty()) << 347 if (G4SolidStore::GetInstance()->size()) 845 { 348 { 846 // Sanity check to assure that extent is 349 // Sanity check to assure that extent is fixed BEFORE creating 847 // any geometry object (solids in this ca 350 // any geometry object (solids in this case) 848 // 351 // 849 G4Exception("G4GeometryManager::SetMaximu 352 G4Exception("G4GeometryManager::SetMaximumExtent()", 850 "GeomMgt0003", FatalException 353 "GeomMgt0003", FatalException, 851 "Extent can be set only BEFOR 354 "Extent can be set only BEFORE creating any geometry object!"); 852 } 355 } 853 G4GeometryTolerance::GetInstance()->SetSurfa 356 G4GeometryTolerance::GetInstance()->SetSurfaceTolerance(extent); 854 } 357 } 855 358 856 // ******************************************* 359 // *************************************************************************** 857 // Reports statistics on voxel optimisation wh 360 // Reports statistics on voxel optimisation when closing geometry. 858 // ******************************************* 361 // *************************************************************************** 859 // 362 // 860 void 363 void 861 G4GeometryManager::ReportVoxelStats( std::vect 364 G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats, 862 G4double << 365 G4double totalCpuTime ) 863 std::ostr << 864 { 366 { 865 os << "------------------------------------- << 367 G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics" 866 << G4endl; << 867 os << "G4GeometryManager::ReportVoxelStats - << 868 << G4endl << G4endl; 368 << G4endl << G4endl; 869 369 870 // 370 // 871 // Get total memory use 371 // Get total memory use 872 // 372 // 873 G4int i, nStat = (G4int)stats.size(); << 373 G4int i, nStat = stats.size(); 874 G4long totalMemory = 0; 374 G4long totalMemory = 0; 875 375 876 for( i=0; i<nStat; ++i ) { totalMemory += s << 376 for( i=0;i<nStat;++i ) { totalMemory += stats[i].GetMemoryUse(); } 877 377 878 os << " Total memory consumed for geometr << 378 G4cout << " Total memory consumed for geometry optimisation: " 879 << totalMemory/1024 << " kByte" << G4 379 << totalMemory/1024 << " kByte" << G4endl; 880 os << " Total CPU time elapsed for geomet << 380 G4cout << " Total CPU time elapsed for geometry optimisation: " 881 << std::setprecision(4) << totalCpuTi << 381 << std::setprecision(2) << totalCpuTime << " seconds" 882 << std::setprecision(6) << G4endl; 382 << std::setprecision(6) << G4endl; 883 383 884 // 384 // 885 // First list: sort by total CPU time 385 // First list: sort by total CPU time 886 // 386 // 887 std::sort( stats.begin(), stats.end(), << 387 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByCpu() ); 888 [](const G4SmartVoxelStat& a, const G4Smar << 889 { << 890 return a.GetTotalTime() > b.GetTotalTime() << 891 } ); << 892 388 893 const G4int maxPrint = 20; << 389 G4int nPrint = nStat > 10 ? 10 : nStat; 894 G4int nPrint = std::min ( nStat, maxPrint ); << 895 390 896 if (nPrint != 0) << 391 if (nPrint) 897 { 392 { 898 os << "\n Voxelisation: top CPU users:" << 393 G4cout << "\n Voxelisation: top CPU users:" << G4endl; 899 os << " Percent Total CPU System C << 394 G4cout << " Percent Total CPU System CPU Memory Volume\n" 900 << " ------- ---------- -------- << 395 << " ------- ---------- ---------- -------- ----------" 901 << G4endl; << 396 << G4endl; >> 397 // 12345678901.234567890123.234567890123.234567890123k . 902 } 398 } 903 399 904 for(i=0; i<nPrint; ++i) << 400 for(i=0;i<nPrint;++i) 905 { 401 { 906 G4double total = stats[i].GetTotalTime(); 402 G4double total = stats[i].GetTotalTime(); 907 G4double system = stats[i].GetSysTime(); 403 G4double system = stats[i].GetSysTime(); 908 G4double perc = 0.0; 404 G4double perc = 0.0; 909 405 910 if (system < 0) { system = 0.0; } 406 if (system < 0) { system = 0.0; } 911 if ((total < 0) || (totalCpuTime < perMill 407 if ((total < 0) || (totalCpuTime < perMillion)) 912 { total = 0; } 408 { total = 0; } 913 else 409 else 914 { perc = total*100/totalCpuTime; } 410 { perc = total*100/totalCpuTime; } 915 411 916 os << std::setprecision(2) << 412 G4cout << std::setprecision(2) 917 << std::setiosflags(std::ios::fixed 413 << std::setiosflags(std::ios::fixed|std::ios::right) 918 << std::setw(11) << perc 414 << std::setw(11) << perc 919 << std::setw(13) << total 415 << std::setw(13) << total 920 << std::setw(13) << system 416 << std::setw(13) << system 921 << std::setw(13) << (stats[i].GetMe 417 << std::setw(13) << (stats[i].GetMemoryUse()+512)/1024 922 << "k " << std::setiosflags(std::io 418 << "k " << std::setiosflags(std::ios::left) 923 << stats[i].GetVolume()->GetName() 419 << stats[i].GetVolume()->GetName() 924 << std::resetiosflags(std::ios::flo 420 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 925 << std::setprecision(6) 421 << std::setprecision(6) 926 << G4endl; 422 << G4endl; 927 } 423 } 928 424 929 // 425 // 930 // Second list: sort by memory use 426 // Second list: sort by memory use 931 // 427 // 932 std::sort( stats.begin(), stats.end(), << 428 std::sort( stats.begin(), stats.end(), G4SmartVoxelStat::ByMemory() ); 933 [](const G4SmartVoxelStat& a, const G4Smar << 934 { << 935 return a.GetMemoryUse() > b.GetMemoryUse() << 936 } ); << 937 429 938 if (nPrint != 0) << 430 if (nPrint) 939 { 431 { 940 os << "\n Voxelisation: top memory user << 432 G4cout << "\n Voxelisation: top memory users:" << G4endl; 941 os << " Percent Memory Heads << 433 G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n" 942 << " ------- -------- ------ << 434 << " ------- -------- ------ ------ -------- ---------- ----------" 943 << G4endl; << 435 << G4endl; >> 436 // 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. . 944 } 437 } 945 438 946 for(i=0; i<nPrint; ++i) << 439 for(i=0;i<nPrint;++i) 947 { 440 { 948 G4long memory = stats[i].GetMemoryUse(); 441 G4long memory = stats[i].GetMemoryUse(); 949 G4double totTime = stats[i].GetTotalTime() 442 G4double totTime = stats[i].GetTotalTime(); 950 if (totTime < 0) { totTime = 0.0; } 443 if (totTime < 0) { totTime = 0.0; } 951 444 952 os << std::setprecision(2) << 445 G4cout << std::setprecision(2) 953 << std::setiosflags(std::ios::fixed|std << 446 << std::setiosflags(std::ios::fixed|std::ios::right) 954 << std::setw(11) << G4double(memory*100 << 447 << std::setw(11) << G4double(memory*100)/G4double(totalMemory) 955 << std::setw(11) << memory/1024 << "k " << 448 << std::setw(11) << memory/1024 << "k " 956 << std::setw( 9) << stats[i].GetNumberH << 449 << std::setw( 9) << stats[i].GetNumberHeads() 957 << std::setw( 9) << stats[i].GetNumberN << 450 << std::setw( 9) << stats[i].GetNumberNodes() 958 << std::setw(11) << stats[i].GetNumberP << 451 << std::setw(11) << stats[i].GetNumberPointers() 959 << std::setw(13) << totTime << " " << 452 << std::setw(13) << totTime << " " 960 << std::setiosflags(std::ios::left) << 453 << std::setiosflags(std::ios::left) 961 << stats[i].GetVolume()->GetName() << 454 << stats[i].GetVolume()->GetName() 962 << std::resetiosflags(std::ios::floatfi << 455 << std::resetiosflags(std::ios::floatfield|std::ios::adjustfield) 963 << std::setprecision(6) << 456 << std::setprecision(6) 964 << G4endl; << 457 << G4endl; 965 } 458 } 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 } 459 } 987 460