Geant4 Cross Reference |
1 // 1 2 // ******************************************* 3 // * License and Disclaimer 4 // * 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 // 26 // ------------------------------------------- 27 // GEANT 4 class implementation file 28 // 29 // ---------------- G4Fancy3DNucleus ---- 30 // by Gunter Folger, May 1998. 31 // class for a 3D nucleus, arranging nuc 32 // ------------------------------------------- 33 // 20110805 M. Kelsey -- Remove C-style array 34 // make vector a container of objects. Mov 35 // to .hh. Move testSums, places, momentum 36 // class data members for reuse. 37 38 #include <algorithm> 39 40 #include "G4Fancy3DNucleus.hh" 41 #include "G4Fancy3DNucleusHelper.hh" 42 #include "G4NuclearFermiDensity.hh" 43 #include "G4NuclearShellModelDensity.hh" 44 #include "G4NucleiProperties.hh" 45 #include "G4HyperNucleiProperties.hh" 46 #include "G4Nucleon.hh" 47 #include "G4SystemOfUnits.hh" 48 #include "Randomize.hh" 49 #include "G4ios.hh" 50 #include "G4Pow.hh" 51 #include "G4HadronicException.hh" 52 53 #include "Randomize.hh" 54 #include "G4ThreeVector.hh" 55 #include "G4RandomDirection.hh" 56 #include "G4LorentzRotation.hh" 57 #include "G4RotationMatrix.hh" 58 #include "G4PhysicalConstants.hh" 59 60 G4Fancy3DNucleus::G4Fancy3DNucleus() 61 : myA(0), myZ(0), myL(0), theNucleons(250), 62 nucleondistance(0.8*fermi),excitationEnerg 63 places(250), momentum(250), fermiM(250), t 64 { 65 } 66 67 G4Fancy3DNucleus::~G4Fancy3DNucleus() 68 { 69 if(theDensity) delete theDensity; 70 } 71 72 #if defined(NON_INTEGER_A_Z) 73 void G4Fancy3DNucleus::Init(G4double theA, G4d 74 { 75 G4int intZ = G4int(theZ); 76 G4int intA= ( G4UniformRand()>theA-G4int(the 77 // forward to integer Init() 78 Init(intA, intZ, std::max(numberOfLambdas, 0 79 80 } 81 #endif 82 83 void G4Fancy3DNucleus::Init(G4int theA, G4int 84 { 85 currentNucleon=-1; 86 theNucleons.clear(); 87 nucleondistance = 0.8*fermi; 88 places.clear(); 89 momentum.clear(); 90 fermiM.clear(); 91 testSums.clear(); 92 93 myZ = theZ; 94 myA = theA; 95 myL = std::max(numberOfLambdas, 0); // Cann 96 excitationEnergy=0; 97 98 theNucleons.resize(myA); // Pre-loads vecto 99 100 // For simplicity, we neglect eventual Lambd 101 // density of nucler levels and the Fermi le 102 103 if(theDensity) delete theDensity; 104 if ( myA < 17 ) { 105 theDensity = new G4NuclearShellModelDensi 106 if( myA == 12 ) nucleondistance=0.9*fermi 107 } else { 108 theDensity = new G4NuclearFermiDensity(my 109 } 110 111 theFermi.Init(myA, myZ); 112 113 ChooseNucleons(); 114 115 ChoosePositions(); 116 117 if( myA == 12 ) CenterNucleons(); // This 118 119 ChooseFermiMomenta(); 120 121 G4double Ebinding= BindingEnergy()/myA; 122 123 for (G4int aNucleon=0; aNucleon < myA; aNucl 124 { 125 theNucleons[aNucleon].SetBindingEnergy(Ebind 126 } 127 128 return; 129 } 130 131 G4bool G4Fancy3DNucleus::StartLoop() 132 { 133 currentNucleon=0; 134 return (theNucleons.size()>0); 135 } 136 137 // Returns by pointer; null pointer indicates 138 G4Nucleon * G4Fancy3DNucleus::GetNextNucleon() 139 { 140 return ( (currentNucleon>=0 && currentNucleo 141 &theNucleons[currentNucleon++] : 0 ); 142 } 143 144 const std::vector<G4Nucleon> & G4Fancy3DNucleu 145 { 146 return theNucleons; 147 } 148 149 150 // Class-scope function to sort nucleons by Z 151 bool G4Fancy3DNucleusHelperForSortInZ(const G4 152 { 153 return nuc1.GetPosition().z() < nuc2.GetPosi 154 } 155 156 void G4Fancy3DNucleus::SortNucleonsIncZ() 157 { 158 if (theNucleons.size() < 2 ) return; // A 159 160 std::sort(theNucleons.begin(), theNucleons.e 161 G4Fancy3DNucleusHelperForSortInZ); 162 } 163 164 void G4Fancy3DNucleus::SortNucleonsDecZ() 165 { 166 if (theNucleons.size() < 2 ) return; // A 167 SortNucleonsIncZ(); 168 169 std::reverse(theNucleons.begin(), theNucleon 170 } 171 172 173 G4double G4Fancy3DNucleus::BindingEnergy() 174 { 175 return G4NucleiProperties::GetBindingEnergy( 176 } 177 178 179 G4double G4Fancy3DNucleus::GetNuclearRadius() 180 { 181 return GetNuclearRadius(0.5); 182 } 183 184 G4double G4Fancy3DNucleus::GetNuclearRadius(co 185 { 186 return theDensity->GetRadius(maxRelativeDens 187 } 188 189 G4double G4Fancy3DNucleus::GetOuterRadius() 190 { 191 G4double maxradius2=0; 192 193 for (int i=0; i<myA; i++) 194 { 195 if ( theNucleons[i].GetPosition().mag2() 196 { 197 maxradius2=theNucleons[i].GetPosition(). 198 } 199 } 200 return std::sqrt(maxradius2)+nucleondistance 201 } 202 203 G4double G4Fancy3DNucleus::GetMass() 204 { 205 if ( myL <= 0 ) return myZ*G4Proton::Proton( 206 (myA-myZ)*G4Neutron:: 207 BindingEnergy(); 208 else return G4HyperNucleiProperti 209 } 210 211 212 213 void G4Fancy3DNucleus::DoLorentzBoost(const G4 214 { 215 for (G4int i=0; i<myA; i++){ 216 theNucleons[i].Boost(theBoost); 217 } 218 } 219 220 void G4Fancy3DNucleus::DoLorentzBoost(const G4 221 { 222 for (G4int i=0; i<myA; i++){ 223 theNucleons[i].Boost(theBeta); 224 } 225 } 226 227 void G4Fancy3DNucleus::DoLorentzContraction(co 228 { 229 G4double beta2=theBeta.mag2(); 230 if (beta2 > 0) { 231 G4double factor=(1-std::sqrt(1-beta2))/be 232 G4ThreeVector rprime; 233 for (G4int i=0; i< myA; i++) { 234 rprime = theNucleons[i].GetPosition() - 235 factor * (theBeta*theNucleons[i].GetP 236 theNucleons[i].SetPosition(rprime); 237 } 238 } 239 } 240 241 void G4Fancy3DNucleus::DoLorentzContraction(co 242 { 243 if (theBoost.e() !=0 ) { 244 G4ThreeVector beta = theBoost.vect()/theB 245 DoLorentzContraction(beta); 246 } 247 } 248 249 250 251 void G4Fancy3DNucleus::CenterNucleons() 252 { 253 G4ThreeVector center; 254 255 for (G4int i=0; i<myA; i++ ) 256 { 257 center+=theNucleons[i].GetPosition(); 258 } 259 center /= -myA; 260 DoTranslation(center); 261 } 262 263 void G4Fancy3DNucleus::DoTranslation(const G4T 264 { 265 G4ThreeVector tempV; 266 for (G4int i=0; i<myA; i++ ) 267 { 268 tempV = theNucleons[i].GetPosition() + t 269 theNucleons[i].SetPosition(tempV); 270 } 271 } 272 273 const G4VNuclearDensity * G4Fancy3DNucleus::Ge 274 { 275 return theDensity; 276 } 277 278 //----------------------- private Implementati 279 280 void G4Fancy3DNucleus::ChooseNucleons() 281 { 282 G4int protons=0, nucleons=0, lambdas=0; 283 G4double probProton = ( G4double(myZ) )/( G4 284 G4double probLambda = myL > 0 ? ( G4double(m 285 while ( nucleons < myA ) { /* Loop checking 286 G4double rnd = G4UniformRand(); 287 if ( rnd < probProton ) { 288 if ( protons < myZ ) { 289 protons++; 290 theNucleons[nucleons++].SetParticleType(G4Pr 291 } 292 } else if ( rnd < probProton + probLambda 293 if ( lambdas < myL ) { 294 lambdas++; 295 theNucleons[nucleons++].SetParticleType(G4La 296 } 297 } else { 298 if ( (nucleons - protons - lambdas) < (m 299 theNucleons[nucleons++].SetParticleType(G4Ne 300 } 301 } 302 } 303 return; 304 } 305 306 void G4Fancy3DNucleus::ChoosePositions() 307 { 308 if( myA != 12) { 309 310 G4int i=0; 311 G4ThreeVector aPos, delta; 312 G4bool freeplace; 313 const G4double nd2=sqr(nucleondistance); 314 G4double maxR=GetNuclearRadius(0.001); / 315 // rel 316 G4int jr=0; 317 G4int jx,jy; 318 G4double arand[600]; 319 G4double *prand=arand; 320 places.clear(); // Reset data buffer 321 G4int interationsLeft=1000*myA; 322 while ( (i < myA) && (--interationsLeft>0) 323 { 324 do 325 { 326 if ( jr < 3 ) 327 { 328 jr=std::min(600,9*(myA - i)); 329 G4RandFlat::shootArray(jr,prand); 330 //CLHEP::RandFlat::shootArray(jr, prand ); 331 } 332 jx=--jr; 333 jy=--jr; 334 aPos.set((2*arand[jx]-1.), (2*arand[jy]-1.), 335 } while (aPos.mag2() > 1. ); /* Loop ch 336 aPos *=maxR; 337 G4double density=theDensity->GetRelative 338 if (G4UniformRand() < density) 339 { 340 freeplace= true; 341 std::vector<G4ThreeVector>::iterator iplace; 342 for( iplace=places.begin(); iplace!=places.e 343 { 344 delta = *iplace - aPos; 345 freeplace= delta.mag2() > nd2; 346 } 347 if ( freeplace ) { 348 G4double pFermi=theFermi.GetFermiMom 349 // protons must at least have bindin 350 // assuming the Fermi energy corres 351 // that the Fermi Energy > CoulombB 352 if (theNucleons[i].GetDefinition() == G4Pr 353 { 354 G4double nucMass = theNucleons[i]. 355 G4double eFermi= std::sqrt( sqr(pF 356 if (eFermi <= CoulombBarrier() ) freepla 357 } 358 } 359 if ( freeplace ) { 360 theNucleons[i].SetPosition(aPos); 361 places.push_back(aPos); 362 ++i; 363 } 364 } 365 } 366 if (interationsLeft<=0) { 367 G4Exception("model/util/G4Fancy3DNucleus 368 "Problem to place nucleons") 369 } 370 371 } else { 372 // Start insertion 373 // Alpha cluster structure of carbon nucle 374 // P. Bozek, W. Broniowski, E.R. Arr 375 // Phys. Rev. C90, 064902 ( 376 const G4double Lbase=3.05*fermi; 377 const G4double Disp=0.552; // 0.91^ 378 const G4double nd2=sqr(nucleondistance); 379 const G4ThreeVector Corner1=G4ThreeVector( 380 const G4ThreeVector Corner2=G4ThreeVector( 381 const G4ThreeVector Corner3=G4ThreeVector( 382 G4ThreeVector R1; 383 R1=G4ThreeVector(G4RandGauss::shoot(0.,Dis 384 theNucleons[0].SetPosition(R1); // First n 385 G4int loopCounterLeft = 10000; 386 for(G4int ii=1; ii<4; ii++) // 2 - 4 n 387 { 388 G4bool Continue; 389 do 390 { 391 R1=G4ThreeVector(G4RandGauss::shoot(0. 392 theNucleons[ii].SetPosition(R1); 393 Continue=false; 394 for(G4int jj=0; jj < ii; jj++) 395 { 396 if( (theNucleons[ii].GetPosition() - 397 } 398 } while( Continue && --loopCounterLeft > 399 } 400 if ( loopCounterLeft <= 0 ) { 401 G4Exception("model/util/G4Fancy3DNucleus 402 "Unable to find a good posit 403 } 404 loopCounterLeft = 10000; 405 for(G4int ii=4; ii<8; ii++) // 5 - 8 n 406 { 407 G4bool Continue; 408 do 409 { 410 R1=G4ThreeVector(G4RandGauss::shoot(0. 411 theNucleons[ii].SetPosition(R1); 412 Continue=false; 413 for(G4int jj=0; jj < ii; jj++) 414 { 415 if( (theNucleons[ii].GetPosition() - 416 } 417 } while( Continue && --loopCounterLeft > 418 } 419 if ( loopCounterLeft <= 0 ) { 420 G4Exception("model/util/G4Fancy3DNucleus 421 "Unable to find a good posit 422 } 423 loopCounterLeft = 10000; 424 for(G4int ii=8; ii<12; ii++) // 9 - 12 425 { 426 G4bool Continue; 427 do 428 { 429 R1=G4ThreeVector(G4RandGauss::shoot(0. 430 theNucleons[ii].SetPosition(R1); 431 Continue=false; 432 for(G4int jj=0; jj < ii; jj++) 433 { 434 if( (theNucleons[ii].GetPosition() - 435 } 436 } while( Continue && --loopCounterLeft > 437 } 438 if ( loopCounterLeft <= 0 ) { 439 G4Exception("model/util/G4Fancy3DNucleus 440 "Unable to find a good posit 441 } 442 G4LorentzRotation RandomRotation; 443 RandomRotation.rotateZ(2.*pi*G4UniformRand 444 RandomRotation.rotateY(std::acos(2.*G4Unif 445 // Randomly rotation of the created nucleu 446 G4LorentzVector Pos; 447 for(G4int ii=0; ii<myA; ii++ ) 448 { 449 Pos=G4LorentzVector(theNucleons[ii].GetP 450 G4ThreeVector NewPos = Pos.vect(); 451 theNucleons[ii].SetPosition(NewPos); 452 } 453 454 } 455 } 456 457 void G4Fancy3DNucleus::ChooseFermiMomenta() 458 { 459 G4int i; 460 G4double density; 461 462 // Pre-allocate buffers for filling by ind 463 momentum.resize(myA, G4ThreeVector(0.,0.,0 464 fermiM.resize(myA, 0.*GeV); 465 466 for (G4int ntry=0; ntry<1 ; ntry ++ ) 467 { 468 for (i=0; i < myA; i++ ) // momenta for a 469 { 470 density = theDensity->GetDensity(theNucle 471 fermiM[i] = theFermi.GetFermiMomentum(den 472 G4ThreeVector mom=theFermi.GetMomentum(de 473 if (theNucleons[i].GetDefinition() == G4P 474 { 475 G4double eMax = std::sqrt(sqr(fermiM[i 476 - CoulombBarrier(); 477 if ( eMax > theNucleons[i].GetDefiniti 478 { 479 G4double pmax2= sqr(eMax) - sqr(th 480 fermiM[i] = std::sqrt(pmax2); 481 while ( mom.mag2() > pmax2 ) /* Loop ch 482 { 483 mom=theFermi.GetMomentum(density, fe 484 } 485 } else 486 { 487 //AR-21Dec2017 : emit a "Jus 488 //G4cerr << "G4Fancy3DNucleus: dif 489 G4ExceptionDescription ed; 490 ed << "Nucleus Z A " << my 491 ed << "proton with eMax=" << 492 G4Exception( "G4Fancy3DNucle 493 "HAD_FANCY3DNUC 494 mom=G4ThreeVector(0,0,0); 495 } 496 497 } 498 momentum[i]= mom; 499 } 500 501 if ( ReduceSum() ) break; 502 // G4cout <<" G4FancyNucleus: iterating 503 } 504 505 // G4ThreeVector sum; 506 // for (G4int index=0; index<myA;sum+=mome 507 // ; 508 // G4cout << "final sum / mag() " << sum < 509 510 G4double energy; 511 for ( i=0; i< myA ; i++ ) 512 { 513 energy = theNucleons[i].GetParticleType 514 - BindingEnergy()/myA; 515 G4LorentzVector tempV(momentum[i],energ 516 theNucleons[i].SetMomentum(tempV); 517 // GF 11-05-2011: set BindingEnergy to 518 //theNucleons[i].SetBindingEnergy( 519 // 0.5*sqr(fermiM[i])/theNucleons[i 520 } 521 } 522 523 524 G4bool G4Fancy3DNucleus::ReduceSum() 525 { 526 G4ThreeVector sum; 527 G4double PFermi=fermiM[myA-1]; 528 529 for (G4int i=0; i < myA-1 ; i++ ) 530 { sum+=momentum[i]; } 531 532 // check if have to do anything at all.. 533 if ( sum.mag() <= PFermi ) 534 { 535 momentum[myA-1]=-sum; 536 return true; 537 } 538 539 // find all possible changes in momentum, chan 540 G4ThreeVector testDir=sum.unit(); 541 testSums.clear(); 542 testSums.resize(myA-1); // Allocate block 543 544 G4ThreeVector delta; 545 for (G4int aNucleon=0; aNucleon < myA-1; ++a 546 delta = 2.*((momentum[aNucleon]*testDir)*t 547 548 testSums[aNucleon].Fill(delta, delta.mag() 549 } 550 551 std::sort(testSums.begin(), testSums.end()); 552 553 // reduce Momentum Sum until the next would 554 G4int index=(G4int)testSums.size(); 555 while ( (sum-testSums[--index].Vector).mag() 556 { 557 // Only take one which improve, ie. don't 558 if ( sum.mag() > (sum-testSums[index].Vect 559 momentum[testSums[index].Index]-=testSum 560 sum-=testSums[index].Vector; 561 } 562 } 563 564 if ( (sum-testSums[index].Vector).mag() <= P 565 { 566 G4int best=-1; 567 G4double pBest=2*PFermi; // anything large 568 for ( G4int aNucleon=0; aNucleon<=index; a 569 { 570 // find the momentum closest to choosen 571 G4double pTry=(testSums[aNucleon].Vector 572 if ( pTry < PFermi 573 && std::abs(momentum[myA-1].mag() - pT 574 { 575 pBest=std::abs(momentum[myA-1].mag() 576 best=aNucleon; 577 } 578 } 579 if ( best < 0 ) 580 { 581 const G4String& text = "G4Fancy3DNucleus 582 throw G4HadronicException(__FILE 583 } 584 momentum[testSums[best].Index]-=testSums[b 585 momentum[myA-1]=testSums[best].Vector-sum; 586 587 return true; 588 589 } 590 591 // try to compensate momentum using another 592 G4int swapit=-1; 593 while (swapit<myA-1) /* Loop checking, 30-O 594 { 595 if ( fermiM[++swapit] > PFermi ) break; 596 } 597 if (swapit == myA-1 ) return false; 598 599 // Now we have a nucleon with a bigger Fermi 600 // Exchange with last nucleon.. and iterate. 601 std::swap(theNucleons[swapit], theNucleons[m 602 std::swap(momentum[swapit], momentum[myA-1]) 603 std::swap(fermiM[swapit], fermiM[myA-1]); 604 return ReduceSum(); 605 } 606 607 G4double G4Fancy3DNucleus::CoulombBarrier() 608 { 609 static const G4double cfactor = (1.44/1.14) 610 return cfactor*myZ/(1.0 + G4Pow::GetInstance 611 } 612