/home/cern/BDSIM_new/src/BDSGammaConversionToMuons.cc

00001 //         ------------ G4GammaConversionToMuons physics process ------
00002 //         by H.Burkhardt, S. Kelner and R. Kokoulin, April 2002
00003 //
00004 //
00005 // 07-08-02: missprint in OR condition in DoIt : f1<0 || f1>f1_max ..etc ...
00006 // 25-10-04: migrade to new interfaces of ParticleChange (vi)
00007 // ---------------------------------------------------------------------------
00008 
00009 #include "BDSGammaConversionToMuons.hh"
00010 #include "G4EnergyLossTables.hh"
00011 #include "G4UnitsTable.hh"
00012 #include "G4MuonPlus.hh"
00013 #include "G4MuonMinus.hh"
00014 
00015 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00016 
00017 using namespace std;
00018 
00019 BDSGammaConversionToMuons::BDSGammaConversionToMuons(const G4String& processName,
00020     G4ProcessType type):G4VDiscreteProcess (processName, type),
00021     LowestEnergyLimit (4*G4MuonPlus::MuonPlus()->GetPDGMass()), // 4*Mmuon
00022     HighestEnergyLimit(1e21*eV), // ok to 1e21eV=1e12GeV, then LPM suppression
00023     CrossSecFactor(1.)
00024 { }
00025 
00026 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00027 
00028 // destructor
00029 
00030 BDSGammaConversionToMuons::~BDSGammaConversionToMuons() // (empty) destructor
00031 { }
00032 
00033 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00034 
00035 G4bool BDSGammaConversionToMuons::IsApplicable(
00036                                         const G4ParticleDefinition& particle)
00037 {
00038    return ( &particle == G4Gamma::Gamma() );
00039 }
00040 
00041 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
00042 
00043 void BDSGammaConversionToMuons::BuildPhysicsTable(const G4ParticleDefinition&)
00044 // Build cross section and mean free path tables
00045 {  //here no tables, just calling PrintInfoDefinition
00046    PrintInfoDefinition();
00047 }
00048 
00049 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
00050 
00051 G4double BDSGammaConversionToMuons::GetMeanFreePath(const G4Track& aTrack,
00052                                               G4double, G4ForceCondition*)
00053 
00054 // returns the photon mean free path in GEANT4 internal units
00055 // (MeanFreePath is a private member of the class)
00056 
00057 {
00058    const G4DynamicParticle* aDynamicGamma = aTrack.GetDynamicParticle();
00059    G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
00060    G4Material* aMaterial = aTrack.GetMaterial();
00061 
00062    if (GammaEnergy <  LowestEnergyLimit)
00063      MeanFreePath = DBL_MAX;
00064    else
00065      MeanFreePath = ComputeMeanFreePath(GammaEnergy,aMaterial);
00066 
00067    return MeanFreePath * 1.e-4;
00068 }
00069 
00070 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
00071 
00072 G4double BDSGammaConversionToMuons::ComputeMeanFreePath(G4double GammaEnergy,
00073                                                        G4Material* aMaterial)
00074 
00075 // computes and returns the photon mean free path in GEANT4 internal units
00076 {
00077   const G4ElementVector* theElementVector = aMaterial->GetElementVector();
00078   const G4double* NbOfAtomsPerVolume = aMaterial->GetVecNbOfAtomsPerVolume();
00079 
00080   G4double SIGMA = 0 ;
00081 
00082   for ( size_t i=0 ; i < aMaterial->GetNumberOfElements() ; i++ )
00083   {
00084     G4double AtomicZ = (*theElementVector)[i]->GetZ();
00085     G4double AtomicA = (*theElementVector)[i]->GetA()/(g/mole);
00086     SIGMA += NbOfAtomsPerVolume[i] *
00087       ComputeCrossSectionPerAtom(GammaEnergy,AtomicZ,AtomicA);
00088   }
00089   return SIGMA > DBL_MIN ? 1./SIGMA : DBL_MAX;
00090 }
00091 
00092 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
00093 
00094 G4double BDSGammaConversionToMuons::GetCrossSectionPerAtom(
00095                                    const G4DynamicParticle* aDynamicGamma,
00096                                          G4Element*         anElement)
00097 
00098 // gives the total cross section per atom in GEANT4 internal units
00099 {
00100    G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
00101    G4double AtomicZ = anElement->GetZ();
00102    G4double AtomicA = anElement->GetA()/(g/mole);
00103    G4double crossSection =
00104         ComputeCrossSectionPerAtom(GammaEnergy,AtomicZ,AtomicA);
00105    return crossSection;
00106 }
00107 
00108 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00109 
00110 G4double BDSGammaConversionToMuons::ComputeCrossSectionPerAtom(
00111                          G4double Egam, G4double Z, G4double A)
00112                          
00113 // Calculates the microscopic cross section in GEANT4 internal units.
00114 // Total cross section parametrisation from H.Burkhardt
00115 // It gives a good description at any energy (from 0 to 10**21 eV)
00116 { static const G4double Mmuon=G4MuonPlus::MuonPlus()->GetPDGMass();
00117   static const G4double Mele=electron_mass_c2;
00118   static const G4double Rc=elm_coupling/Mmuon; // classical particle radius
00119   static const G4double sqrte=sqrt(exp(1.));
00120   static const G4double PowSat=-0.88;
00121 
00122   static G4double CrossSection = 0.0 ;
00123 
00124   if ( A < 1. ) return 0;
00125   if ( Egam < 4*Mmuon ) return 0 ; // below threshold return 0
00126 
00127   static G4double EgamLast=0,Zlast=0,PowThres,Ecor,B,Dn,Zthird,Winfty,WMedAppr,
00128       Wsatur,sigfac;
00129   
00130   if(Zlast==Z && Egam==EgamLast) return CrossSection; // already calculated
00131   EgamLast=Egam;
00132   
00133   if(Zlast!=Z) // new element
00134   { Zlast=Z;
00135     if(Z==1) // special case of Hydrogen
00136     { B=202.4;
00137       Dn=1.49;
00138     }
00139     else
00140     { B=183.;
00141       Dn=1.54*pow(A,0.27);
00142     }
00143     Zthird=pow(Z,-1./3.); // Z**(-1/3)
00144     Winfty=B*Zthird*Mmuon/(Dn*Mele);
00145     WMedAppr=1./(4.*Dn*sqrte*Mmuon);
00146     Wsatur=Winfty/WMedAppr;
00147     sigfac=4.*fine_structure_const*Z*Z*Rc*Rc;
00148     PowThres=1.479+0.00799*Dn;
00149     Ecor=-18.+4347./(B*Zthird);
00150   }
00151   G4double CorFuc=1.+.04*log(1.+Ecor/Egam);
00152   G4double Eg=pow(1.-4.*Mmuon/Egam,PowThres)*pow( pow(Wsatur,PowSat)+
00153               pow(Egam,PowSat),1./PowSat); // threshold and saturation
00154   CrossSection=7./9.*sigfac*log(1.+WMedAppr*CorFuc*Eg);
00155   CrossSection*=CrossSecFactor; // increase the CrossSection by  (by default 1)
00156   return CrossSection;
00157 }
00158 
00159 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00160 
00161 void BDSGammaConversionToMuons::SetCrossSecFactor(G4double fac)
00162 // Set the factor to artificially increase the cross section
00163 { CrossSecFactor=fac;
00164   G4cout << "The cross section for GammaConversionToMuons is artificially "
00165          << "increased by the CrossSecFactor=" << CrossSecFactor << G4endl;
00166 }
00167 
00168 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00169 
00170 G4VParticleChange* BDSGammaConversionToMuons::PostStepDoIt(
00171                                                         const G4Track& aTrack,
00172                                                         const G4Step&  aStep)
00173 //
00174 // generation of gamma->mu+mu-
00175 //
00176 {
00177   aParticleChange.Initialize(aTrack);
00178   G4Material* aMaterial = aTrack.GetMaterial();
00179 
00180   static const G4double Mmuon=G4MuonPlus::MuonPlus()->GetPDGMass();
00181   static const G4double Mele=electron_mass_c2;
00182   static const G4double sqrte=sqrt(exp(1.));
00183 
00184   // current Gamma energy and direction, return if energy too low
00185   const G4DynamicParticle *aDynamicGamma = aTrack.GetDynamicParticle();
00186   G4double Egam = aDynamicGamma->GetKineticEnergy();
00187   if (Egam < 4*Mmuon) return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
00188   G4ParticleMomentum GammaDirection = aDynamicGamma->GetMomentumDirection();
00189 
00190   // select randomly one element constituting the material
00191   const G4Element& anElement = *SelectRandomAtom(aDynamicGamma, aMaterial);
00192   G4double Z = anElement.GetZ();
00193   G4double A = anElement.GetA()/(g/mole);
00194 
00195   static G4double Zlast=0,B,Dn,Zthird,Winfty,A027,C1Num2,C2Term2;
00196   if(Zlast!=Z) // the element has changed
00197   { Zlast=Z;
00198     if(Z==1) // special case of Hydrogen
00199     { B=202.4;
00200       Dn=1.49;
00201     }
00202     else
00203     { B=183.;
00204       Dn=1.54*pow(A,0.27);
00205     }
00206     Zthird=pow(Z,-1./3.); // Z**(-1/3)
00207     Winfty=B*Zthird*Mmuon/(Dn*Mele);
00208     A027=pow(A,0.27);
00209     G4double C1Num=0.35*A027;
00210     C1Num2=C1Num*C1Num;
00211     C2Term2=Mele/(183.*Zthird*Mmuon);
00212   }
00213 
00214   G4double GammaMuonInv=Mmuon/Egam;
00215   G4double sqrtx=sqrt(.25-GammaMuonInv);
00216   G4double xmax=.5+sqrtx;
00217   G4double xmin=.5-sqrtx;
00218 
00219   // generate xPlus according to the differential cross section by rejection
00220   G4double Ds2=(Dn*sqrte-2.);
00221   G4double sBZ=sqrte*B*Zthird/Mele;
00222   G4double LogWmaxInv=1./log(Winfty*(1.+2.*Ds2*GammaMuonInv)
00223                              /(1.+2.*sBZ*Mmuon*GammaMuonInv));
00224   G4double xPlus,xMinus,xPM,result,W;
00225   do
00226   { xPlus=xmin+G4UniformRand()*(xmax-xmin);
00227     xMinus=1.-xPlus;
00228     xPM=xPlus*xMinus;
00229     G4double del=Mmuon*Mmuon/(2.*Egam*xPM);
00230     W=Winfty*(1.+Ds2*del/Mmuon)/(1.+sBZ*del);
00231     if(W<1.) W=1.; // to avoid negative cross section at xmin
00232     G4double xxp=1.-4./3.*xPM; // the main xPlus dependence
00233     result=xxp*log(W)*LogWmaxInv;
00234     if(result>1.)
00235     { 
00236       G4Exception("BDSGammaConversionToMuons::PostStepDoIt: Error in dSigxPlusGen, result > 1");
00237       exit(1);
00238     }
00239   }
00240   while (G4UniformRand() > result);
00241 
00242   // now generate the angular variables via the auxilary variables t,psi,rho
00243   G4double t;
00244   G4double psi;
00245   G4double rho;
00246 
00247   G4double thetaPlus,thetaMinus,phiHalf; // final angular variables
00248 
00249   do      // t, psi, rho generation start  (while angle < pi)
00250   {
00251     //generate t by the rejection method
00252     G4double C1=C1Num2* GammaMuonInv/xPM;
00253     G4double f1_max=(1.-xPM) / (1.+C1);
00254     G4double f1; // the probability density
00255     do
00256     { t=G4UniformRand();
00257       f1=(1.-2.*xPM+4.*xPM*t*(1.-t)) / (1.+C1/(t*t));
00258       if(f1<0 || f1> f1_max) // should never happend
00259       {
00260         G4Exception("BDSGammaConversionToMuons::PostStepDoIt: f1 outside allowed range");
00261         exit(1);
00262       }
00263     }
00264     while ( G4UniformRand()*f1_max > f1);
00265     // generate psi by the rejection method
00266     G4double f2_max=1.-2.*xPM*(1.-4.*t*(1.-t));
00267 
00268     // long version
00269     G4double f2;
00270     do
00271     { psi=2.*pi*G4UniformRand();
00272       f2=1.-2.*xPM+4.*xPM*t*(1.-t)*(1.+cos(2.*psi));
00273       if(f2<0 || f2> f2_max) // should never happend
00274       { 
00275         G4Exception("BDSGammaConversionToMuons::PostStepDoIt: f2 outside allowed range");
00276         exit(1);
00277       }
00278     }
00279     while ( G4UniformRand()*f2_max > f2);
00280 
00281     // generate rho by direct transformation
00282     G4double C2Term1=GammaMuonInv/(2.*xPM*t);
00283     G4double C2=4./sqrt(xPM)*pow(C2Term1*C2Term1+C2Term2*C2Term2,2.);
00284     G4double rhomax=1.9/A027*(1./t-1.);
00285     G4double beta=log( (C2+pow(rhomax,4.))/C2 );
00286     rho=pow(C2 *( exp(beta*G4UniformRand())-1. ) ,0.25);
00287 
00288     //now get from t and psi the kinematical variables
00289     G4double u=sqrt(1./t-1.);
00290     G4double xiHalf=0.5*rho*cos(psi);
00291     phiHalf=0.5*rho/u*sin(psi);
00292 
00293     thetaPlus =GammaMuonInv*(u+xiHalf)/xPlus;
00294     thetaMinus=GammaMuonInv*(u-xiHalf)/xMinus;
00295 
00296   } while ( std::abs(thetaPlus)>pi || std::abs(thetaMinus) >pi);
00297 
00298   // now construct the vectors
00299   // azimuthal symmetry, take phi0 at random between 0 and 2 pi
00300   G4double phi0=2.*pi*G4UniformRand(); 
00301   G4double EPlus=xPlus*Egam;
00302   G4double EMinus=xMinus*Egam;
00303 
00304   // mu+ mu- directions for gamma in z-direction
00305   G4ThreeVector MuPlusDirection  ( sin(thetaPlus) *cos(phi0+phiHalf),
00306                    sin(thetaPlus)  *sin(phi0+phiHalf), cos(thetaPlus) );
00307   G4ThreeVector MuMinusDirection (-sin(thetaMinus)*cos(phi0-phiHalf),
00308                   -sin(thetaMinus) *sin(phi0-phiHalf), cos(thetaMinus) );
00309   // rotate to actual gamma direction
00310   MuPlusDirection.rotateUz(GammaDirection);
00311   MuMinusDirection.rotateUz(GammaDirection);
00312   aParticleChange.SetNumberOfSecondaries(2);
00313   // create G4DynamicParticle object for the particle1
00314   G4DynamicParticle* aParticle1= new G4DynamicParticle(
00315                            G4MuonPlus::MuonPlus(),MuPlusDirection,EPlus-Mmuon);
00316   aParticleChange.AddSecondary(aParticle1);
00317   // create G4DynamicParticle object for the particle2
00318   G4DynamicParticle* aParticle2= new G4DynamicParticle(
00319                        G4MuonMinus::MuonMinus(),MuMinusDirection,EMinus-Mmuon);
00320   aParticleChange.AddSecondary(aParticle2);
00321   //
00322   // Kill the incident photon
00323   //
00324   aParticleChange.ProposeMomentumDirection( 0., 0., 0. ) ;
00325   aParticleChange.ProposeEnergy( 0. ) ;
00326   aParticleChange.ProposeTrackStatus( fStopAndKill ) ;
00327   //  Reset NbOfInteractionLengthLeft and return aParticleChange
00328   return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep );
00329 }
00330 
00331 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00332 
00333 G4Element* BDSGammaConversionToMuons::SelectRandomAtom(
00334                                         const G4DynamicParticle* aDynamicGamma,
00335                                               G4Material* aMaterial)
00336 {
00337   // select randomly 1 element within the material, invoked by PostStepDoIt
00338 
00339   const G4int NumberOfElements            = aMaterial->GetNumberOfElements();
00340   const G4ElementVector* theElementVector = aMaterial->GetElementVector();
00341   if (NumberOfElements == 1) return (*theElementVector)[0];
00342 
00343   const G4double* NbOfAtomsPerVolume = aMaterial->GetVecNbOfAtomsPerVolume();
00344 
00345   G4double PartialSumSigma = 0. ;
00346   G4double rval = G4UniformRand()/MeanFreePath;
00347 
00348 
00349   for ( G4int i=0 ; i < NumberOfElements ; i++ )
00350       { PartialSumSigma += NbOfAtomsPerVolume[i] *
00351                  GetCrossSectionPerAtom(aDynamicGamma, (*theElementVector)[i]);
00352         if (rval <= PartialSumSigma) return ((*theElementVector)[i]);
00353       }
00354   G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
00355        << "' has no elements, NULL pointer returned." << G4endl;
00356   return NULL;
00357 }
00358 
00359 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
00360 
00361 void BDSGammaConversionToMuons::PrintInfoDefinition()
00362 {
00363   G4String comments ="gamma->mu+mu- Bethe Heitler process.\n";
00364   G4cout << G4endl << GetProcessName() << ":  " << comments
00365          << "        good cross section parametrization from "
00366          << G4BestUnit(LowestEnergyLimit,"Energy")
00367          << " to " << HighestEnergyLimit/GeV << " GeV for all Z." << G4endl;
00368 }
00369 
00370 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....

Generated on Wed Mar 5 17:25:22 2008 for BDSIM by  doxygen 1.5.3