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 // 27 // 28 // Physics model class G4NuclNuclDiffuseElastic 29 // 30 // 31 // G4 Model: optical diffuse elastic scattering with 4-momentum balance 32 // 33 // 24-May-07 V. Grichine 34 // 35 36 #include "G4NuclNuclDiffuseElastic.hh" 37 #include "G4ParticleTable.hh" 38 #include "G4ParticleDefinition.hh" 39 #include "G4IonTable.hh" 40 #include "G4NucleiProperties.hh" 41 42 #include "Randomize.hh" 43 #include "G4Integrator.hh" 44 #include "globals.hh" 45 #include "G4PhysicalConstants.hh" 46 #include "G4SystemOfUnits.hh" 47 48 #include "G4Proton.hh" 49 #include "G4Neutron.hh" 50 #include "G4Deuteron.hh" 51 #include "G4Alpha.hh" 52 #include "G4PionPlus.hh" 53 #include "G4PionMinus.hh" 54 55 #include "G4Element.hh" 56 #include "G4ElementTable.hh" 57 #include "G4NistManager.hh" 58 #include "G4PhysicsTable.hh" 59 #include "G4PhysicsLogVector.hh" 60 #include "G4PhysicsFreeVector.hh" 61 #include "G4HadronicParameters.hh" 62 63 ///////////////////////////////////////////////////////////////////////// 64 // 65 // Test Constructor. Just to check xsc 66 67 68 G4NuclNuclDiffuseElastic::G4NuclNuclDiffuseElastic() 69 : G4HadronElastic("NNDiffuseElastic"), fParticle(0) 70 { 71 SetMinEnergy( 50*MeV ); 72 SetMaxEnergy( G4HadronicParameters::Instance()->GetMaxEnergy() ); 73 verboseLevel = 0; 74 lowEnergyRecoilLimit = 100.*keV; 75 lowEnergyLimitQ = 0.0*GeV; 76 lowEnergyLimitHE = 0.0*GeV; 77 lowestEnergyLimit= 0.0*keV; 78 plabLowLimit = 20.0*MeV; 79 80 theProton = G4Proton::Proton(); 81 theNeutron = G4Neutron::Neutron(); 82 theDeuteron = G4Deuteron::Deuteron(); 83 theAlpha = G4Alpha::Alpha(); 84 thePionPlus = G4PionPlus::PionPlus(); 85 thePionMinus= G4PionMinus::PionMinus(); 86 87 fEnergyBin = 300; // Increased from the original 200 to have no wider log-energy-bins up to 10 PeV 88 fAngleBin = 200; 89 90 fEnergyVector = new G4PhysicsLogVector( theMinEnergy, theMaxEnergy, fEnergyBin ); 91 fAngleTable = 0; 92 93 fParticle = 0; 94 fWaveVector = 0.; 95 fAtomicWeight = 0.; 96 fAtomicNumber = 0.; 97 fNuclearRadius = 0.; 98 fBeta = 0.; 99 fZommerfeld = 0.; 100 fAm = 0.; 101 fAddCoulomb = false; 102 // Ranges of angle table relative to current Rutherford (Coulomb grazing) angle 103 104 // Empirical parameters 105 106 fCofAlphaMax = 1.5; 107 fCofAlphaCoulomb = 0.5; 108 109 fProfileDelta = 1.; 110 fProfileAlpha = 0.5; 111 112 fCofLambda = 1.0; 113 fCofDelta = 0.04; 114 fCofAlpha = 0.095; 115 116 fNuclearRadius1 = fNuclearRadius2 = fNuclearRadiusSquare 117 = fRutherfordRatio = fCoulombPhase0 = fHalfRutThetaTg = fHalfRutThetaTg2 118 = fRutherfordTheta = fProfileLambda = fCofPhase = fCofFar 119 = fSumSigma = fEtaRatio = fReZ = 0.0; 120 fMaxL = 0; 121 122 fNuclearRadiusCof = 1.0; 123 fCoulombMuC = 0.0; 124 } 125 126 ////////////////////////////////////////////////////////////////////////////// 127 // 128 // Destructor 129 130 G4NuclNuclDiffuseElastic::~G4NuclNuclDiffuseElastic() 131 { 132 if ( fEnergyVector ) { 133 delete fEnergyVector; 134 fEnergyVector = 0; 135 } 136 137 for ( std::vector<G4PhysicsTable*>::iterator it = fAngleBank.begin(); 138 it != fAngleBank.end(); ++it ) { 139 if ( (*it) ) (*it)->clearAndDestroy(); 140 delete *it; 141 *it = 0; 142 } 143 fAngleTable = 0; 144 } 145 146 ////////////////////////////////////////////////////////////////////////////// 147 // 148 // Initialisation for given particle using element table of application 149 150 void G4NuclNuclDiffuseElastic::Initialise() 151 { 152 153 // fEnergyVector = new G4PhysicsLogVector( theMinEnergy, theMaxEnergy, fEnergyBin ); 154 155 const G4ElementTable* theElementTable = G4Element::GetElementTable(); 156 std::size_t jEl, numOfEl = G4Element::GetNumberOfElements(); 157 158 // projectile radius 159 160 G4double A1 = G4double( fParticle->GetBaryonNumber() ); 161 G4double R1 = CalculateNuclearRad(A1); 162 163 for(jEl = 0 ; jEl < numOfEl; ++jEl) // application element loop 164 { 165 fAtomicNumber = (*theElementTable)[jEl]->GetZ(); // atomic number 166 fAtomicWeight = G4NistManager::Instance()->GetAtomicMassAmu( static_cast< G4int >( fAtomicNumber ) ); 167 168 fNuclearRadius = CalculateNuclearRad(fAtomicWeight); 169 fNuclearRadius += R1; 170 171 if(verboseLevel > 0) 172 { 173 G4cout<<"G4NuclNuclDiffuseElastic::Initialise() the element: " 174 <<(*theElementTable)[jEl]->GetName()<<G4endl; 175 } 176 fElementNumberVector.push_back(fAtomicNumber); 177 fElementNameVector.push_back((*theElementTable)[jEl]->GetName()); 178 179 BuildAngleTable(); 180 fAngleBank.push_back(fAngleTable); 181 } 182 } 183 184 185 //////////////////////////////////////////////////////////////////////////// 186 // 187 // return differential elastic cross section d(sigma)/d(omega) 188 189 G4double 190 G4NuclNuclDiffuseElastic::GetDiffuseElasticXsc( const G4ParticleDefinition* particle, 191 G4double theta, 192 G4double momentum, 193 G4double A ) 194 { 195 fParticle = particle; 196 fWaveVector = momentum/hbarc; 197 fAtomicWeight = A; 198 fAddCoulomb = false; 199 fNuclearRadius = CalculateNuclearRad(A); 200 201 G4double sigma = fNuclearRadius*fNuclearRadius*GetDiffElasticProb(theta); 202 203 return sigma; 204 } 205 206 //////////////////////////////////////////////////////////////////////////// 207 // 208 // return invariant differential elastic cross section d(sigma)/d(tMand) 209 210 G4double 211 G4NuclNuclDiffuseElastic::GetInvElasticXsc( const G4ParticleDefinition* particle, 212 G4double tMand, 213 G4double plab, 214 G4double A, G4double Z ) 215 { 216 G4double m1 = particle->GetPDGMass(); 217 G4LorentzVector lv1(0.,0.,plab,std::sqrt(plab*plab+m1*m1)); 218 219 G4int iZ = static_cast<G4int>(Z+0.5); 220 G4int iA = static_cast<G4int>(A+0.5); 221 G4ParticleDefinition * theDef = 0; 222 223 if (iZ == 1 && iA == 1) theDef = theProton; 224 else if (iZ == 1 && iA == 2) theDef = theDeuteron; 225 else if (iZ == 1 && iA == 3) theDef = G4Triton::Triton(); 226 else if (iZ == 2 && iA == 3) theDef = G4He3::He3(); 227 else if (iZ == 2 && iA == 4) theDef = theAlpha; 228 else theDef = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(iZ,iA,0); 229 230 G4double tmass = theDef->GetPDGMass(); 231 232 G4LorentzVector lv(0.0,0.0,0.0,tmass); 233 lv += lv1; 234 235 G4ThreeVector bst = lv.boostVector(); 236 lv1.boost(-bst); 237 238 G4ThreeVector p1 = lv1.vect(); 239 G4double ptot = p1.mag(); 240 G4double ptot2 = ptot*ptot; 241 G4double cost = 1 - 0.5*std::fabs(tMand)/ptot2; 242 243 if( cost >= 1.0 ) cost = 1.0; 244 else if( cost <= -1.0) cost = -1.0; 245 246 G4double thetaCMS = std::acos(cost); 247 248 G4double sigma = GetDiffuseElasticXsc( particle, thetaCMS, ptot, A); 249 250 sigma *= pi/ptot2; 251 252 return sigma; 253 } 254 255 //////////////////////////////////////////////////////////////////////////// 256 // 257 // return differential elastic cross section d(sigma)/d(omega) with Coulomb 258 // correction 259 260 G4double 261 G4NuclNuclDiffuseElastic::GetDiffuseElasticSumXsc( const G4ParticleDefinition* particle, 262 G4double theta, 263 G4double momentum, 264 G4double A, G4double Z ) 265 { 266 fParticle = particle; 267 fWaveVector = momentum/hbarc; 268 fAtomicWeight = A; 269 fAtomicNumber = Z; 270 fNuclearRadius = CalculateNuclearRad(A); 271 fAddCoulomb = false; 272 273 G4double z = particle->GetPDGCharge(); 274 275 G4double kRt = fWaveVector*fNuclearRadius*theta; 276 G4double kRtC = 1.9; 277 278 if( z && (kRt > kRtC) ) 279 { 280 fAddCoulomb = true; 281 fBeta = CalculateParticleBeta( particle, momentum); 282 fZommerfeld = CalculateZommerfeld( fBeta, z, fAtomicNumber); 283 fAm = CalculateAm( momentum, fZommerfeld, fAtomicNumber); 284 } 285 G4double sigma = fNuclearRadius*fNuclearRadius*GetDiffElasticSumProb(theta); 286 287 return sigma; 288 } 289 290 //////////////////////////////////////////////////////////////////////////// 291 // 292 // return invariant differential elastic cross section d(sigma)/d(tMand) with Coulomb 293 // correction 294 295 G4double 296 G4NuclNuclDiffuseElastic::GetInvElasticSumXsc( const G4ParticleDefinition* particle, 297 G4double tMand, 298 G4double plab, 299 G4double A, G4double Z ) 300 { 301 G4double m1 = particle->GetPDGMass(); 302 303 G4LorentzVector lv1(0.,0.,plab,std::sqrt(plab*plab+m1*m1)); 304 305 G4int iZ = static_cast<G4int>(Z+0.5); 306 G4int iA = static_cast<G4int>(A+0.5); 307 308 G4ParticleDefinition* theDef = 0; 309 310 if (iZ == 1 && iA == 1) theDef = theProton; 311 else if (iZ == 1 && iA == 2) theDef = theDeuteron; 312 else if (iZ == 1 && iA == 3) theDef = G4Triton::Triton(); 313 else if (iZ == 2 && iA == 3) theDef = G4He3::He3(); 314 else if (iZ == 2 && iA == 4) theDef = theAlpha; 315 else theDef = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(iZ,iA,0); 316 317 G4double tmass = theDef->GetPDGMass(); 318 319 G4LorentzVector lv(0.0,0.0,0.0,tmass); 320 lv += lv1; 321 322 G4ThreeVector bst = lv.boostVector(); 323 lv1.boost(-bst); 324 325 G4ThreeVector p1 = lv1.vect(); 326 G4double ptot = p1.mag(); 327 G4double ptot2 = ptot*ptot; 328 G4double cost = 1 - 0.5*std::fabs(tMand)/ptot2; 329 330 if( cost >= 1.0 ) cost = 1.0; 331 else if( cost <= -1.0) cost = -1.0; 332 333 G4double thetaCMS = std::acos(cost); 334 335 G4double sigma = GetDiffuseElasticSumXsc( particle, thetaCMS, ptot, A, Z ); 336 337 sigma *= pi/ptot2; 338 339 return sigma; 340 } 341 342 //////////////////////////////////////////////////////////////////////////// 343 // 344 // return invariant differential elastic cross section d(sigma)/d(tMand) with Coulomb 345 // correction 346 347 G4double 348 G4NuclNuclDiffuseElastic::GetInvCoulombElasticXsc( const G4ParticleDefinition* particle, 349 G4double tMand, 350 G4double plab, 351 G4double A, G4double Z ) 352 { 353 G4double m1 = particle->GetPDGMass(); 354 G4LorentzVector lv1(0.,0.,plab,std::sqrt(plab*plab+m1*m1)); 355 356 G4int iZ = static_cast<G4int>(Z+0.5); 357 G4int iA = static_cast<G4int>(A+0.5); 358 G4ParticleDefinition * theDef = 0; 359 360 if (iZ == 1 && iA == 1) theDef = theProton; 361 else if (iZ == 1 && iA == 2) theDef = theDeuteron; 362 else if (iZ == 1 && iA == 3) theDef = G4Triton::Triton(); 363 else if (iZ == 2 && iA == 3) theDef = G4He3::He3(); 364 else if (iZ == 2 && iA == 4) theDef = theAlpha; 365 else theDef = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(iZ,iA,0); 366 367 G4double tmass = theDef->GetPDGMass(); 368 369 G4LorentzVector lv(0.0,0.0,0.0,tmass); 370 lv += lv1; 371 372 G4ThreeVector bst = lv.boostVector(); 373 lv1.boost(-bst); 374 375 G4ThreeVector p1 = lv1.vect(); 376 G4double ptot = p1.mag(); 377 G4double ptot2 = ptot*ptot; 378 G4double cost = 1 - 0.5*std::fabs(tMand)/ptot2; 379 380 if( cost >= 1.0 ) cost = 1.0; 381 else if( cost <= -1.0) cost = -1.0; 382 383 G4double thetaCMS = std::acos(cost); 384 385 G4double sigma = GetCoulombElasticXsc( particle, thetaCMS, ptot, Z ); 386 387 sigma *= pi/ptot2; 388 389 return sigma; 390 } 391 392 //////////////////////////////////////////////////////////////////////////// 393 // 394 // return differential elastic probability d(probability)/d(omega) 395 396 G4double 397 G4NuclNuclDiffuseElastic::GetDiffElasticProb( // G4ParticleDefinition* particle, 398 G4double theta 399 // G4double momentum, 400 // G4double A 401 ) 402 { 403 G4double sigma, bzero, bzero2, bonebyarg, bonebyarg2, damp, damp2; 404 G4double delta, diffuse, gamma; 405 G4double e1, e2, bone, bone2; 406 407 // G4double wavek = momentum/hbarc; // wave vector 408 // G4double r0 = 1.08*fermi; 409 // G4double rad = r0*G4Pow::GetInstance()->A13(A); 410 411 G4double kr = fWaveVector*fNuclearRadius; // wavek*rad; 412 G4double kr2 = kr*kr; 413 G4double krt = kr*theta; 414 415 bzero = BesselJzero(krt); 416 bzero2 = bzero*bzero; 417 bone = BesselJone(krt); 418 bone2 = bone*bone; 419 bonebyarg = BesselOneByArg(krt); 420 bonebyarg2 = bonebyarg*bonebyarg; 421 422 // VI - Coverity complains 423 /* 424 if (fParticle == theProton) 425 { 426 diffuse = 0.63*fermi; 427 gamma = 0.3*fermi; 428 delta = 0.1*fermi*fermi; 429 e1 = 0.3*fermi; 430 e2 = 0.35*fermi; 431 } 432 else // as proton, if were not defined 433 { 434 */ 435 diffuse = 0.63*fermi; 436 gamma = 0.3*fermi; 437 delta = 0.1*fermi*fermi; 438 e1 = 0.3*fermi; 439 e2 = 0.35*fermi; 440 //} 441 G4double lambda = 15.; // 15 ok 442 443 // G4double kgamma = fWaveVector*gamma; // wavek*delta; 444 445 G4double kgamma = lambda*(1.-G4Exp(-fWaveVector*gamma/lambda)); // wavek*delta; 446 G4double kgamma2 = kgamma*kgamma; 447 448 // G4double dk2t = delta*fWaveVector*fWaveVector*theta; // delta*wavek*wavek*theta; 449 // G4double dk2t2 = dk2t*dk2t; 450 // G4double pikdt = pi*fWaveVector*diffuse*theta;// pi*wavek*diffuse*theta; 451 452 G4double pikdt = lambda*(1.-G4Exp(-pi*fWaveVector*diffuse*theta/lambda)); // wavek*delta; 453 454 damp = DampFactor(pikdt); 455 damp2 = damp*damp; 456 457 G4double mode2k2 = (e1*e1+e2*e2)*fWaveVector*fWaveVector; 458 G4double e2dk3t = -2.*e2*delta*fWaveVector*fWaveVector*fWaveVector*theta; 459 460 461 sigma = kgamma2; 462 // sigma += dk2t2; 463 sigma *= bzero2; 464 sigma += mode2k2*bone2 + e2dk3t*bzero*bone; 465 sigma += kr2*bonebyarg2; 466 sigma *= damp2; // *rad*rad; 467 468 return sigma; 469 } 470 471 //////////////////////////////////////////////////////////////////////////// 472 // 473 // return differential elastic probability d(probability)/d(omega) with 474 // Coulomb correction 475 476 G4double 477 G4NuclNuclDiffuseElastic::GetDiffElasticSumProb( // G4ParticleDefinition* particle, 478 G4double theta 479 // G4double momentum, 480 // G4double A 481 ) 482 { 483 G4double sigma, bzero, bzero2, bonebyarg, bonebyarg2, damp, damp2; 484 G4double delta, diffuse, gamma; 485 G4double e1, e2, bone, bone2; 486 487 // G4double wavek = momentum/hbarc; // wave vector 488 // G4double r0 = 1.08*fermi; 489 // G4double rad = r0*G4Pow::GetInstance()->A13(A); 490 491 G4double kr = fWaveVector*fNuclearRadius; // wavek*rad; 492 G4double kr2 = kr*kr; 493 G4double krt = kr*theta; 494 495 bzero = BesselJzero(krt); 496 bzero2 = bzero*bzero; 497 bone = BesselJone(krt); 498 bone2 = bone*bone; 499 bonebyarg = BesselOneByArg(krt); 500 bonebyarg2 = bonebyarg*bonebyarg; 501 502 if (fParticle == theProton) 503 { 504 diffuse = 0.63*fermi; 505 // diffuse = 0.6*fermi; 506 gamma = 0.3*fermi; 507 delta = 0.1*fermi*fermi; 508 e1 = 0.3*fermi; 509 e2 = 0.35*fermi; 510 } 511 else // as proton, if were not defined 512 { 513 diffuse = 0.63*fermi; 514 gamma = 0.3*fermi; 515 delta = 0.1*fermi*fermi; 516 e1 = 0.3*fermi; 517 e2 = 0.35*fermi; 518 } 519 G4double lambda = 15.; // 15 ok 520 // G4double kgamma = fWaveVector*gamma; // wavek*delta; 521 G4double kgamma = lambda*(1.-G4Exp(-fWaveVector*gamma/lambda)); // wavek*delta; 522 523 // G4cout<<"kgamma = "<<kgamma<<G4endl; 524 525 if(fAddCoulomb) // add Coulomb correction 526 { 527 G4double sinHalfTheta = std::sin(0.5*theta); 528 G4double sinHalfTheta2 = sinHalfTheta*sinHalfTheta; 529 530 kgamma += 0.5*fZommerfeld/kr/(sinHalfTheta2+fAm); // correction at J0() 531 // kgamma += 0.65*fZommerfeld/kr/(sinHalfTheta2+fAm); // correction at J0() 532 } 533 534 G4double kgamma2 = kgamma*kgamma; 535 536 // G4double dk2t = delta*fWaveVector*fWaveVector*theta; // delta*wavek*wavek*theta; 537 // G4cout<<"dk2t = "<<dk2t<<G4endl; 538 // G4double dk2t2 = dk2t*dk2t; 539 // G4double pikdt = pi*fWaveVector*diffuse*theta;// pi*wavek*diffuse*theta; 540 541 G4double pikdt = lambda*(1.-G4Exp(-pi*fWaveVector*diffuse*theta/lambda)); // wavek*delta; 542 543 // G4cout<<"pikdt = "<<pikdt<<G4endl; 544 545 damp = DampFactor(pikdt); 546 damp2 = damp*damp; 547 548 G4double mode2k2 = (e1*e1+e2*e2)*fWaveVector*fWaveVector; 549 G4double e2dk3t = -2.*e2*delta*fWaveVector*fWaveVector*fWaveVector*theta; 550 551 sigma = kgamma2; 552 // sigma += dk2t2; 553 sigma *= bzero2; 554 sigma += mode2k2*bone2; 555 sigma += e2dk3t*bzero*bone; 556 557 // sigma += kr2*(1 + 8.*fZommerfeld*fZommerfeld/kr2)*bonebyarg2; // correction at J1()/() 558 sigma += kr2*bonebyarg2; // correction at J1()/() 559 560 sigma *= damp2; // *rad*rad; 561 562 return sigma; 563 } 564 565 566 //////////////////////////////////////////////////////////////////////////// 567 // 568 // return differential elastic probability d(probability)/d(t) with 569 // Coulomb correction 570 571 G4double 572 G4NuclNuclDiffuseElastic::GetDiffElasticSumProbA( G4double alpha ) 573 { 574 G4double theta; 575 576 theta = std::sqrt(alpha); 577 578 // theta = std::acos( 1 - alpha/2. ); 579 580 G4double sigma, bzero, bzero2, bonebyarg, bonebyarg2, damp, damp2; 581 G4double delta, diffuse, gamma; 582 G4double e1, e2, bone, bone2; 583 584 // G4double wavek = momentum/hbarc; // wave vector 585 // G4double r0 = 1.08*fermi; 586 // G4double rad = r0*G4Pow::GetInstance()->A13(A); 587 588 G4double kr = fWaveVector*fNuclearRadius; // wavek*rad; 589 G4double kr2 = kr*kr; 590 G4double krt = kr*theta; 591 592 bzero = BesselJzero(krt); 593 bzero2 = bzero*bzero; 594 bone = BesselJone(krt); 595 bone2 = bone*bone; 596 bonebyarg = BesselOneByArg(krt); 597 bonebyarg2 = bonebyarg*bonebyarg; 598 599 if (fParticle == theProton) 600 { 601 diffuse = 0.63*fermi; 602 // diffuse = 0.6*fermi; 603 gamma = 0.3*fermi; 604 delta = 0.1*fermi*fermi; 605 e1 = 0.3*fermi; 606 e2 = 0.35*fermi; 607 } 608 else // as proton, if were not defined 609 { 610 diffuse = 0.63*fermi; 611 gamma = 0.3*fermi; 612 delta = 0.1*fermi*fermi; 613 e1 = 0.3*fermi; 614 e2 = 0.35*fermi; 615 } 616 G4double lambda = 15.; // 15 ok 617 // G4double kgamma = fWaveVector*gamma; // wavek*delta; 618 G4double kgamma = lambda*(1.-G4Exp(-fWaveVector*gamma/lambda)); // wavek*delta; 619 620 // G4cout<<"kgamma = "<<kgamma<<G4endl; 621 622 if(fAddCoulomb) // add Coulomb correction 623 { 624 G4double sinHalfTheta = theta*0.5; // std::sin(0.5*theta); 625 G4double sinHalfTheta2 = sinHalfTheta*sinHalfTheta; 626 627 kgamma += 0.5*fZommerfeld/kr/(sinHalfTheta2+fAm); // correction at J0() 628 // kgamma += 0.65*fZommerfeld/kr/(sinHalfTheta2+fAm); // correction at J0() 629 } 630 631 G4double kgamma2 = kgamma*kgamma; 632 633 // G4double dk2t = delta*fWaveVector*fWaveVector*theta; // delta*wavek*wavek*theta; 634 // G4cout<<"dk2t = "<<dk2t<<G4endl; 635 // G4double dk2t2 = dk2t*dk2t; 636 // G4double pikdt = pi*fWaveVector*diffuse*theta;// pi*wavek*diffuse*theta; 637 638 G4double pikdt = lambda*(1.-G4Exp(-pi*fWaveVector*diffuse*theta/lambda)); // wavek*delta; 639 640 // G4cout<<"pikdt = "<<pikdt<<G4endl; 641 642 damp = DampFactor(pikdt); 643 damp2 = damp*damp; 644 645 G4double mode2k2 = (e1*e1+e2*e2)*fWaveVector*fWaveVector; 646 G4double e2dk3t = -2.*e2*delta*fWaveVector*fWaveVector*fWaveVector*theta; 647 648 sigma = kgamma2; 649 // sigma += dk2t2; 650 sigma *= bzero2; 651 sigma += mode2k2*bone2; 652 sigma += e2dk3t*bzero*bone; 653 654 // sigma += kr2*(1 + 8.*fZommerfeld*fZommerfeld/kr2)*bonebyarg2; // correction at J1()/() 655 sigma += kr2*bonebyarg2; // correction at J1()/() 656 657 sigma *= damp2; // *rad*rad; 658 659 return sigma; 660 } 661 662 663 //////////////////////////////////////////////////////////////////////////// 664 // 665 // return differential elastic probability 2*pi*sin(theta)*d(probability)/d(omega) 666 667 G4double 668 G4NuclNuclDiffuseElastic::GetIntegrandFunction( G4double alpha ) 669 { 670 G4double result; 671 672 result = GetDiffElasticSumProbA(alpha); 673 674 // result *= 2*pi*std::sin(theta); 675 676 return result; 677 } 678 679 //////////////////////////////////////////////////////////////////////////// 680 // 681 // return integral elastic cross section d(sigma)/d(omega) integrated 0 - theta 682 683 G4double 684 G4NuclNuclDiffuseElastic::IntegralElasticProb( const G4ParticleDefinition* particle, 685 G4double theta, 686 G4double momentum, 687 G4double A ) 688 { 689 G4double result; 690 fParticle = particle; 691 fWaveVector = momentum/hbarc; 692 fAtomicWeight = A; 693 694 fNuclearRadius = CalculateNuclearRad(A); 695 696 697 G4Integrator<G4NuclNuclDiffuseElastic,G4double(G4NuclNuclDiffuseElastic::*)(G4double)> integral; 698 699 // result = integral.Legendre10(this,&G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., theta ); 700 result = integral.Legendre96(this,&G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., theta ); 701 702 return result; 703 } 704 705 //////////////////////////////////////////////////////////////////////////// 706 // 707 // Return inv momentum transfer -t > 0 708 709 G4double G4NuclNuclDiffuseElastic::SampleT( const G4ParticleDefinition* aParticle, 710 G4double p, G4double A) 711 { 712 G4double theta = SampleThetaCMS( aParticle, p, A); // sample theta in cms 713 G4double t = 2*p*p*( 1 - std::cos(theta) ); // -t !!! 714 return t; 715 } 716 717 //////////////////////////////////////////////////////////////////////////// 718 // 719 // Return scattering angle sampled in cms 720 721 722 G4double 723 G4NuclNuclDiffuseElastic::SampleThetaCMS(const G4ParticleDefinition* particle, 724 G4double momentum, G4double A) 725 { 726 G4int i, iMax = 100; 727 G4double norm, theta1, theta2, thetaMax; 728 G4double result = 0., sum = 0.; 729 730 fParticle = particle; 731 fWaveVector = momentum/hbarc; 732 fAtomicWeight = A; 733 734 fNuclearRadius = CalculateNuclearRad(A); 735 736 thetaMax = 10.174/fWaveVector/fNuclearRadius; 737 738 if (thetaMax > pi) thetaMax = pi; 739 740 G4Integrator<G4NuclNuclDiffuseElastic,G4double(G4NuclNuclDiffuseElastic::*)(G4double)> integral; 741 742 // result = integral.Legendre10(this,&G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., theta ); 743 norm = integral.Legendre96(this,&G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., thetaMax ); 744 745 norm *= G4UniformRand(); 746 747 for(i = 1; i <= iMax; i++) 748 { 749 theta1 = (i-1)*thetaMax/iMax; 750 theta2 = i*thetaMax/iMax; 751 sum += integral.Legendre10(this,&G4NuclNuclDiffuseElastic::GetIntegrandFunction, theta1, theta2); 752 753 if ( sum >= norm ) 754 { 755 result = 0.5*(theta1 + theta2); 756 break; 757 } 758 } 759 if (i > iMax ) result = 0.5*(theta1 + theta2); 760 761 G4double sigma = pi*thetaMax/iMax; 762 763 result += G4RandGauss::shoot(0.,sigma); 764 765 if(result < 0.) result = 0.; 766 if(result > thetaMax) result = thetaMax; 767 768 return result; 769 } 770 771 ///////////////////////////////////////////////////////////////////////////// 772 ///////////////////// Table preparation and reading //////////////////////// 773 774 //////////////////////////////////////////////////////////////////////////// 775 // 776 // Interface function. Return inv momentum transfer -t > 0 from initialisation table 777 778 G4double G4NuclNuclDiffuseElastic::SampleInvariantT( const G4ParticleDefinition* aParticle, G4double p, 779 G4int Z, G4int A) 780 { 781 fParticle = aParticle; 782 fAtomicNumber = G4double(Z); 783 fAtomicWeight = G4double(A); 784 785 G4double t(0.), m1 = fParticle->GetPDGMass(); 786 G4double totElab = std::sqrt(m1*m1+p*p); 787 G4double mass2 = G4NucleiProperties::GetNuclearMass(A, Z); 788 G4LorentzVector lv1(p,0.0,0.0,totElab); 789 G4LorentzVector lv(0.0,0.0,0.0,mass2); 790 lv += lv1; 791 792 G4ThreeVector bst = lv.boostVector(); 793 lv1.boost(-bst); 794 795 G4ThreeVector p1 = lv1.vect(); 796 G4double momentumCMS = p1.mag(); 797 798 // t = SampleTableT( aParticle, momentumCMS, G4double(Z), G4double(A) ); // sample theta2 in cms 799 800 t = SampleCoulombMuCMS( aParticle, momentumCMS); // sample theta2 in cms 801 802 803 return t; 804 } 805 806 //////////////////////////////////////////////////////////////////////////// 807 // 808 // Return inv momentum transfer -t > 0 as Coulomb scattering <= thetaC 809 810 G4double G4NuclNuclDiffuseElastic::SampleCoulombMuCMS( const G4ParticleDefinition* aParticle, G4double p) 811 { 812 G4double t(0.), rand(0.), mu(0.); 813 814 G4double A1 = G4double( aParticle->GetBaryonNumber() ); 815 G4double R1 = CalculateNuclearRad(A1); 816 817 fNuclearRadius = CalculateNuclearRad(fAtomicWeight); 818 fNuclearRadius += R1; 819 820 InitDynParameters(fParticle, p); 821 822 fCoulombMuC = fHalfRutThetaTg2/(1.+fHalfRutThetaTg2); 823 824 rand = G4UniformRand(); 825 826 // sample (1-cosTheta) in 0 < Theta < ThetaC as Coulomb scattering 827 828 mu = fCoulombMuC*rand*fAm; 829 mu /= fAm + fCoulombMuC*( 1. - rand ); 830 831 t = 4.*p*p*mu; 832 833 return t; 834 } 835 836 837 //////////////////////////////////////////////////////////////////////////// 838 // 839 // Return inv momentum transfer -t > 0 from initialisation table 840 841 G4double G4NuclNuclDiffuseElastic::SampleTableT( const G4ParticleDefinition* aParticle, G4double p, 842 G4double Z, G4double A) 843 { 844 G4double alpha = SampleTableThetaCMS( aParticle, p, Z, A); // sample theta2 in cms 845 // G4double t = 2*p*p*( 1 - std::cos(std::sqrt(alpha)) ); // -t !!! 846 G4double t = p*p*alpha; // -t !!! 847 return t; 848 } 849 850 //////////////////////////////////////////////////////////////////////////// 851 // 852 // Return scattering angle2 sampled in cms according to precalculated table. 853 854 855 G4double 856 G4NuclNuclDiffuseElastic::SampleTableThetaCMS(const G4ParticleDefinition* particle, 857 G4double momentum, G4double Z, G4double A) 858 { 859 std::size_t iElement; 860 G4int iMomentum, iAngle; 861 G4double randAngle, position, theta1, theta2, E1, E2, W1, W2, W; 862 G4double m1 = particle->GetPDGMass(); 863 864 for(iElement = 0; iElement < fElementNumberVector.size(); iElement++) 865 { 866 if( std::fabs(Z - fElementNumberVector[iElement]) < 0.5) break; 867 } 868 if ( iElement == fElementNumberVector.size() ) 869 { 870 InitialiseOnFly(Z,A); // table preparation, if needed 871 872 // iElement--; 873 874 // G4cout << "G4NuclNuclDiffuseElastic: Element with atomic number " << Z 875 // << " is not found, return zero angle" << G4endl; 876 // return 0.; // no table for this element 877 } 878 // G4cout<<"iElement = "<<iElement<<G4endl; 879 880 fAngleTable = fAngleBank[iElement]; 881 882 G4double kinE = std::sqrt(momentum*momentum + m1*m1) - m1; 883 884 for( iMomentum = 0; iMomentum < fEnergyBin; iMomentum++) 885 { 886 // G4cout<<iMomentum<<", kinE = "<<kinE/MeV<<", vectorE = "<<fEnergyVector->GetLowEdgeEnergy(iMomentum)/MeV<<G4endl; 887 888 if( kinE < fEnergyVector->GetLowEdgeEnergy(iMomentum) ) break; 889 } 890 // G4cout<<"iMomentum = "<<iMomentum<<", fEnergyBin -1 = "<<fEnergyBin -1<<G4endl; 891 892 893 if ( iMomentum >= fEnergyBin ) iMomentum = fEnergyBin-1; // kinE is more then theMaxEnergy 894 if ( iMomentum < 0 ) iMomentum = 0; // against negative index, kinE < theMinEnergy 895 896 897 if (iMomentum == fEnergyBin -1 || iMomentum == 0 ) // the table edges 898 { 899 position = (*(*fAngleTable)(iMomentum))(fAngleBin-2)*G4UniformRand(); 900 901 // G4cout<<"position = "<<position<<G4endl; 902 903 for(iAngle = 0; iAngle < fAngleBin-1; iAngle++) 904 { 905 if( position < (*(*fAngleTable)(iMomentum))(iAngle) ) break; 906 } 907 if (iAngle >= fAngleBin-1) iAngle = fAngleBin-2; 908 909 // G4cout<<"iAngle = "<<iAngle<<G4endl; 910 911 randAngle = GetScatteringAngle(iMomentum, iAngle, position); 912 913 // G4cout<<"randAngle = "<<randAngle<<G4endl; 914 } 915 else // kinE inside between energy table edges 916 { 917 // position = (*(*fAngleTable)(iMomentum))(fAngleBin-2)*G4UniformRand(); 918 position = (*(*fAngleTable)(iMomentum))(0)*G4UniformRand(); 919 920 // G4cout<<"position = "<<position<<G4endl; 921 922 for(iAngle = 0; iAngle < fAngleBin-1; iAngle++) 923 { 924 // if( position < (*(*fAngleTable)(iMomentum))(iAngle) ) break; 925 if( position > (*(*fAngleTable)(iMomentum))(iAngle) ) break; 926 } 927 if (iAngle >= fAngleBin-1) iAngle = fAngleBin-2; 928 929 // G4cout<<"iAngle = "<<iAngle<<G4endl; 930 931 theta2 = GetScatteringAngle(iMomentum, iAngle, position); 932 933 // G4cout<<"theta2 = "<<theta2<<G4endl; 934 935 E2 = fEnergyVector->GetLowEdgeEnergy(iMomentum); 936 937 // G4cout<<"E2 = "<<E2<<G4endl; 938 939 iMomentum--; 940 941 // position = (*(*fAngleTable)(iMomentum))(fAngleBin-2)*G4UniformRand(); 942 943 // G4cout<<"position = "<<position<<G4endl; 944 945 for(iAngle = 0; iAngle < fAngleBin-1; iAngle++) 946 { 947 // if( position < (*(*fAngleTable)(iMomentum))(iAngle) ) break; 948 if( position > (*(*fAngleTable)(iMomentum))(iAngle) ) break; 949 } 950 if (iAngle >= fAngleBin-1) iAngle = fAngleBin-2; 951 952 theta1 = GetScatteringAngle(iMomentum, iAngle, position); 953 954 // G4cout<<"theta1 = "<<theta1<<G4endl; 955 956 E1 = fEnergyVector->GetLowEdgeEnergy(iMomentum); 957 958 // G4cout<<"E1 = "<<E1<<G4endl; 959 960 W = 1.0/(E2 - E1); 961 W1 = (E2 - kinE)*W; 962 W2 = (kinE - E1)*W; 963 964 randAngle = W1*theta1 + W2*theta2; 965 966 // randAngle = theta2; 967 } 968 // G4double angle = randAngle; 969 // if (randAngle > 0.) randAngle /= 2*pi*std::sin(angle); 970 // G4cout<<"randAngle = "<<randAngle/degree<<G4endl; 971 972 return randAngle; 973 } 974 975 ////////////////////////////////////////////////////////////////////////////// 976 // 977 // Initialisation for given particle on fly using new element number 978 979 void G4NuclNuclDiffuseElastic::InitialiseOnFly(G4double Z, G4double A) 980 { 981 fAtomicNumber = Z; // atomic number 982 fAtomicWeight = G4NistManager::Instance()->GetAtomicMassAmu( static_cast< G4int >( Z ) ); 983 984 G4double A1 = G4double( fParticle->GetBaryonNumber() ); 985 G4double R1 = CalculateNuclearRad(A1); 986 987 fNuclearRadius = CalculateNuclearRad(fAtomicWeight) + R1; 988 989 if( verboseLevel > 0 ) 990 { 991 G4cout<<"G4NuclNuclDiffuseElastic::Initialise() the element with Z = " 992 <<Z<<"; and A = "<<A<<G4endl; 993 } 994 fElementNumberVector.push_back(fAtomicNumber); 995 996 BuildAngleTable(); 997 998 fAngleBank.push_back(fAngleTable); 999 1000 return; 1001 } 1002 1003 /////////////////////////////////////////////////////////////////////////////// 1004 // 1005 // Build for given particle and element table of momentum, angle probability. 1006 // For the moment in lab system. 1007 1008 void G4NuclNuclDiffuseElastic::BuildAngleTable() 1009 { 1010 G4int i, j; 1011 G4double partMom, kinE, m1 = fParticle->GetPDGMass(); 1012 G4double alpha1, alpha2, alphaMax, alphaCoulomb, delta = 0., sum = 0.; 1013 1014 // G4cout<<"particle z = "<<z<<"; particle m1 = "<<m1/GeV<<" GeV"<<G4endl; 1015 1016 G4Integrator<G4NuclNuclDiffuseElastic,G4double(G4NuclNuclDiffuseElastic::*)(G4double)> integral; 1017 1018 fAngleTable = new G4PhysicsTable(fEnergyBin); 1019 1020 for( i = 0; i < fEnergyBin; i++) 1021 { 1022 kinE = fEnergyVector->GetLowEdgeEnergy(i); 1023 1024 // G4cout<<G4endl; 1025 // G4cout<<"kinE = "<<kinE/MeV<<" MeV"<<G4endl; 1026 1027 partMom = std::sqrt( kinE*(kinE + 2*m1) ); 1028 1029 InitDynParameters(fParticle, partMom); 1030 1031 alphaMax = fRutherfordTheta*fCofAlphaMax; 1032 1033 if(alphaMax > pi) alphaMax = pi; 1034 1035 // VI: Coverity complain 1036 //alphaMax = pi2; 1037 1038 alphaCoulomb = fRutherfordTheta*fCofAlphaCoulomb; 1039 1040 // G4cout<<"alphaCoulomb = "<<alphaCoulomb/degree<<"; alphaMax = "<<alphaMax/degree<<G4endl; 1041 1042 G4PhysicsFreeVector* angleVector = new G4PhysicsFreeVector(fAngleBin-1); 1043 1044 // G4PhysicsLogVector* angleBins = new G4PhysicsLogVector( 0.001*alphaMax, alphaMax, fAngleBin ); 1045 1046 G4double delth = (alphaMax-alphaCoulomb)/fAngleBin; 1047 1048 sum = 0.; 1049 1050 // fAddCoulomb = false; 1051 fAddCoulomb = true; 1052 1053 // for(j = 1; j < fAngleBin; j++) 1054 for(j = fAngleBin-1; j >= 1; j--) 1055 { 1056 // alpha1 = angleBins->GetLowEdgeEnergy(j-1); 1057 // alpha2 = angleBins->GetLowEdgeEnergy(j); 1058 1059 // alpha1 = alphaMax*(j-1)/fAngleBin; 1060 // alpha2 = alphaMax*( j )/fAngleBin; 1061 1062 alpha1 = alphaCoulomb + delth*(j-1); 1063 // if(alpha1 < kRlim2) alpha1 = kRlim2; 1064 alpha2 = alpha1 + delth; 1065 1066 delta = integral.Legendre10(this, &G4NuclNuclDiffuseElastic::GetFresnelIntegrandXsc, alpha1, alpha2); 1067 // delta = integral.Legendre96(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, alpha1, alpha2); 1068 1069 sum += delta; 1070 1071 angleVector->PutValue( j-1 , alpha1, sum ); // alpha2 1072 // G4cout<<"j-1 = "<<j-1<<"; alpha2 = "<<alpha2/degree<<"; sum = "<<sum<<G4endl; 1073 } 1074 fAngleTable->insertAt(i,angleVector); 1075 1076 // delete[] angleVector; 1077 // delete[] angleBins; 1078 } 1079 return; 1080 } 1081 1082 ///////////////////////////////////////////////////////////////////////////////// 1083 // 1084 // 1085 1086 G4double 1087 G4NuclNuclDiffuseElastic:: GetScatteringAngle( G4int iMomentum, G4int iAngle, G4double position ) 1088 { 1089 G4double x1, x2, y1, y2, randAngle; 1090 1091 if( iAngle == 0 ) 1092 { 1093 randAngle = (*fAngleTable)(iMomentum)->GetLowEdgeEnergy(iAngle); 1094 // iAngle++; 1095 } 1096 else 1097 { 1098 if ( iAngle >= G4int((*fAngleTable)(iMomentum)->GetVectorLength()) ) 1099 { 1100 iAngle = G4int((*fAngleTable)(iMomentum)->GetVectorLength() - 1); 1101 } 1102 y1 = (*(*fAngleTable)(iMomentum))(iAngle-1); 1103 y2 = (*(*fAngleTable)(iMomentum))(iAngle); 1104 1105 x1 = (*fAngleTable)(iMomentum)->GetLowEdgeEnergy(iAngle-1); 1106 x2 = (*fAngleTable)(iMomentum)->GetLowEdgeEnergy(iAngle); 1107 1108 if ( x1 == x2 ) randAngle = x2; 1109 else 1110 { 1111 if ( y1 == y2 ) randAngle = x1 + ( x2 - x1 )*G4UniformRand(); 1112 else 1113 { 1114 randAngle = x1 + ( position - y1 )*( x2 - x1 )/( y2 - y1 ); 1115 } 1116 } 1117 } 1118 return randAngle; 1119 } 1120 1121 1122 1123 //////////////////////////////////////////////////////////////////////////// 1124 // 1125 // Return scattering angle sampled in lab system (target at rest) 1126 1127 1128 1129 G4double 1130 G4NuclNuclDiffuseElastic::SampleThetaLab( const G4HadProjectile* aParticle, 1131 G4double tmass, G4double A) 1132 { 1133 const G4ParticleDefinition* theParticle = aParticle->GetDefinition(); 1134 G4double m1 = theParticle->GetPDGMass(); 1135 G4double plab = aParticle->GetTotalMomentum(); 1136 G4LorentzVector lv1 = aParticle->Get4Momentum(); 1137 G4LorentzVector lv(0.0,0.0,0.0,tmass); 1138 lv += lv1; 1139 1140 G4ThreeVector bst = lv.boostVector(); 1141 lv1.boost(-bst); 1142 1143 G4ThreeVector p1 = lv1.vect(); 1144 G4double ptot = p1.mag(); 1145 G4double tmax = 4.0*ptot*ptot; 1146 G4double t = 0.0; 1147 1148 1149 // 1150 // Sample t 1151 // 1152 1153 t = SampleT( theParticle, ptot, A); 1154 1155 // NaN finder 1156 if(!(t < 0.0 || t >= 0.0)) 1157 { 1158 if (verboseLevel > 0) 1159 { 1160 G4cout << "G4NuclNuclDiffuseElastic:WARNING: A = " << A 1161 << " mom(GeV)= " << plab/GeV 1162 << " S-wave will be sampled" 1163 << G4endl; 1164 } 1165 t = G4UniformRand()*tmax; 1166 } 1167 if(verboseLevel>1) 1168 { 1169 G4cout <<" t= " << t << " tmax= " << tmax 1170 << " ptot= " << ptot << G4endl; 1171 } 1172 // Sampling of angles in CM system 1173 1174 G4double phi = G4UniformRand()*twopi; 1175 G4double cost = 1. - 2.0*t/tmax; 1176 G4double sint; 1177 1178 if( cost >= 1.0 ) 1179 { 1180 cost = 1.0; 1181 sint = 0.0; 1182 } 1183 else if( cost <= -1.0) 1184 { 1185 cost = -1.0; 1186 sint = 0.0; 1187 } 1188 else 1189 { 1190 sint = std::sqrt((1.0-cost)*(1.0+cost)); 1191 } 1192 if (verboseLevel>1) 1193 { 1194 G4cout << "cos(t)=" << cost << " std::sin(t)=" << sint << G4endl; 1195 } 1196 G4ThreeVector v1(sint*std::cos(phi),sint*std::sin(phi),cost); 1197 v1 *= ptot; 1198 G4LorentzVector nlv1(v1.x(),v1.y(),v1.z(),std::sqrt(ptot*ptot + m1*m1)); 1199 1200 nlv1.boost(bst); 1201 1202 G4ThreeVector np1 = nlv1.vect(); 1203 1204 // G4double theta = std::acos( np1.z()/np1.mag() ); // degree; 1205 1206 G4double theta = np1.theta(); 1207 1208 return theta; 1209 } 1210 1211 //////////////////////////////////////////////////////////////////////////// 1212 // 1213 // Return scattering angle in lab system (target at rest) knowing theta in CMS 1214 1215 1216 1217 G4double 1218 G4NuclNuclDiffuseElastic::ThetaCMStoThetaLab( const G4DynamicParticle* aParticle, 1219 G4double tmass, G4double thetaCMS) 1220 { 1221 const G4ParticleDefinition* theParticle = aParticle->GetDefinition(); 1222 G4double m1 = theParticle->GetPDGMass(); 1223 // G4double plab = aParticle->GetTotalMomentum(); 1224 G4LorentzVector lv1 = aParticle->Get4Momentum(); 1225 G4LorentzVector lv(0.0,0.0,0.0,tmass); 1226 1227 lv += lv1; 1228 1229 G4ThreeVector bst = lv.boostVector(); 1230 1231 lv1.boost(-bst); 1232 1233 G4ThreeVector p1 = lv1.vect(); 1234 G4double ptot = p1.mag(); 1235 1236 G4double phi = G4UniformRand()*twopi; 1237 G4double cost = std::cos(thetaCMS); 1238 G4double sint; 1239 1240 if( cost >= 1.0 ) 1241 { 1242 cost = 1.0; 1243 sint = 0.0; 1244 } 1245 else if( cost <= -1.0) 1246 { 1247 cost = -1.0; 1248 sint = 0.0; 1249 } 1250 else 1251 { 1252 sint = std::sqrt((1.0-cost)*(1.0+cost)); 1253 } 1254 if (verboseLevel>1) 1255 { 1256 G4cout << "cos(tcms)=" << cost << " std::sin(tcms)=" << sint << G4endl; 1257 } 1258 G4ThreeVector v1(sint*std::cos(phi),sint*std::sin(phi),cost); 1259 v1 *= ptot; 1260 G4LorentzVector nlv1(v1.x(),v1.y(),v1.z(),std::sqrt(ptot*ptot + m1*m1)); 1261 1262 nlv1.boost(bst); 1263 1264 G4ThreeVector np1 = nlv1.vect(); 1265 1266 1267 G4double thetaLab = np1.theta(); 1268 1269 return thetaLab; 1270 } 1271 1272 //////////////////////////////////////////////////////////////////////////// 1273 // 1274 // Return scattering angle in CMS system (target at rest) knowing theta in Lab 1275 1276 1277 1278 G4double 1279 G4NuclNuclDiffuseElastic::ThetaLabToThetaCMS( const G4DynamicParticle* aParticle, 1280 G4double tmass, G4double thetaLab) 1281 { 1282 const G4ParticleDefinition* theParticle = aParticle->GetDefinition(); 1283 G4double m1 = theParticle->GetPDGMass(); 1284 G4double plab = aParticle->GetTotalMomentum(); 1285 G4LorentzVector lv1 = aParticle->Get4Momentum(); 1286 G4LorentzVector lv(0.0,0.0,0.0,tmass); 1287 1288 lv += lv1; 1289 1290 G4ThreeVector bst = lv.boostVector(); 1291 1292 // lv1.boost(-bst); 1293 1294 // G4ThreeVector p1 = lv1.vect(); 1295 // G4double ptot = p1.mag(); 1296 1297 G4double phi = G4UniformRand()*twopi; 1298 G4double cost = std::cos(thetaLab); 1299 G4double sint; 1300 1301 if( cost >= 1.0 ) 1302 { 1303 cost = 1.0; 1304 sint = 0.0; 1305 } 1306 else if( cost <= -1.0) 1307 { 1308 cost = -1.0; 1309 sint = 0.0; 1310 } 1311 else 1312 { 1313 sint = std::sqrt((1.0-cost)*(1.0+cost)); 1314 } 1315 if (verboseLevel>1) 1316 { 1317 G4cout << "cos(tlab)=" << cost << " std::sin(tlab)=" << sint << G4endl; 1318 } 1319 G4ThreeVector v1(sint*std::cos(phi),sint*std::sin(phi),cost); 1320 v1 *= plab; 1321 G4LorentzVector nlv1(v1.x(),v1.y(),v1.z(),std::sqrt(plab*plab + m1*m1)); 1322 1323 nlv1.boost(-bst); 1324 1325 G4ThreeVector np1 = nlv1.vect(); 1326 1327 1328 G4double thetaCMS = np1.theta(); 1329 1330 return thetaCMS; 1331 } 1332 1333 /////////////////////////////////////////////////////////////////////////////// 1334 // 1335 // Test for given particle and element table of momentum, angle probability. 1336 // For the moment in lab system. 1337 1338 void G4NuclNuclDiffuseElastic::TestAngleTable(const G4ParticleDefinition* theParticle, G4double partMom, 1339 G4double Z, G4double A) 1340 { 1341 fAtomicNumber = Z; // atomic number 1342 fAtomicWeight = A; // number of nucleons 1343 fNuclearRadius = CalculateNuclearRad(fAtomicWeight); 1344 1345 1346 1347 G4cout<<"G4NuclNuclDiffuseElastic::TestAngleTable() init the element with Z = " 1348 <<Z<<"; and A = "<<A<<G4endl; 1349 1350 fElementNumberVector.push_back(fAtomicNumber); 1351 1352 1353 1354 1355 G4int i=0, j; 1356 G4double a = 0., z = theParticle->GetPDGCharge(), m1 = fParticle->GetPDGMass(); 1357 G4double alpha1=0., alpha2=0., alphaMax=0., alphaCoulomb=0.; 1358 G4double deltaL10 = 0., deltaL96 = 0., deltaAG = 0.; 1359 G4double sumL10 = 0.,sumL96 = 0.,sumAG = 0.; 1360 G4double epsilon = 0.001; 1361 1362 G4Integrator<G4NuclNuclDiffuseElastic,G4double(G4NuclNuclDiffuseElastic::*)(G4double)> integral; 1363 1364 fAngleTable = new G4PhysicsTable(fEnergyBin); 1365 1366 fWaveVector = partMom/hbarc; 1367 1368 G4double kR = fWaveVector*fNuclearRadius; 1369 G4double kR2 = kR*kR; 1370 G4double kRmax = 10.6; // 10.6, 18, 10.174; ~ 3 maxima of J1 or 15., 25. 1371 G4double kRcoul = 1.2; // 1.4, 2.5; // on the first slope of J1 1372 1373 alphaMax = kRmax*kRmax/kR2; 1374 1375 if (alphaMax > 4.) alphaMax = 4.; // vmg05-02-09: was pi2 1376 1377 alphaCoulomb = kRcoul*kRcoul/kR2; 1378 1379 if( z ) 1380 { 1381 a = partMom/m1; // beta*gamma for m1 1382 fBeta = a/std::sqrt(1+a*a); 1383 fZommerfeld = CalculateZommerfeld( fBeta, z, fAtomicNumber); 1384 fAm = CalculateAm( partMom, fZommerfeld, fAtomicNumber); 1385 } 1386 G4PhysicsFreeVector* angleVector = new G4PhysicsFreeVector(fAngleBin-1); 1387 1388 // G4PhysicsLogVector* angleBins = new G4PhysicsLogVector( 0.001*alphaMax, alphaMax, fAngleBin ); 1389 1390 1391 fAddCoulomb = false; 1392 1393 for(j = 1; j < fAngleBin; j++) 1394 { 1395 // alpha1 = angleBins->GetLowEdgeEnergy(j-1); 1396 // alpha2 = angleBins->GetLowEdgeEnergy(j); 1397 1398 alpha1 = alphaMax*(j-1)/fAngleBin; 1399 alpha2 = alphaMax*( j )/fAngleBin; 1400 1401 if( ( alpha2 > alphaCoulomb ) && z ) fAddCoulomb = true; 1402 1403 deltaL10 = integral.Legendre10(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, alpha1, alpha2); 1404 deltaL96 = integral.Legendre96(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, alpha1, alpha2); 1405 deltaAG = integral.AdaptiveGauss(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, 1406 alpha1, alpha2,epsilon); 1407 1408 // G4cout<<alpha1<<"\t"<<std::sqrt(alpha1)/degree<<"\t" 1409 // <<deltaL10<<"\t"<<deltaL96<<"\t"<<deltaAG<<G4endl; 1410 1411 sumL10 += deltaL10; 1412 sumL96 += deltaL96; 1413 sumAG += deltaAG; 1414 1415 G4cout<<alpha1<<"\t"<<std::sqrt(alpha1)/degree<<"\t" 1416 <<sumL10<<"\t"<<sumL96<<"\t"<<sumAG<<G4endl; 1417 1418 angleVector->PutValue( j-1 , alpha1, sumL10 ); // alpha2 1419 } 1420 fAngleTable->insertAt(i,angleVector); 1421 fAngleBank.push_back(fAngleTable); 1422 1423 /* 1424 // Integral over all angle range - Bad accuracy !!! 1425 1426 sumL10 = integral.Legendre10(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., alpha2); 1427 sumL96 = integral.Legendre96(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, 0., alpha2); 1428 sumAG = integral.AdaptiveGauss(this, &G4NuclNuclDiffuseElastic::GetIntegrandFunction, 1429 0., alpha2,epsilon); 1430 G4cout<<G4endl; 1431 G4cout<<alpha2<<"\t"<<std::sqrt(alpha2)/degree<<"\t" 1432 <<sumL10<<"\t"<<sumL96<<"\t"<<sumAG<<G4endl; 1433 */ 1434 return; 1435 } 1436 1437 ///////////////////////////////////////////////////////////////// 1438 // 1439 // 1440 1441 G4double G4NuclNuclDiffuseElastic::GetLegendrePol(G4int n, G4double theta) 1442 { 1443 G4double legPol, epsilon = 1.e-6; 1444 G4double x = std::cos(theta); 1445 1446 if ( n < 0 ) legPol = 0.; 1447 else if( n == 0 ) legPol = 1.; 1448 else if( n == 1 ) legPol = x; 1449 else if( n == 2 ) legPol = (3.*x*x-1.)/2.; 1450 else if( n == 3 ) legPol = (5.*x*x*x-3.*x)/2.; 1451 else if( n == 4 ) legPol = (35.*x*x*x*x-30.*x*x+3.)/8.; 1452 else if( n == 5 ) legPol = (63.*x*x*x*x*x-70.*x*x*x+15.*x)/8.; 1453 else if( n == 6 ) legPol = (231.*x*x*x*x*x*x-315.*x*x*x*x+105.*x*x-5.)/16.; 1454 else 1455 { 1456 // legPol = ( (2*n-1)*x*GetLegendrePol(n-1,x) - (n-1)*GetLegendrePol(n-2,x) )/n; 1457 1458 legPol = std::sqrt( 2./(n*CLHEP::pi*std::sin(theta+epsilon)) )*std::sin( (n+0.5)*theta+0.25*CLHEP::pi ); 1459 } 1460 return legPol; 1461 } 1462 1463 ///////////////////////////////////////////////////////////////// 1464 // 1465 // 1466 1467 G4complex G4NuclNuclDiffuseElastic::GetErfComp(G4complex z, G4int nMax) 1468 { 1469 G4int n; 1470 G4double n2, cofn, shny, chny, fn, gn; 1471 1472 G4double x = z.real(); 1473 G4double y = z.imag(); 1474 1475 G4double outRe = 0., outIm = 0.; 1476 1477 G4double twox = 2.*x; 1478 G4double twoxy = twox*y; 1479 G4double twox2 = twox*twox; 1480 1481 G4double cof1 = G4Exp(-x*x)/CLHEP::pi; 1482 1483 G4double cos2xy = std::cos(twoxy); 1484 G4double sin2xy = std::sin(twoxy); 1485 1486 G4double twoxcos2xy = twox*cos2xy; 1487 G4double twoxsin2xy = twox*sin2xy; 1488 1489 for( n = 1; n <= nMax; n++) 1490 { 1491 n2 = n*n; 1492 1493 cofn = G4Exp(-0.5*n2)/(n2+twox2); // /(n2+0.5*twox2); 1494 1495 chny = std::cosh(n*y); 1496 shny = std::sinh(n*y); 1497 1498 fn = twox - twoxcos2xy*chny + n*sin2xy*shny; 1499 gn = twoxsin2xy*chny + n*cos2xy*shny; 1500 1501 fn *= cofn; 1502 gn *= cofn; 1503 1504 outRe += fn; 1505 outIm += gn; 1506 } 1507 outRe *= 2*cof1; 1508 outIm *= 2*cof1; 1509 1510 if(std::abs(x) < 0.0001) 1511 { 1512 outRe += GetErf(x); 1513 outIm += cof1*y; 1514 } 1515 else 1516 { 1517 outRe += GetErf(x) + cof1*(1-cos2xy)/twox; 1518 outIm += cof1*sin2xy/twox; 1519 } 1520 return G4complex(outRe, outIm); 1521 } 1522 1523 1524 ///////////////////////////////////////////////////////////////// 1525 // 1526 // 1527 1528 G4complex G4NuclNuclDiffuseElastic::GetErfInt(G4complex z) // , G4int nMax) 1529 { 1530 G4double outRe, outIm; 1531 1532 G4double x = z.real(); 1533 G4double y = z.imag(); 1534 fReZ = x; 1535 1536 G4Integrator<G4NuclNuclDiffuseElastic,G4double(G4NuclNuclDiffuseElastic::*)(G4double)> integral; 1537 1538 outRe = integral.Legendre96(this,&G4NuclNuclDiffuseElastic::GetExpSin, 0., y ); 1539 outIm = integral.Legendre96(this,&G4NuclNuclDiffuseElastic::GetExpCos, 0., y ); 1540 1541 outRe *= 2./std::sqrt(CLHEP::pi); 1542 outIm *= 2./std::sqrt(CLHEP::pi); 1543 1544 outRe += GetErf(x); 1545 1546 return G4complex(outRe, outIm); 1547 } 1548 1549 ///////////////////////////////////////////////////////////////// 1550 // 1551 // 1552 1553 1554 G4complex G4NuclNuclDiffuseElastic::GammaLess(G4double theta) 1555 { 1556 G4double sinThetaR = 2.*fHalfRutThetaTg/(1. + fHalfRutThetaTg2); 1557 G4double cosHalfThetaR2 = 1./(1. + fHalfRutThetaTg2); 1558 1559 G4double u = std::sqrt(0.5*fProfileLambda/sinThetaR); 1560 G4double kappa = u/std::sqrt(CLHEP::pi); 1561 G4double dTheta = theta - fRutherfordTheta; 1562 u *= dTheta; 1563 G4double u2 = u*u; 1564 G4double u2m2p3 = u2*2./3.; 1565 1566 G4complex im = G4complex(0.,1.); 1567 G4complex order = G4complex(u,u); 1568 order /= std::sqrt(2.); 1569 1570 G4complex gamma = CLHEP::pi*kappa*GetErfcInt(-order)*std::exp(im*(u*u+0.25*CLHEP::pi)); 1571 G4complex a0 = 0.5*(1. + 4.*(1.+im*u2)*cosHalfThetaR2/3.)/sinThetaR; 1572 G4complex a1 = 0.5*(1. + 2.*(1.+im*u2m2p3)*cosHalfThetaR2)/sinThetaR; 1573 G4complex out = gamma*(1. - a1*dTheta) - a0; 1574 1575 return out; 1576 } 1577 1578 ///////////////////////////////////////////////////////////////// 1579 // 1580 // 1581 1582 G4complex G4NuclNuclDiffuseElastic::GammaMore(G4double theta) 1583 { 1584 G4double sinThetaR = 2.*fHalfRutThetaTg/(1. + fHalfRutThetaTg2); 1585 G4double cosHalfThetaR2 = 1./(1. + fHalfRutThetaTg2); 1586 1587 G4double u = std::sqrt(0.5*fProfileLambda/sinThetaR); 1588 G4double kappa = u/std::sqrt(CLHEP::pi); 1589 G4double dTheta = theta - fRutherfordTheta; 1590 u *= dTheta; 1591 G4double u2 = u*u; 1592 G4double u2m2p3 = u2*2./3.; 1593 1594 G4complex im = G4complex(0.,1.); 1595 G4complex order = G4complex(u,u); 1596 order /= std::sqrt(2.); 1597 G4complex gamma = CLHEP::pi*kappa*GetErfcInt(order)*std::exp(im*(u*u+0.25*CLHEP::pi)); 1598 G4complex a0 = 0.5*(1. + 4.*(1.+im*u2)*cosHalfThetaR2/3.)/sinThetaR; 1599 G4complex a1 = 0.5*(1. + 2.*(1.+im*u2m2p3)*cosHalfThetaR2)/sinThetaR; 1600 G4complex out = -gamma*(1. - a1*dTheta) - a0; 1601 1602 return out; 1603 } 1604 1605 ///////////////////////////////////////////////////////////////// 1606 // 1607 // 1608 1609 G4complex G4NuclNuclDiffuseElastic::AmplitudeNear(G4double theta) 1610 { 1611 G4double kappa = std::sqrt(0.5*fProfileLambda/std::sin(theta)/CLHEP::pi); 1612 G4complex out = G4complex(kappa/fWaveVector,0.); 1613 1614 out *= PhaseNear(theta); 1615 1616 if( theta <= fRutherfordTheta ) 1617 { 1618 out *= GammaLess(theta) + ProfileNear(theta); 1619 // out *= GammaMore(theta) + ProfileNear(theta); 1620 out += CoulombAmplitude(theta); 1621 } 1622 else 1623 { 1624 out *= GammaMore(theta) + ProfileNear(theta); 1625 // out *= GammaLess(theta) + ProfileNear(theta); 1626 } 1627 return out; 1628 } 1629 1630 ///////////////////////////////////////////////////////////////// 1631 // 1632 // 1633 1634 G4complex G4NuclNuclDiffuseElastic::AmplitudeSim(G4double theta) 1635 { 1636 G4double sinThetaR = 2.*fHalfRutThetaTg/(1. + fHalfRutThetaTg2); 1637 G4double dTheta = 0.5*(theta - fRutherfordTheta); 1638 G4double sindTheta = std::sin(dTheta); 1639 G4double persqrt2 = std::sqrt(0.5); 1640 1641 G4complex order = G4complex(persqrt2,persqrt2); 1642 order *= std::sqrt(0.5*fProfileLambda/sinThetaR)*2.*sindTheta; 1643 // order *= std::sqrt(0.5*fProfileLambda/sinThetaR)*2.*dTheta; 1644 1645 G4complex out; 1646 1647 if ( theta <= fRutherfordTheta ) 1648 { 1649 out = 1. - 0.5*GetErfcInt(-order)*ProfileNear(theta); 1650 } 1651 else 1652 { 1653 out = 0.5*GetErfcInt(order)*ProfileNear(theta); 1654 } 1655 1656 out *= CoulombAmplitude(theta); 1657 1658 return out; 1659 } 1660 1661 ///////////////////////////////////////////////////////////////// 1662 // 1663 // 1664 1665 G4complex G4NuclNuclDiffuseElastic::AmplitudeGla(G4double theta) 1666 { 1667 G4int n; 1668 G4double T12b, b, b2; // cosTheta = std::cos(theta); 1669 G4complex out = G4complex(0.,0.), shiftC, shiftN; 1670 G4complex im = G4complex(0.,1.); 1671 1672 for( n = 0; n < fMaxL; n++) 1673 { 1674 shiftC = std::exp( im*2.*CalculateCoulombPhase(n) ); 1675 // b = ( fZommerfeld + std::sqrt( fZommerfeld*fZommerfeld + n*(n+1) ) )/fWaveVector; 1676 b = ( std::sqrt( G4double(n*(n+1)) ) )/fWaveVector; 1677 b2 = b*b; 1678 T12b = fSumSigma*G4Exp(-b2/fNuclearRadiusSquare)/CLHEP::pi/fNuclearRadiusSquare; 1679 shiftN = std::exp( -0.5*(1.-im*fEtaRatio)*T12b ) - 1.; 1680 out += (2.*n+1.)*shiftC*shiftN*GetLegendrePol(n, theta); 1681 } 1682 out /= 2.*im*fWaveVector; 1683 out += CoulombAmplitude(theta); 1684 return out; 1685 } 1686 1687 1688 ///////////////////////////////////////////////////////////////// 1689 // 1690 // 1691 1692 G4complex G4NuclNuclDiffuseElastic::AmplitudeGG(G4double theta) 1693 { 1694 G4int n; 1695 G4double T12b, a, aTemp, b2, sinThetaH = std::sin(0.5*theta); 1696 G4double sinThetaH2 = sinThetaH*sinThetaH; 1697 G4complex out = G4complex(0.,0.); 1698 G4complex im = G4complex(0.,1.); 1699 1700 a = -fSumSigma/CLHEP::twopi/fNuclearRadiusSquare; 1701 b2 = fWaveVector*fWaveVector*fNuclearRadiusSquare*sinThetaH2; 1702 1703 aTemp = a; 1704 1705 for( n = 1; n < fMaxL; n++) 1706 { 1707 T12b = aTemp*G4Exp(-b2/n)/n; 1708 aTemp *= a; 1709 out += T12b; 1710 G4cout<<"out = "<<out<<G4endl; 1711 } 1712 out *= -4.*im*fWaveVector/CLHEP::pi; 1713 out += CoulombAmplitude(theta); 1714 return out; 1715 } 1716 1717 1718 /////////////////////////////////////////////////////////////////////////////// 1719 // 1720 // Test for given particle and element table of momentum, angle probability. 1721 // For the partMom in CMS. 1722 1723 void G4NuclNuclDiffuseElastic::InitParameters(const G4ParticleDefinition* theParticle, 1724 G4double partMom, G4double Z, G4double A) 1725 { 1726 fAtomicNumber = Z; // atomic number 1727 fAtomicWeight = A; // number of nucleons 1728 1729 fNuclearRadius2 = CalculateNuclearRad(fAtomicWeight); 1730 G4double A1 = G4double( theParticle->GetBaryonNumber() ); 1731 fNuclearRadius1 = CalculateNuclearRad(A1); 1732 // fNuclearRadius = std::sqrt(fNuclearRadius1*fNuclearRadius1+fNuclearRadius2*fNuclearRadius2); 1733 fNuclearRadius = fNuclearRadius1 + fNuclearRadius2; 1734 1735 G4double a = 0.; 1736 G4double z = theParticle->GetPDGCharge(); 1737 G4double m1 = theParticle->GetPDGMass(); 1738 1739 fWaveVector = partMom/CLHEP::hbarc; 1740 1741 G4double lambda = fCofLambda*fWaveVector*fNuclearRadius; 1742 G4cout<<"kR = "<<lambda<<G4endl; 1743 1744 if( z ) 1745 { 1746 a = partMom/m1; // beta*gamma for m1 1747 fBeta = a/std::sqrt(1+a*a); 1748 fZommerfeld = CalculateZommerfeld( fBeta, z, fAtomicNumber); 1749 fRutherfordRatio = fZommerfeld/fWaveVector; 1750 fAm = CalculateAm( partMom, fZommerfeld, fAtomicNumber); 1751 } 1752 G4cout<<"fZommerfeld = "<<fZommerfeld<<G4endl; 1753 fProfileLambda = lambda; // *std::sqrt(1.-2*fZommerfeld/lambda); 1754 G4cout<<"fProfileLambda = "<<fProfileLambda<<G4endl; 1755 fProfileDelta = fCofDelta*fProfileLambda; 1756 fProfileAlpha = fCofAlpha*fProfileLambda; 1757 1758 CalculateCoulombPhaseZero(); 1759 CalculateRutherfordAnglePar(); 1760 1761 return; 1762 } 1763 /////////////////////////////////////////////////////////////////////////////// 1764 // 1765 // Test for given particle and element table of momentum, angle probability. 1766 // For the partMom in CMS. 1767 1768 void G4NuclNuclDiffuseElastic::InitDynParameters(const G4ParticleDefinition* theParticle, 1769 G4double partMom) 1770 { 1771 G4double a = 0.; 1772 G4double z = theParticle->GetPDGCharge(); 1773 G4double m1 = theParticle->GetPDGMass(); 1774 1775 fWaveVector = partMom/CLHEP::hbarc; 1776 1777 G4double lambda = fCofLambda*fWaveVector*fNuclearRadius; 1778 1779 if( z ) 1780 { 1781 a = partMom/m1; // beta*gamma for m1 1782 fBeta = a/std::sqrt(1+a*a); 1783 fZommerfeld = CalculateZommerfeld( fBeta, z, fAtomicNumber); 1784 fRutherfordRatio = fZommerfeld/fWaveVector; 1785 fAm = CalculateAm( partMom, fZommerfeld, fAtomicNumber); 1786 } 1787 fProfileLambda = lambda; // *std::sqrt(1.-2*fZommerfeld/lambda); 1788 fProfileDelta = fCofDelta*fProfileLambda; 1789 fProfileAlpha = fCofAlpha*fProfileLambda; 1790 1791 CalculateCoulombPhaseZero(); 1792 CalculateRutherfordAnglePar(); 1793 1794 return; 1795 } 1796 1797 1798 /////////////////////////////////////////////////////////////////////////////// 1799 // 1800 // Test for given particle and element table of momentum, angle probability. 1801 // For the partMom in CMS. 1802 1803 void G4NuclNuclDiffuseElastic::InitParametersGla(const G4DynamicParticle* aParticle, 1804 G4double partMom, G4double Z, G4double A) 1805 { 1806 fAtomicNumber = Z; // target atomic number 1807 fAtomicWeight = A; // target number of nucleons 1808 1809 fNuclearRadius2 = CalculateNuclearRad(fAtomicWeight); // target nucleus radius 1810 G4double A1 = G4double( aParticle->GetDefinition()->GetBaryonNumber() ); 1811 fNuclearRadius1 = CalculateNuclearRad(A1); // projectile nucleus radius 1812 fNuclearRadiusSquare = fNuclearRadius1*fNuclearRadius1+fNuclearRadius2*fNuclearRadius2; 1813 1814 1815 G4double a = 0., kR12; 1816 G4double z = aParticle->GetDefinition()->GetPDGCharge(); 1817 G4double m1 = aParticle->GetDefinition()->GetPDGMass(); 1818 1819 fWaveVector = partMom/CLHEP::hbarc; 1820 1821 G4double pN = A1 - z; 1822 if( pN < 0. ) pN = 0.; 1823 1824 G4double tN = A - Z; 1825 if( tN < 0. ) tN = 0.; 1826 1827 G4double pTkin = aParticle->GetKineticEnergy(); 1828 pTkin /= A1; 1829 1830 1831 fSumSigma = (Z*z+pN*tN)*GetHadronNucleonXscNS(theProton, pTkin, theProton) + 1832 (z*tN+pN*Z)*GetHadronNucleonXscNS(theProton, pTkin, theNeutron); 1833 1834 G4cout<<"fSumSigma = "<<fSumSigma/CLHEP::millibarn<<" mb"<<G4endl; 1835 G4cout<<"pi*R2 = "<<CLHEP::pi*fNuclearRadiusSquare/CLHEP::millibarn<<" mb"<<G4endl; 1836 kR12 = fWaveVector*std::sqrt(fNuclearRadiusSquare); 1837 G4cout<<"k*sqrt(R2) = "<<kR12<<" "<<G4endl; 1838 fMaxL = (G4int(kR12)+1)*4; 1839 G4cout<<"fMaxL = "<<fMaxL<<" "<<G4endl; 1840 1841 if( z ) 1842 { 1843 a = partMom/m1; // beta*gamma for m1 1844 fBeta = a/std::sqrt(1+a*a); 1845 fZommerfeld = CalculateZommerfeld( fBeta, z, fAtomicNumber); 1846 fAm = CalculateAm( partMom, fZommerfeld, fAtomicNumber); 1847 } 1848 1849 CalculateCoulombPhaseZero(); 1850 1851 1852 return; 1853 } 1854 1855 1856 ///////////////////////////////////////////////////////////////////////////////////// 1857 // 1858 // Returns nucleon-nucleon cross-section based on N. Starkov parametrisation of 1859 // data from mainly http://wwwppds.ihep.su:8001/c5-6A.html database 1860 // projectile nucleon is pParticle with pTkin shooting target nucleon tParticle 1861 1862 G4double 1863 G4NuclNuclDiffuseElastic::GetHadronNucleonXscNS( G4ParticleDefinition* pParticle, 1864 G4double pTkin, 1865 G4ParticleDefinition* tParticle) 1866 { 1867 G4double xsection(0), /*Delta,*/ A0, B0; 1868 G4double hpXsc(0); 1869 G4double hnXsc(0); 1870 1871 1872 G4double targ_mass = tParticle->GetPDGMass(); 1873 G4double proj_mass = pParticle->GetPDGMass(); 1874 1875 G4double proj_energy = proj_mass + pTkin; 1876 G4double proj_momentum = std::sqrt(pTkin*(pTkin+2*proj_mass)); 1877 1878 G4double sMand = CalcMandelstamS ( proj_mass , targ_mass , proj_momentum ); 1879 1880 sMand /= CLHEP::GeV*CLHEP::GeV; // in GeV for parametrisation 1881 proj_momentum /= CLHEP::GeV; 1882 proj_energy /= CLHEP::GeV; 1883 proj_mass /= CLHEP::GeV; 1884 G4double logS = G4Log(sMand); 1885 1886 // General PDG fit constants 1887 1888 1889 // fEtaRatio=Re[f(0)]/Im[f(0)] 1890 1891 if( proj_momentum >= 1.2 ) 1892 { 1893 fEtaRatio = 0.13*(logS - 5.8579332)*G4Pow::GetInstance()->powA(sMand,-0.18); 1894 } 1895 else if( proj_momentum >= 0.6 ) 1896 { 1897 fEtaRatio = -75.5*(G4Pow::GetInstance()->powA(proj_momentum,0.25)-0.95)/ 1898 (G4Pow::GetInstance()->powA(3*proj_momentum,2.2)+1); 1899 } 1900 else 1901 { 1902 fEtaRatio = 15.5*proj_momentum/(27*proj_momentum*proj_momentum*proj_momentum+2); 1903 } 1904 G4cout<<"fEtaRatio = "<<fEtaRatio<<G4endl; 1905 1906 // xsc 1907 1908 if( proj_momentum >= 10. ) // high energy: pp = nn = np 1909 // if( proj_momentum >= 2.) 1910 { 1911 //Delta = 1.; 1912 1913 //if( proj_energy < 40. ) Delta = 0.916+0.0021*proj_energy; 1914 1915 //AR-12Aug2016 if( proj_momentum >= 10.) 1916 { 1917 B0 = 7.5; 1918 A0 = 100. - B0*G4Log(3.0e7); 1919 1920 xsection = A0 + B0*G4Log(proj_energy) - 11 1921 + 103*G4Pow::GetInstance()->powA(2*0.93827*proj_energy + proj_mass*proj_mass+ 1922 0.93827*0.93827,-0.165); // mb 1923 } 1924 } 1925 else // low energy pp = nn != np 1926 { 1927 if(pParticle == tParticle) // pp or nn // nn to be pp 1928 { 1929 if( proj_momentum < 0.73 ) 1930 { 1931 hnXsc = 23 + 50*( G4Pow::GetInstance()->powA( G4Log(0.73/proj_momentum), 3.5 ) ); 1932 } 1933 else if( proj_momentum < 1.05 ) 1934 { 1935 hnXsc = 23 + 40*(G4Log(proj_momentum/0.73))* 1936 (G4Log(proj_momentum/0.73)); 1937 } 1938 else // if( proj_momentum < 10. ) 1939 { 1940 hnXsc = 39.0 + 1941 75*(proj_momentum - 1.2)/(G4Pow::GetInstance()->powA(proj_momentum,3.0) + 0.15); 1942 } 1943 xsection = hnXsc; 1944 } 1945 else // pn to be np 1946 { 1947 if( proj_momentum < 0.8 ) 1948 { 1949 hpXsc = 33+30*G4Pow::GetInstance()->powA(G4Log(proj_momentum/1.3),4.0); 1950 } 1951 else if( proj_momentum < 1.4 ) 1952 { 1953 hpXsc = 33+30*G4Pow::GetInstance()->powA(G4Log(proj_momentum/0.95),2.0); 1954 } 1955 else // if( proj_momentum < 10. ) 1956 { 1957 hpXsc = 33.3+ 1958 20.8*(G4Pow::GetInstance()->powA(proj_momentum,2.0)-1.35)/ 1959 (G4Pow::GetInstance()->powA(proj_momentum,2.50)+0.95); 1960 } 1961 xsection = hpXsc; 1962 } 1963 } 1964 xsection *= CLHEP::millibarn; // parametrised in mb 1965 G4cout<<"xsection = "<<xsection/CLHEP::millibarn<<" mb"<<G4endl; 1966 return xsection; 1967 } 1968 1969 ///////////////////////////////////////////////////////////////// 1970 // 1971 // The ratio el/ruth for Fresnel smooth nucleus profile 1972 1973 G4double G4NuclNuclDiffuseElastic::GetRatioGen(G4double theta) 1974 { 1975 G4double sinThetaR = 2.*fHalfRutThetaTg/(1. + fHalfRutThetaTg2); 1976 G4double dTheta = 0.5*(theta - fRutherfordTheta); 1977 G4double sindTheta = std::sin(dTheta); 1978 1979 G4double prof = Profile(theta); 1980 G4double prof2 = prof*prof; 1981 // G4double profmod = std::abs(prof); 1982 G4double order = std::sqrt(fProfileLambda/sinThetaR/CLHEP::pi)*2.*sindTheta; 1983 1984 order = std::abs(order); // since sin changes sign! 1985 // G4cout<<"order = "<<order<<G4endl; 1986 1987 G4double cosFresnel = GetCint(order); 1988 G4double sinFresnel = GetSint(order); 1989 1990 G4double out; 1991 1992 if ( theta <= fRutherfordTheta ) 1993 { 1994 out = 1. + 0.5*( (0.5-cosFresnel)*(0.5-cosFresnel)+(0.5-sinFresnel)*(0.5-sinFresnel) )*prof2; 1995 out += ( cosFresnel + sinFresnel - 1. )*prof; 1996 } 1997 else 1998 { 1999 out = 0.5*( (0.5-cosFresnel)*(0.5-cosFresnel)+(0.5-sinFresnel)*(0.5-sinFresnel) )*prof2; 2000 } 2001 2002 return out; 2003 } 2004 2005 /////////////////////////////////////////////////////////////////// 2006 // 2007 // For the calculation of arg Gamma(z) one needs complex extension 2008 // of ln(Gamma(z)) 2009 2010 G4complex G4NuclNuclDiffuseElastic::GammaLogarithm(G4complex zz) 2011 { 2012 const G4double cof[6] = { 76.18009172947146, -86.50532032941677, 2013 24.01409824083091, -1.231739572450155, 2014 0.1208650973866179e-2, -0.5395239384953e-5 } ; 2015 G4int j; 2016 G4complex z = zz - 1.0; 2017 G4complex tmp = z + 5.5; 2018 tmp -= (z + 0.5) * std::log(tmp); 2019 G4complex ser = G4complex(1.000000000190015,0.); 2020 2021 for ( j = 0; j <= 5; j++ ) 2022 { 2023 z += 1.0; 2024 ser += cof[j]/z; 2025 } 2026 return -tmp + std::log(2.5066282746310005*ser); 2027 } 2028 2029 ///////////////////////////////////////////////////////////// 2030 // 2031 // Bessel J0 function based on rational approximation from 2032 // J.F. Hart, Computer Approximations, New York, Willey 1968, p. 141 2033 2034 G4double G4NuclNuclDiffuseElastic::BesselJzero(G4double value) 2035 { 2036 G4double modvalue, value2, fact1, fact2, arg, shift, bessel; 2037 2038 modvalue = std::fabs(value); 2039 2040 if ( value < 8.0 && value > -8.0 ) 2041 { 2042 value2 = value*value; 2043 2044 fact1 = 57568490574.0 + value2*(-13362590354.0 2045 + value2*( 651619640.7 2046 + value2*(-11214424.18 2047 + value2*( 77392.33017 2048 + value2*(-184.9052456 ) ) ) ) ); 2049 2050 fact2 = 57568490411.0 + value2*( 1029532985.0 2051 + value2*( 9494680.718 2052 + value2*(59272.64853 2053 + value2*(267.8532712 2054 + value2*1.0 ) ) ) ); 2055 2056 bessel = fact1/fact2; 2057 } 2058 else 2059 { 2060 arg = 8.0/modvalue; 2061 2062 value2 = arg*arg; 2063 2064 shift = modvalue-0.785398164; 2065 2066 fact1 = 1.0 + value2*(-0.1098628627e-2 2067 + value2*(0.2734510407e-4 2068 + value2*(-0.2073370639e-5 2069 + value2*0.2093887211e-6 ) ) ); 2070 2071 fact2 = -0.1562499995e-1 + value2*(0.1430488765e-3 2072 + value2*(-0.6911147651e-5 2073 + value2*(0.7621095161e-6 2074 - value2*0.934945152e-7 ) ) ); 2075 2076 bessel = std::sqrt(0.636619772/modvalue)*(std::cos(shift)*fact1 - arg*std::sin(shift)*fact2 ); 2077 } 2078 return bessel; 2079 } 2080 2081 ///////////////////////////////////////////////////////////// 2082 // 2083 // Bessel J1 function based on rational approximation from 2084 // J.F. Hart, Computer Approximations, New York, Willey 1968, p. 141 2085 2086 G4double G4NuclNuclDiffuseElastic::BesselJone(G4double value) 2087 { 2088 G4double modvalue, value2, fact1, fact2, arg, shift, bessel; 2089 2090 modvalue = std::fabs(value); 2091 2092 if ( modvalue < 8.0 ) 2093 { 2094 value2 = value*value; 2095 2096 fact1 = value*(72362614232.0 + value2*(-7895059235.0 2097 + value2*( 242396853.1 2098 + value2*(-2972611.439 2099 + value2*( 15704.48260 2100 + value2*(-30.16036606 ) ) ) ) ) ); 2101 2102 fact2 = 144725228442.0 + value2*(2300535178.0 2103 + value2*(18583304.74 2104 + value2*(99447.43394 2105 + value2*(376.9991397 2106 + value2*1.0 ) ) ) ); 2107 bessel = fact1/fact2; 2108 } 2109 else 2110 { 2111 arg = 8.0/modvalue; 2112 2113 value2 = arg*arg; 2114 2115 shift = modvalue - 2.356194491; 2116 2117 fact1 = 1.0 + value2*( 0.183105e-2 2118 + value2*(-0.3516396496e-4 2119 + value2*(0.2457520174e-5 2120 + value2*(-0.240337019e-6 ) ) ) ); 2121 2122 fact2 = 0.04687499995 + value2*(-0.2002690873e-3 2123 + value2*( 0.8449199096e-5 2124 + value2*(-0.88228987e-6 2125 + value2*0.105787412e-6 ) ) ); 2126 2127 bessel = std::sqrt( 0.636619772/modvalue)*(std::cos(shift)*fact1 - arg*std::sin(shift)*fact2); 2128 2129 if (value < 0.0) bessel = -bessel; 2130 } 2131 return bessel; 2132 } 2133 2134 // 2135 // 2136 ///////////////////////////////////////////////////////////////////////////////// 2137