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 // << 26 // G4GeometryWorkspace - implementation << 27 // 25 // 28 // Authors: John Apostolakis (CERN), Andrea Do << 29 // ------------------------------------------- << 30 26 31 #include "G4GeometryWorkspace.hh" 27 #include "G4GeometryWorkspace.hh" >> 28 >> 29 #include "G4PVReplica.hh" >> 30 #include "G4PVParameterised.hh" >> 31 #include "G4VPVParameterisation.hh" 32 #include "G4PhysicalVolumeStore.hh" 32 #include "G4PhysicalVolumeStore.hh" 33 #include "G4AutoLock.hh" << 33 #include "G4VSolid.hh" 34 34 35 namespace << 35 #include "G4LogicalVolume.hh" 36 { << 36 #include "G4VPhysicalVolume.hh" 37 G4Mutex mutex_init = G4MUTEX_INITIALIZER; << 37 #include "G4PVReplica.hh" 38 G4GeometryWorkspace::pool_type thePool; << 38 #include "G4Region.hh" 39 } << 39 >> 40 #include "G4AutoLock.hh" 40 41 41 // ------------------------------------------- << 42 // << 43 G4GeometryWorkspace::pool_type* G4GeometryWork << 44 { << 45 return &thePool; << 46 } << 47 42 48 // ------------------------------------------- << 49 // << 50 G4GeometryWorkspace::G4GeometryWorkspace() 43 G4GeometryWorkspace::G4GeometryWorkspace() >> 44 : fVerbose(false) 51 { 45 { 52 fpLogicalVolumeSIM= 46 fpLogicalVolumeSIM= 53 &const_cast<G4LVManager&>(G4LogicalVolum 47 &const_cast<G4LVManager&>(G4LogicalVolume::GetSubInstanceManager()); 54 fpPhysicalVolumeSIM= 48 fpPhysicalVolumeSIM= 55 &const_cast<G4PVManager&>( G4VPhysicalVo 49 &const_cast<G4PVManager&>( G4VPhysicalVolume::GetSubInstanceManager() ); 56 fpReplicaSIM= 50 fpReplicaSIM= 57 &const_cast<G4PVRManager&>(G4PVReplica:: 51 &const_cast<G4PVRManager&>(G4PVReplica::GetSubInstanceManager()); 58 fpRegionSIM= 52 fpRegionSIM= 59 &const_cast<G4RegionManager&>(G4Region:: 53 &const_cast<G4RegionManager&>(G4Region::GetSubInstanceManager()); 60 54 61 // Create a work area for Logical Volumes in << 55 // Create a work area for Logical Volumes in this thread - then capture its address 62 // then capture its address << 63 // << 64 InitialiseWorkspace(); 56 InitialiseWorkspace(); 65 57 66 fLogicalVolumeOffset = fpLogicalVolumeSIM->G << 58 fLogicalVolumeOffset= fpLogicalVolumeSIM->GetOffset(); 67 59 68 fPhysicalVolumeOffset = fpPhysicalVolumeSIM- << 60 fPhysicalVolumeOffset= fpPhysicalVolumeSIM->GetOffset(); 69 61 70 fReplicaOffset = fpReplicaSIM->GetOffset(); << 62 fReplicaOffset= fpReplicaSIM->GetOffset(); 71 63 72 fRegionOffset = fpRegionSIM->GetOffset(); << 64 fRegionOffset= fpRegionSIM->GetOffset(); 73 } 65 } 74 66 75 // ------------------------------------------- << 67 G4GeometryWorkspace::~G4GeometryWorkspace() 76 // << 68 { >> 69 >> 70 } >> 71 >> 72 // Static methods >> 73 // For with current (original) G4WorkerThread -- which uses static methods >> 74 77 void 75 void 78 G4GeometryWorkspace::UseWorkspace() 76 G4GeometryWorkspace::UseWorkspace() 79 { 77 { 80 // Geometry related, split classes mechanism << 78 if( fVerbose ) 81 // for this thread << 79 G4cout << "G4GeometryWorkspace::UseWorkspace: Start " << G4endl; 82 // << 80 >> 81 // Implementation copied from G4WorkerThread::BuildGeometryAndPhysicsVector() >> 82 // and improved for G4PVParamaterised >> 83 // John Apostolakis, May 30, 2013 >> 84 >> 85 //Geometry related, split classes mechanism: instantiate sub-instance for this thread 83 fpLogicalVolumeSIM->UseWorkArea(fLogicalVolu 86 fpLogicalVolumeSIM->UseWorkArea(fLogicalVolumeOffset); 84 fpPhysicalVolumeSIM->UseWorkArea(fPhysicalVo 87 fpPhysicalVolumeSIM->UseWorkArea(fPhysicalVolumeOffset); 85 88 86 fpReplicaSIM->UseWorkArea(fReplicaOffset); 89 fpReplicaSIM->UseWorkArea(fReplicaOffset); 87 fpRegionSIM->UseWorkArea(fRegionOffset); 90 fpRegionSIM->UseWorkArea(fRegionOffset); 88 91 89 // When recycling a workspace 92 // When recycling a workspace 90 // - it must be a lightweight operation, t 93 // - it must be a lightweight operation, to reuse a valid work area 91 // - so it must NOT Initialise anything! 94 // - so it must NOT Initialise anything! 92 // Do not call InitialisePhysicalVolumes(); 95 // Do not call InitialisePhysicalVolumes(); >> 96 >> 97 if( fVerbose ) >> 98 G4cout << "G4GeometryWorkspace::UseWorkspace: End " << G4endl; 93 } 99 } 94 100 95 // ------------------------------------------- << 101 96 // << 97 void G4GeometryWorkspace::ReleaseWorkspace() 102 void G4GeometryWorkspace::ReleaseWorkspace() >> 103 // The opposite of Use Workspace - let go of it. 98 { 104 { 99 fpLogicalVolumeSIM->UseWorkArea(nullptr); << 105 fpLogicalVolumeSIM->UseWorkArea(0); 100 fpPhysicalVolumeSIM->UseWorkArea(nullptr); << 106 fpPhysicalVolumeSIM->UseWorkArea(0); 101 107 102 fpReplicaSIM->UseWorkArea(nullptr); << 108 fpReplicaSIM->UseWorkArea(0); 103 fpRegionSIM->UseWorkArea(nullptr); << 109 fpRegionSIM->UseWorkArea(0); 104 } 110 } 105 111 106 // ------------------------------------------- << 112 namespace { 107 // << 113 G4Mutex solidclone= G4MUTEX_INITIALIZER; >> 114 } 108 void G4GeometryWorkspace::InitialisePhysicalVo 115 void G4GeometryWorkspace::InitialisePhysicalVolumes() 109 { << 110 G4PhysicalVolumeStore* physVolStore = G4Phys << 111 for (auto physVol : *physVolStore) << 112 { 116 { 113 G4LogicalVolume *logicalVol = physVol->Get << 117 G4PhysicalVolumeStore* physVolStore = G4PhysicalVolumeStore::GetInstance(); 114 << 118 for (size_t ip=0; ip<physVolStore->size(); ip++) 115 // Use shadow pointer << 116 // << 117 G4VSolid* solid = logicalVol->GetMasterSol << 118 auto g4PVReplica = dynamic_cast<G4PVReplic << 119 if (g4PVReplica == nullptr) << 120 { 119 { 121 // Placement volume << 120 G4VPhysicalVolume* physVol = (*physVolStore)[ip]; 122 // << 121 G4LogicalVolume *logicalVol = physVol->GetLogicalVolume(); 123 logicalVol->InitialiseWorker(logicalVol, << 122 //use shadow pointer >> 123 G4VSolid *solid = logicalVol->GetMasterSolid(); >> 124 G4PVReplica *g4PVReplica = 0; >> 125 g4PVReplica = dynamic_cast<G4PVReplica*>(physVol); >> 126 if (!g4PVReplica) >> 127 { >> 128 // Placement volume >> 129 logicalVol->InitialiseWorker(logicalVol,solid,0); >> 130 } >> 131 else >> 132 { >> 133 //g4PVReplica->SlaveG4PVReplica(g4PVReplica); >> 134 g4PVReplica->InitialiseWorker(g4PVReplica); >> 135 if( ! g4PVReplica->IsParameterised() ) >> 136 { >> 137 logicalVol->InitialiseWorker(logicalVol,solid,0); >> 138 // If the replica's solid (in LV) is changed during navigation, it must be thread-private >> 139 CloneReplicaSolid( g4PVReplica ); >> 140 } >> 141 else >> 142 { >> 143 G4PVParameterised *paramVol >> 144 = dynamic_cast<G4PVParameterised*>(physVol); >> 145 if (!paramVol) >> 146 { >> 147 G4Exception("G4GeometryWorkspace::CreateAndUseWorkspace", "Runtime Error PV01", >> 148 FatalException, >> 149 "Cannot find Parameterisation for G4PVParameterised object."); >> 150 } >> 151 CloneParameterisedSolids( paramVol ); >> 152 } >> 153 } 124 } 154 } 125 else << 155 if( fVerbose ) 126 { << 156 G4cout << "G4GeometryWorkspace::InitialisePhysicalVolumes: " 127 g4PVReplica->InitialiseWorker(g4PVReplic << 157 << "Copying geometry - Done!" << G4endl; 128 logicalVol->InitialiseWorker(logicalVol, << 129 << 130 // If the replica's solid (in LV) is cha << 131 // it must be thread-private << 132 // << 133 CloneReplicaSolid( g4PVReplica ); << 134 } << 135 } << 136 } 158 } 137 159 138 // ------------------------------------------- << 160 139 // Create a clone of the solid for this replic << 161 G4bool G4GeometryWorkspace::CloneReplicaSolid( G4PVReplica *replicaPV ) 140 // << 141 G4bool G4GeometryWorkspace::CloneReplicaSolid( << 142 { 162 { 143 G4LogicalVolume* logicalV = replicaPV->GetLo << 163 // Create a clone of the solid for this replica in this thread 144 G4VSolid* solid = logicalV->GetSolid(); << 164 >> 165 // Check that it is not a parameterisation ? 145 166 146 G4AutoLock aLock(&mutex_init); << 167 // The solid Ptr is in the Logical Volume 147 G4VSolid* workerSolid = solid->Clone(); << 168 G4LogicalVolume *logicalV= replicaPV ->GetLogicalVolume(); >> 169 G4VSolid *solid= logicalV->GetSolid(); >> 170 >> 171 G4AutoLock aLock(&solidclone); >> 172 G4VSolid *workerSolid = solid->Clone(); 148 aLock.unlock(); 173 aLock.unlock(); 149 174 150 if( workerSolid != nullptr ) << 175 if( workerSolid ) >> 176 { >> 177 logicalV->InitialiseWorker(logicalV,workerSolid,0); >> 178 }else{ >> 179 // In the case that not all solids support(ed) the Clone() >> 180 // method, we do similar thing here to dynamically cast >> 181 // and then get the clone method. >> 182 G4ExceptionDescription ed; >> 183 ed << " ERROR: Unable to initialise geometry for worker node." << G4endl; >> 184 ed << " A solid lacks the Clone() method - or Clone() failed." << G4endl; >> 185 ed << " Type of solid: " << solid->GetEntityType() << G4endl; >> 186 ed << " Parameters: " << *solid << G4endl; >> 187 G4Exception(" G4GeometryWorkspace::CloneParameterisedVolume", "MT-BuildGeometry001", >> 188 FatalException, ed); >> 189 return false; >> 190 } >> 191 return true; // It Worked >> 192 } >> 193 >> 194 G4bool G4GeometryWorkspace::CloneParameterisedSolids( G4PVParameterised *paramVol ) >> 195 { >> 196 // Each G4PVParameterised instance, has associated with it at least one >> 197 // solid for each worker thread. >> 198 // *Simple* Parameterisations have a single type of solid, and the >> 199 // pointer points to the same instance of a solid during the simulation. >> 200 // For this case, it is possible to adapt automatically to >> 201 // multi-threading, simply by cloning the solid - so long >> 202 // as all solids support the Clone() method. >> 203 >> 204 // Check whether it is a simple parameterisation or not >> 205 G4VPVParameterisation *param= paramVol->GetParameterisation(); >> 206 unsigned int numCopies= paramVol->GetMultiplicity(); >> 207 unsigned int numDifferent= 0; >> 208 >> 209 G4LogicalVolume *logicalV= paramVol->GetLogicalVolume(); >> 210 // assert( logicalV != 0); >> 211 G4VSolid *solid= logicalV->GetSolid(); >> 212 >> 213 for( unsigned int i=0; i< numCopies; i++) >> 214 { >> 215 G4VSolid *solidChk= param->ComputeSolid(i, paramVol); >> 216 if( solidChk != solid) >> 217 { >> 218 numDifferent++; >> 219 } >> 220 } >> 221 if( numDifferent>0 ) 151 { 222 { 152 logicalV->InitialiseWorker(logicalV,worker << 223 G4ExceptionDescription ed; >> 224 >> 225 ed << " Parameterisation is implemented using several instances of Solids " >> 226 << " - potentially to support different types of solids. " << G4endl; >> 227 ed << " The current implementation of Geant4-MT does not support " >> 228 << " this type of Parameterisation" << G4endl; >> 229 G4Exception("G4GeometryWorkspace::CloneParameterisedVolume", "GeometryNotSupportedInMT-01", >> 230 FatalException, ed); 153 } 231 } 154 else << 232 >> 233 // Threads may attempt to clone a solids simultaneously. Those cloned solids will be >> 234 // registered into a shared solid store (C++ container). Need a lock to >> 235 // guarantee thread safety >> 236 G4AutoLock aLock(&solidclone); >> 237 G4VSolid *workerSolid = solid->Clone(); >> 238 aLock.unlock(); >> 239 if( workerSolid ) 155 { 240 { >> 241 logicalV->InitialiseWorker(logicalV,workerSolid,0); >> 242 }else{ 156 // In the case that not all solids support 243 // In the case that not all solids support(ed) the Clone() 157 // method, we do similar thing here to dyn 244 // method, we do similar thing here to dynamically cast 158 // and then get the clone method << 245 // and then get the clone method. 159 // << 160 G4ExceptionDescription ed; 246 G4ExceptionDescription ed; 161 ed << "ERROR - Unable to initialise geomet << 247 ed << " ERROR: Unable to initialise geometry for worker node." << G4endl; 162 << "A solid lacks the Clone() method - << 248 ed << " A solid lacks the Clone() method - or Clone() failed." << G4endl; 163 << " Type of solid: " << solid->GetEn << 249 ed << " Type of solid: " << solid->GetEntityType() << G4endl; 164 << " Parameters: " << *solid; << 250 ed << " Parameters: " << *solid << G4endl; 165 G4Exception("G4GeometryWorkspace::CloneRep << 251 G4Exception(" G4GeometryWorkspace::CloneParameterisedVolume", "MT-BuildGeometry001", 166 "GeomVol0003", FatalException, << 252 FatalException, ed); 167 return false; << 168 } 253 } 169 return true; // It Worked 254 return true; // It Worked 170 } 255 } 171 256 172 // ------------------------------------------- << 257 173 // << 258 void 174 void G4GeometryWorkspace::InitialiseWorkspace( << 259 G4GeometryWorkspace::InitialiseWorkspace() 175 { 260 { 176 // Geometry related, split classes mechanism << 261 if( fVerbose ) 177 // Do *NOT* instantiate sub-instance for thi << 262 G4cout << "G4GeometryWorkspace::InitialiseWorkspace: Copying geometry - Start " << G4endl; 178 // << 263 >> 264 // Implementation copied from G4WorkerThread::BuildGeometryAndPhysicsVector() >> 265 // and improved for G4PVParamaterised >> 266 // John Apostolakis, May 30, 2013 >> 267 >> 268 //Geometry related, split classes mechanism: >> 269 // Do *NOT* instantiate sub-instance for this thread, >> 270 // just copy the contents !! 179 fpLogicalVolumeSIM->SlaveCopySubInstanceArra 271 fpLogicalVolumeSIM->SlaveCopySubInstanceArray(); 180 fpPhysicalVolumeSIM->SlaveCopySubInstanceArr 272 fpPhysicalVolumeSIM->SlaveCopySubInstanceArray(); 181 fpReplicaSIM->SlaveCopySubInstanceArray(); 273 fpReplicaSIM->SlaveCopySubInstanceArray(); 182 fpRegionSIM->SlaveInitializeSubInstance(); 274 fpRegionSIM->SlaveInitializeSubInstance(); 183 275 184 InitialisePhysicalVolumes(); 276 InitialisePhysicalVolumes(); >> 277 >> 278 if( fVerbose ) >> 279 G4cout << "G4GeometryWorkspace::InitialiseWorkspace: " >> 280 << "Copying geometry - Done!" << G4endl; 185 } 281 } 186 282 187 // ------------------------------------------- << 188 // << 189 void G4GeometryWorkspace::DestroyWorkspace() 283 void G4GeometryWorkspace::DestroyWorkspace() 190 { 284 { 191 G4PhysicalVolumeStore* physVolStore = G4Phys 285 G4PhysicalVolumeStore* physVolStore = G4PhysicalVolumeStore::GetInstance(); 192 for (auto physVol : *physVolStore) << 286 for (size_t ip=0; ip<physVolStore->size(); ip++) 193 { 287 { 194 G4LogicalVolume* logicalVol = physVol->Get << 288 G4VPhysicalVolume* physVol = (*physVolStore)[ip]; 195 auto g4PVReplica = dynamic_cast<G4PVReplic << 289 G4LogicalVolume *logicalVol = physVol->GetLogicalVolume(); 196 if (g4PVReplica != nullptr) << 290 G4PVReplica *g4PVReplica = 0; >> 291 g4PVReplica = dynamic_cast<G4PVReplica*>(physVol); >> 292 if (g4PVReplica) 197 { 293 { 198 g4PVReplica->TerminateWorker(g4PVReplica 294 g4PVReplica->TerminateWorker(g4PVReplica); >> 295 G4PVParameterised *paramVol = 0; >> 296 paramVol = dynamic_cast<G4PVParameterised*>(physVol); >> 297 if (paramVol) >> 298 { >> 299 // G4VSolid *solid = logicalVol->fSolid; >> 300 logicalVol->TerminateWorker(logicalVol); >> 301 // if( solid->IsClone() ) delete solid; >> 302 } >> 303 else >> 304 { >> 305 logicalVol->TerminateWorker(logicalVol); >> 306 } >> 307 } >> 308 else >> 309 { >> 310 logicalVol->TerminateWorker(logicalVol); 199 } 311 } 200 logicalVol->TerminateWorker(logicalVol); << 201 } 312 } 202 << 313 203 // Threads may attempt to free memory simult << 204 // Need a lock to guarantee thread safety << 205 // << 206 G4AutoLock aLock(&mutex_init); << 207 fpLogicalVolumeSIM->FreeSlave(); 314 fpLogicalVolumeSIM->FreeSlave(); 208 fpPhysicalVolumeSIM->FreeSlave(); 315 fpPhysicalVolumeSIM->FreeSlave(); 209 fpReplicaSIM->FreeSlave(); 316 fpReplicaSIM->FreeSlave(); 210 fpRegionSIM->FreeSlave(); 317 fpRegionSIM->FreeSlave(); 211 aLock.unlock(); << 212 } 318 } 213 319