Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/coherent_elastic/src/G4NuclNuclDiffuseElastic.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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