Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // G4ParticleTable class implementation 27 // 28 // Authors: G.Cosmo, 2 December 1995 - Design, based on object model 29 // H.Kurashige, 27 June 1996 - First implementation 30 // History: 31 // - 14 Nov 1997, H.Kurashige - Added messenger 32 // - 24 Sep 1998, H.Kurashige - Added dictionary for encoding 33 // - 28 Oct 1999, H.Kurashige - Migration to STL maps 34 // - 15 Sep 2017, K.L.Genser - Added support for MuonicAtom 35 // -------------------------------------------------------------------- 36 37 #include "G4ParticleTable.hh" 38 39 #include "G4IonTable.hh" 40 #include "G4ParticleMessenger.hh" 41 #include "G4StateManager.hh" 42 #include "G4UImessenger.hh" 43 #include "G4ios.hh" 44 #include "globals.hh" 45 46 // These fields should be thread local or thread private. For a singleton 47 // class, we can change any member field as static without any problem 48 // because there is only one instance. Then we are allowed to add 49 // "G4ThreadLocal" 50 // 51 G4ThreadLocal G4ParticleTable::G4PTblDictionary* G4ParticleTable::fDictionary = nullptr; 52 G4ThreadLocal G4ParticleTable::G4PTblDicIterator* G4ParticleTable::fIterator = nullptr; 53 G4ThreadLocal G4ParticleTable::G4PTblEncodingDictionary* G4ParticleTable::fEncodingDictionary = 54 nullptr; 55 56 // These shadow pointers are used by each worker thread to copy the content 57 // from the master thread 58 // 59 G4ParticleTable::G4PTblDictionary* G4ParticleTable::fDictionaryShadow = nullptr; 60 G4ParticleTable::G4PTblDicIterator* G4ParticleTable::fIteratorShadow = nullptr; 61 G4ParticleTable::G4PTblEncodingDictionary* G4ParticleTable::fEncodingDictionaryShadow = nullptr; 62 63 // Static class variable: pointer to single instance of class 64 // 65 G4ParticleTable* G4ParticleTable::fgParticleTable = nullptr; 66 67 #ifdef G4MULTITHREADED 68 // Lock for particle table accesses. 69 // 70 G4Mutex& G4ParticleTable::particleTableMutex() 71 { 72 static G4Mutex _instance = G4MUTEX_INITIALIZER; 73 return _instance; 74 } 75 G4int& G4ParticleTable::lockCount() 76 { 77 static G4int _instance = 0; 78 return _instance; 79 } 80 #endif 81 82 G4ParticleTable* G4ParticleTable::GetParticleTable() 83 { 84 if (fgParticleTable == nullptr) { 85 static G4ParticleTable theParticleTable; 86 fgParticleTable = &theParticleTable; 87 } 88 89 // Here we initialize all thread private data members. 90 // 91 if (fDictionary == nullptr) fgParticleTable->WorkerG4ParticleTable(); 92 93 return fgParticleTable; 94 } 95 96 G4ParticleTable::G4ParticleTable() 97 { 98 fDictionary = new G4PTblDictionary(); 99 100 // Set up the shadow pointer used by worker threads 101 // 102 if (fDictionaryShadow == nullptr) { 103 fDictionaryShadow = fDictionary; 104 } 105 106 fIterator = new G4PTblDicIterator(*fDictionary); 107 108 // Set up the shadow pointer used by worker threads 109 // 110 if (fIteratorShadow == nullptr) { 111 fIteratorShadow = fIterator; 112 } 113 114 fEncodingDictionary = new G4PTblEncodingDictionary(); 115 // Set up the shadow pointer used by worker threads 116 // 117 if (fEncodingDictionaryShadow == nullptr) { 118 fEncodingDictionaryShadow = fEncodingDictionary; 119 } 120 121 // Ion Table 122 // 123 fIonTable = new G4IonTable(); 124 fParticleMessenger = nullptr; 125 } 126 127 // This method is similar to the constructor. It is used by each worker 128 // thread to achieve the partial effect as that of the master thread. 129 // Here we initialize all thread private data members 130 void G4ParticleTable::WorkerG4ParticleTable() 131 { 132 // The iterator for the shadow particle table is not sharable. 133 // 134 #ifdef G4MULTITHREADED 135 G4MUTEXLOCK(&G4ParticleTable::particleTableMutex()); 136 G4ParticleTable::lockCount()++; 137 #endif 138 if (fDictionary == nullptr) { 139 fDictionary = new G4PTblDictionary(); 140 } 141 else { 142 fDictionary->clear(); 143 } 144 145 if (fEncodingDictionary == nullptr) { 146 fEncodingDictionary = new G4PTblEncodingDictionary(); 147 } 148 else { 149 fEncodingDictionary->clear(); 150 } 151 152 fIteratorShadow->reset(false); 153 while ((*fIteratorShadow)()) // Loop checking, 09.08.2015, K.Kurashige 154 { 155 G4ParticleDefinition* particle = fIteratorShadow->value(); 156 fDictionary->insert(std::pair<G4String, G4ParticleDefinition*>(GetKey(particle), particle)); 157 G4int code = particle->GetPDGEncoding(); 158 if (code != 0) { 159 fEncodingDictionary->insert(std::pair<G4int, G4ParticleDefinition*>(code, particle)); 160 } 161 } 162 fIterator = new G4PTblDicIterator(*fDictionary); 163 164 #ifdef G4MULTITHREADED 165 G4MUTEXUNLOCK(&G4ParticleTable::particleTableMutex()); 166 #endif 167 168 fIonTable->WorkerG4IonTable(); 169 } 170 171 G4ParticleTable::~G4ParticleTable() 172 { 173 readyToUse = false; 174 175 // remove all items from G4ParticleTable 176 RemoveAllParticles(); 177 178 // delete Ion Table 179 delete fIonTable; 180 fIonTable = nullptr; 181 182 // delete dictionary for encoding 183 if (fEncodingDictionary != nullptr) { 184 fEncodingDictionary->clear(); 185 delete fEncodingDictionary; 186 fEncodingDictionary = nullptr; 187 } 188 189 if (fDictionary != nullptr) { 190 delete fIterator; 191 fIterator = nullptr; 192 193 fDictionary->clear(); 194 delete fDictionary; 195 fDictionary = nullptr; 196 } 197 198 delete fParticleMessenger; 199 fParticleMessenger = nullptr; 200 201 fgParticleTable = nullptr; 202 203 G4ParticleDefinition::Clean(); // Delete sub-instance static data 204 } 205 206 void G4ParticleTable::DestroyWorkerG4ParticleTable() 207 { 208 // delete Ion Table in worker thread 209 if (fIonTable != nullptr) fIonTable->DestroyWorkerG4IonTable(); 210 211 // delete dictionary for encoding 212 if (fEncodingDictionary != nullptr) { 213 fEncodingDictionary->clear(); 214 delete fEncodingDictionary; 215 fEncodingDictionary = nullptr; 216 } 217 218 if (fDictionary != nullptr) { 219 delete fIterator; 220 fIterator = nullptr; 221 222 fDictionary->clear(); 223 delete fDictionary; 224 fDictionary = nullptr; 225 } 226 } 227 228 G4UImessenger* G4ParticleTable::CreateMessenger() 229 { 230 if (fParticleMessenger == nullptr) { 231 // UI messenger 232 fParticleMessenger = new G4ParticleMessenger(this); 233 } 234 return fParticleMessenger; 235 } 236 237 void G4ParticleTable::DeleteAllParticles() 238 { 239 // set readyToUse false 240 readyToUse = false; 241 242 #ifdef G4VERBOSE 243 if (verboseLevel > 1) { 244 G4cout << "G4ParticleTable::DeleteAllParticles() " << G4endl; 245 } 246 #endif 247 248 // delete all particles 249 G4PTblDicIterator* piter = fIterator; 250 piter->reset(false); 251 while ((*piter)()) // Loop checking, 09.08.2015, K.Kurashige 252 { 253 #ifdef G4VERBOSE 254 if (verboseLevel > 2) { 255 G4cout << "Delete " << (piter->value())->GetParticleName() << " " << (piter->value()) 256 << G4endl; 257 } 258 #endif 259 delete (piter->value()); 260 } 261 RemoveAllParticles(); 262 } 263 264 void G4ParticleTable::RemoveAllParticles() 265 { 266 if (readyToUse) { 267 G4Exception("G4ParticleTable::RemoveAllParticle()", "PART115", JustWarning, 268 "No effects because readyToUse is true."); 269 return; 270 } 271 272 #ifdef G4VERBOSE 273 if (verboseLevel > 1) { 274 G4cout << "G4ParticleTable::RemoveAllParticles() " << G4endl; 275 } 276 #endif 277 278 // remove all contents in Ion Table 279 if (fIonTable != nullptr) { 280 fIonTable->clear(); 281 } 282 283 // clear dictionary 284 if (fDictionary != nullptr) { 285 fDictionary->clear(); 286 } 287 } 288 289 G4ParticleDefinition* G4ParticleTable::Insert(G4ParticleDefinition* particle) 290 { 291 // check particle name 292 if ((particle == nullptr) || (GetKey(particle).empty())) { 293 G4Exception("G4ParticleTable::Insert()", "PART121", FatalException, 294 "Particle witnout name can not be registered."); 295 #ifdef G4VERBOSE 296 if (verboseLevel > 1) { 297 G4cout << "The particle[Addr:" << particle << "] has no name " << G4endl; 298 } 299 #endif 300 return nullptr; 301 } 302 303 if (contains(particle)) { 304 #ifdef G4VERBOSE 305 if (verboseLevel > 2) { 306 FindParticle(particle)->DumpTable(); 307 } 308 #endif 309 G4String msg = "The particle "; 310 msg += particle->GetParticleName(); 311 msg += " has already been registered in the Particle Table "; 312 G4Exception("G4ParticleTable::Insert()", "PART122", FatalException, msg); 313 314 return particle; 315 } 316 317 G4PTblDictionary* pdic = fDictionaryShadow; 318 319 // insert into Dictionary 320 pdic->insert(std::pair<G4String, G4ParticleDefinition*>(GetKey(particle), particle)); 321 #ifdef G4MULTITHREADED 322 if (G4Threading::IsWorkerThread()) { 323 fDictionary->insert(std::pair<G4String, G4ParticleDefinition*>(GetKey(particle), particle)); 324 } 325 #endif 326 327 G4PTblEncodingDictionary* pedic = fEncodingDictionaryShadow; 328 329 // insert into EncodingDictionary 330 G4int code = particle->GetPDGEncoding(); 331 if (code != 0) { 332 pedic->insert(std::pair<G4int, G4ParticleDefinition*>(code, particle)); 333 #ifdef G4MULTITHREADED 334 if (G4Threading::IsWorkerThread()) { 335 fEncodingDictionary->insert(std::pair<G4int, G4ParticleDefinition*>(code, particle)); 336 } 337 #endif 338 } 339 340 // insert it in IonTable if "nucleus" 341 if (fIonTable->IsIon(particle)) { 342 fIonTable->Insert(particle); 343 } 344 345 // set Verbose Level same as ParticleTable 346 particle->SetVerboseLevel(verboseLevel); 347 348 #ifdef G4VERBOSE 349 if (verboseLevel > 3) { 350 G4cout << "The particle " << particle->GetParticleName() << " is inserted in the ParticleTable " 351 << G4endl; 352 } 353 #endif 354 return particle; 355 } 356 357 G4ParticleDefinition* G4ParticleTable::Remove(G4ParticleDefinition* particle) 358 { 359 if (particle == nullptr) return nullptr; 360 #ifdef G4MULTITHREADED 361 if (G4Threading::IsWorkerThread()) { 362 G4ExceptionDescription ed; 363 ed << "Request of removing " << particle->GetParticleName() 364 << " is ignored as it is invoked from a worker thread."; 365 G4Exception("G4ParticleTable::Remove()", "PART10117", JustWarning, ed); 366 return nullptr; 367 } 368 #endif 369 if (readyToUse) { 370 G4StateManager* pStateManager = G4StateManager::GetStateManager(); 371 G4ApplicationState currentState = pStateManager->GetCurrentState(); 372 if (currentState != G4State_PreInit) { 373 G4String msg = "Request of removing "; 374 msg += particle->GetParticleName(); 375 msg += " has No effects other than Pre_Init"; 376 G4Exception("G4ParticleTable::Remove()", "PART117", JustWarning, msg); 377 return nullptr; 378 } 379 380 #ifdef G4VERBOSE 381 if (verboseLevel > 0) { 382 G4cout << particle->GetParticleName() << " will be removed from the ParticleTable " << G4endl; 383 } 384 #endif 385 } 386 387 auto it = fDictionaryShadow->find(GetKey(particle)); 388 if (it != fDictionaryShadow->end()) { 389 fDictionaryShadow->erase(it); 390 // remove from EncodingDictionary 391 G4int code = particle->GetPDGEncoding(); 392 if (code != 0) { 393 fEncodingDictionaryShadow->erase(fEncodingDictionaryShadow->find(code)); 394 } 395 } 396 else { 397 return nullptr; 398 } 399 400 // remove it from IonTable if "nucleus" 401 if (fIonTable->IsIon(particle)) { 402 fIonTable->Remove(particle); 403 } 404 405 #ifdef G4VERBOSE 406 if (verboseLevel > 3) { 407 G4cout << "The particle " << particle->GetParticleName() 408 << " is removed from the ParticleTable " << G4endl; 409 } 410 #endif 411 412 return particle; 413 } 414 415 G4ParticleDefinition* G4ParticleTable::GetParticle(G4int index) const 416 { 417 CheckReadiness(); 418 if ((index >= 0) && (index < entries())) { 419 G4PTblDicIterator* piter = fIterator; 420 piter->reset(false); 421 G4int counter = 0; 422 while ((*piter)()) // Loop checking, 09.08.2015, K.Kurashige 423 { 424 if (counter == index) return piter->value(); 425 ++counter; 426 } 427 } 428 #ifdef G4VERBOSE 429 if (verboseLevel > 1) { 430 G4cout << " G4ParticleTable::GetParticle" 431 << " invalid index (=" << index << ")" << G4endl; 432 } 433 #endif 434 return nullptr; 435 } 436 437 const G4String& G4ParticleTable::GetParticleName(G4int index) const 438 { 439 G4ParticleDefinition* aParticle = GetParticle(index); 440 if (aParticle != nullptr) { 441 return aParticle->GetParticleName(); 442 } 443 444 return noName; 445 } 446 447 G4ParticleDefinition* G4ParticleTable::FindParticle(const G4String& particle_name) 448 { 449 auto it = fDictionary->find(particle_name); 450 if (it != fDictionary->end()) { 451 return (*it).second; 452 } 453 454 #ifdef G4MULTITHREADED 455 G4ParticleDefinition* ptcl = nullptr; 456 if (G4Threading::IsWorkerThread()) { 457 G4MUTEXLOCK(&G4ParticleTable::particleTableMutex()); 458 auto its = fDictionaryShadow->find(particle_name); 459 if (its != fDictionaryShadow->end()) { 460 fDictionary->insert(*its); 461 ptcl = (*its).second; 462 G4int code = ptcl->GetPDGEncoding(); 463 if (code != 0) 464 fEncodingDictionary->insert(std::pair<G4int, G4ParticleDefinition*>(code, ptcl)); 465 } 466 G4MUTEXUNLOCK(&G4ParticleTable::particleTableMutex()); 467 } 468 return ptcl; 469 #else 470 return nullptr; 471 #endif 472 } 473 474 void G4ParticleTable::SelectParticle(const G4String& name) 475 { 476 if (name != selectedName) { 477 const G4ParticleDefinition* part = FindParticle(name); 478 if (part != nullptr) { 479 #ifdef G4MULTITHREADED 480 G4MUTEXLOCK(&G4ParticleTable::particleTableMutex()); 481 #endif 482 selectedParticle = part; 483 selectedName = name; 484 #ifdef G4MULTITHREADED 485 G4MUTEXUNLOCK(&G4ParticleTable::particleTableMutex()); 486 #endif 487 } 488 } 489 } 490 491 G4ParticleDefinition* G4ParticleTable::FindParticle(const G4ParticleDefinition* particle) 492 { 493 CheckReadiness(); 494 G4String key = GetKey(particle); 495 return FindParticle(key); 496 } 497 498 G4ParticleDefinition* G4ParticleTable::FindParticle(G4int aPDGEncoding) 499 { 500 CheckReadiness(); 501 // check aPDGEncoding is valid 502 if (aPDGEncoding == 0) { 503 #ifdef G4VERBOSE 504 if (verboseLevel > 1) { 505 G4cout << "PDGEncoding [" << aPDGEncoding << "] is not valid " << G4endl; 506 } 507 #endif 508 return nullptr; 509 } 510 511 G4PTblEncodingDictionary* pedic = fEncodingDictionary; 512 G4ParticleDefinition* particle = nullptr; 513 514 if (pedic != nullptr) { 515 auto it = pedic->find(aPDGEncoding); 516 if (it != pedic->end()) { 517 particle = (*it).second; 518 } 519 } 520 521 #ifdef G4MULTITHREADED 522 if (particle == nullptr && G4Threading::IsWorkerThread()) { 523 G4MUTEXLOCK(&G4ParticleTable::particleTableMutex()); 524 auto its = fEncodingDictionaryShadow->find(aPDGEncoding); 525 if (its != fEncodingDictionaryShadow->end()) { 526 particle = (*its).second; 527 fEncodingDictionary->insert(*its); 528 G4String key = GetKey(particle); 529 fDictionary->insert(std::pair<G4String, G4ParticleDefinition*>(key, particle)); 530 } 531 G4MUTEXUNLOCK(&G4ParticleTable::particleTableMutex()); 532 } 533 #endif 534 535 #ifdef G4VERBOSE 536 if ((particle == nullptr) && (verboseLevel > 1)) { 537 G4cout << "CODE:" << aPDGEncoding << " does not exist in ParticleTable " << G4endl; 538 } 539 #endif 540 return particle; 541 } 542 543 void G4ParticleTable::DumpTable(const G4String& particle_name) 544 { 545 CheckReadiness(); 546 if ((particle_name == "ALL") || (particle_name == "all")) { 547 // dump all particles 548 G4PTblDicIterator* piter = fIterator; 549 piter->reset(); 550 while ((*piter)()) // Loop checking, 09.08.2015, K.Kurashige 551 { 552 (piter->value())->DumpTable(); 553 } 554 } 555 else { 556 // dump only particle with name of particle_name 557 G4ParticleDefinition* ptr = FindParticle(particle_name); 558 if (ptr != nullptr) { 559 ptr->DumpTable(); 560 } 561 else { 562 #ifdef G4VERBOSE 563 if (verboseLevel > 1) { 564 G4cout << " G4ParticleTable::DumpTable : " << particle_name 565 << " does not exist in ParticleTable " << G4endl; 566 } 567 #endif 568 } 569 } 570 } 571 572 void G4ParticleTable::CheckReadiness() const 573 { 574 if (!readyToUse) { 575 G4String msg; 576 msg = "Illegal use of G4ParticleTable :\n"; 577 msg += "Access to G4ParticleTable for finding a particle or equivalent\n"; 578 msg += "operation occurs before G4VUserPhysicsList is instantiated and\n"; 579 msg += "assigned to G4RunManager. Such an access is prohibited since\n"; 580 msg += "Geant4 version 8.0. To fix this problem, please make sure that\n"; 581 msg += "your main() instantiates G4VUserPhysicsList and set it to\n"; 582 msg += "G4RunManager before instantiating other user classes such as\n"; 583 msg += "G4VUserPrimaryParticleGeneratorAction."; 584 G4Exception("G4ParticleTable::CheckReadiness()", "PART002", FatalException, msg); 585 } 586 } 587 588 G4IonTable* G4ParticleTable::GetIonTable() const 589 { 590 return fIonTable; 591 } 592 593 const G4ParticleTable::G4PTblDictionary* G4ParticleTable::GetDictionary() const 594 { 595 return fDictionary; 596 } 597 598 G4ParticleTable::G4PTblDicIterator* G4ParticleTable::GetIterator() const 599 { 600 return fIterator; 601 } 602 603 const G4ParticleTable::G4PTblEncodingDictionary* G4ParticleTable::GetEncodingDictionary() const 604 { 605 return fEncodingDictionary; 606 } 607 608 G4bool G4ParticleTable::contains(const G4String& particle_name) const 609 { 610 auto it = fDictionaryShadow->find(particle_name); 611 return (it != fDictionaryShadow->cend()); 612 } 613 614 G4int G4ParticleTable::entries() const 615 { 616 return (G4int)fDictionary->size(); 617 } 618 619 G4int G4ParticleTable::size() const 620 { 621 return (G4int)fDictionary->size(); 622 } 623