G4PAIModel.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 // $Id$
00027 //
00028 // -------------------------------------------------------------------
00029 //
00030 // GEANT4 Class
00031 // File name:     G4PAIModel.cc
00032 //
00033 // Author: Vladimir.Grichine@cern.ch on base of Vladimir Ivanchenko model interface
00034 //
00035 // Creation date: 05.10.2003
00036 //
00037 // Modifications:
00038 //
00039 // 17.08.04 V.Grichine, bug fixed for Tkin<=0 in SampleSecondary
00040 // 16.08.04 V.Grichine, bug fixed in massRatio for DEDX, CrossSection, SampleSecondary
00041 // 08.04.05 Major optimisation of internal interfaces (V.Ivantchenko)
00042 // 26.07.09 Fixed logic to work with several materials (V.Ivantchenko)
00043 // 21.11.10 V. Grichine verbose flag for protons and G4PAYySection to check sandia table 
00044 //
00045 
00046 #include "G4PAIModel.hh"
00047 
00048 #include "G4PhysicalConstants.hh"
00049 #include "G4SystemOfUnits.hh"
00050 #include "G4Region.hh"
00051 #include "G4PhysicsLogVector.hh"
00052 #include "G4PhysicsFreeVector.hh"
00053 #include "G4PhysicsTable.hh"
00054 #include "G4ProductionCutsTable.hh"
00055 #include "G4MaterialCutsCouple.hh"
00056 #include "G4MaterialTable.hh"
00057 #include "G4SandiaTable.hh"
00058 #include "G4OrderedTable.hh"
00059 
00060 #include "Randomize.hh"
00061 #include "G4Electron.hh"
00062 #include "G4Positron.hh"
00063 #include "G4Poisson.hh"
00064 #include "G4Step.hh"
00065 #include "G4Material.hh"
00066 #include "G4DynamicParticle.hh"
00067 #include "G4ParticleDefinition.hh"
00068 #include "G4ParticleChangeForLoss.hh"
00069 
00071 
00072 using namespace std;
00073 
00074 G4PAIModel::G4PAIModel(const G4ParticleDefinition* p, const G4String& nam)
00075   : G4VEmModel(nam),G4VEmFluctuationModel(nam),
00076   fVerbose(0),
00077   fLowestGamma(1.005),
00078   fHighestGamma(10000.),
00079   fTotBin(200),
00080   fMeanNumber(20),
00081   fParticle(0),
00082   fHighKinEnergy(100.*TeV),
00083   fTwoln10(2.0*log(10.0)),
00084   fBg2lim(0.0169),
00085   fTaulim(8.4146e-3)
00086 {  
00087   fElectron = G4Electron::Electron();
00088   fPositron = G4Positron::Positron();
00089 
00090   fPAItransferTable  = 0;
00091   fPAIdEdxTable      = 0;
00092   fSandiaPhotoAbsCof = 0;
00093   fdEdxVector        = 0;
00094   fLambdaVector      = 0;
00095   fdNdxCutVector     = 0;
00096   fParticleEnergyVector = 0;
00097   fSandiaIntervalNumber = 0;
00098   fMatIndex = 0;
00099   fDeltaCutInKinEnergy = 0.0;
00100   fParticleChange = 0;
00101   fMaterial = 0;
00102   fCutCouple = 0;
00103 
00104   if(p) { SetParticle(p); }
00105   else  { SetParticle(fElectron); }
00106 
00107   isInitialised      = false;
00108 }
00109 
00111 
00112 G4PAIModel::~G4PAIModel()
00113 {
00114   //  G4cout << "PAI: start destruction" << G4endl;
00115   if(fParticleEnergyVector) delete fParticleEnergyVector;
00116   if(fdEdxVector)           delete fdEdxVector ;
00117   if(fLambdaVector)         delete fLambdaVector;
00118   if(fdNdxCutVector)        delete fdNdxCutVector;
00119 
00120   if( fPAItransferTable )
00121     {
00122       fPAItransferTable->clearAndDestroy();
00123       delete fPAItransferTable ;
00124     }
00125   if( fPAIdEdxTable )
00126     {
00127       fPAIdEdxTable->clearAndDestroy();
00128       delete fPAIdEdxTable ;
00129     }
00130   if(fSandiaPhotoAbsCof)
00131     {
00132       for(G4int i=0;i<fSandiaIntervalNumber;i++)
00133         {
00134           delete[] fSandiaPhotoAbsCof[i];
00135         }
00136       delete[] fSandiaPhotoAbsCof;
00137     }
00138   //G4cout << "PAI: end destruction" << G4endl;
00139 }
00140 
00142 
00143 void G4PAIModel::SetParticle(const G4ParticleDefinition* p)
00144 {
00145   if(fParticle == p) { return; }
00146   fParticle = p;
00147   fMass = fParticle->GetPDGMass();
00148   fSpin = fParticle->GetPDGSpin();
00149   G4double q = fParticle->GetPDGCharge()/eplus;
00150   fChargeSquare = q*q;
00151   fLowKinEnergy = 0.2*MeV*fMass/proton_mass_c2;
00152   fRatio = electron_mass_c2/fMass;
00153   fQc = fMass/fRatio;
00154   fLowestKineticEnergy  = fMass*(fLowestGamma  - 1.0);
00155   fHighestKineticEnergy = fMass*(fHighestGamma - 1.0);
00156 }
00157 
00159 
00160 void G4PAIModel::Initialise(const G4ParticleDefinition* p,
00161                             const G4DataVector&)
00162 {
00163   if( fVerbose > 0 && p->GetParticleName()=="proton") 
00164   {
00165     G4cout<<"G4PAIModel::Initialise for "<<p->GetParticleName()<<G4endl;
00166     fPAIySection.SetVerbose(1);
00167   }
00168   else fPAIySection.SetVerbose(0);
00169 
00170   if(isInitialised) { return; }
00171   isInitialised = true;
00172 
00173   SetParticle(p);
00174 
00175   fParticleEnergyVector = new G4PhysicsLogVector(fLowestKineticEnergy,
00176                                                  fHighestKineticEnergy,
00177                                                  fTotBin);
00178 
00179   fParticleChange = GetParticleChangeForLoss();
00180 
00181   // Prepare initialization
00182   const G4ProductionCutsTable* theCoupleTable =
00183         G4ProductionCutsTable::GetProductionCutsTable();
00184   const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
00185   size_t numOfMat   = G4Material::GetNumberOfMaterials();
00186   size_t numRegions = fPAIRegionVector.size();
00187 
00188   for(size_t iReg = 0; iReg < numRegions; ++iReg) // region loop
00189   {
00190     const G4Region* curReg = fPAIRegionVector[iReg];
00191 
00192     for(size_t jMat = 0; jMat < numOfMat; ++jMat) // region material loop
00193     {
00194       fMaterial  = (*theMaterialTable)[jMat];
00195       fCutCouple = theCoupleTable->GetMaterialCutsCouple( fMaterial, 
00196                                           curReg->GetProductionCuts() );
00197       //G4cout << "Reg <" <<curReg->GetName() << ">  mat <" 
00198       //             << fMaterial->GetName() << ">  fCouple= " 
00199       //             << fCutCouple<<"  " << p->GetParticleName() <<G4endl;
00200       if( fCutCouple ) 
00201       {
00202         fMaterialCutsCoupleVector.push_back(fCutCouple);
00203 
00204         fPAItransferTable = new G4PhysicsTable(fTotBin+1);
00205         fPAIdEdxTable = new G4PhysicsTable(fTotBin+1);
00206 
00207         fDeltaCutInKinEnergy = 
00208           (*theCoupleTable->GetEnergyCutsVector(1))[fCutCouple->GetIndex()];
00209      
00210         //ComputeSandiaPhotoAbsCof();
00211         BuildPAIonisationTable();
00212 
00213         fPAIxscBank.push_back(fPAItransferTable);
00214         fPAIdEdxBank.push_back(fPAIdEdxTable);
00215         fdEdxTable.push_back(fdEdxVector);
00216 
00217         BuildLambdaVector();
00218         fdNdxCutTable.push_back(fdNdxCutVector);
00219         fLambdaTable.push_back(fLambdaVector);
00220       }
00221     }
00222   }
00223 }
00224 
00226 
00227 void G4PAIModel::InitialiseMe(const G4ParticleDefinition*) 
00228 {}
00229 
00231 
00232 void G4PAIModel::ComputeSandiaPhotoAbsCof()
00233 { 
00234   G4int i, j;
00235   const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
00236 
00237   G4SandiaTable thisMaterialSandiaTable(fMatIndex) ;
00238   G4int numberOfElements = 
00239     (*theMaterialTable)[fMatIndex]->GetNumberOfElements();
00240 
00241   G4int* thisMaterialZ = new G4int[numberOfElements] ;
00242 
00243   for(i=0;i<numberOfElements;i++)  
00244   {
00245     thisMaterialZ[i] = 
00246     (G4int)(*theMaterialTable)[fMatIndex]->GetElement(i)->GetZ() ;
00247   }  
00248   fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaIntervals
00249                            (thisMaterialZ,numberOfElements) ;
00250 
00251   fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaMixing
00252                            ( thisMaterialZ ,
00253                              (*theMaterialTable)[fMatIndex]->GetFractionVector() ,
00254                              numberOfElements,fSandiaIntervalNumber) ;
00255    
00256   fSandiaPhotoAbsCof = new G4double*[fSandiaIntervalNumber] ;
00257 
00258   for(i=0; i<fSandiaIntervalNumber; i++)  
00259   {
00260     fSandiaPhotoAbsCof[i] = new G4double[5];
00261   }
00262    
00263   for( i = 0 ; i < fSandiaIntervalNumber ; i++ )
00264   {
00265     fSandiaPhotoAbsCof[i][0] = thisMaterialSandiaTable.GetPhotoAbsorpCof(i+1,0); 
00266 
00267     for( j = 1; j < 5 ; j++ )
00268     {
00269       fSandiaPhotoAbsCof[i][j] = thisMaterialSandiaTable.GetPhotoAbsorpCof(i+1,j)*
00270                  (*theMaterialTable)[fMatIndex]->GetDensity() ;
00271     }
00272   }
00273   delete[] thisMaterialZ;
00274 }
00275 
00277 //
00278 // Build tables for the ionization energy loss
00279 //  the tables are built for MATERIALS
00280 //                           *********
00281 
00282 void G4PAIModel::BuildPAIonisationTable()
00283 {
00284   G4double LowEdgeEnergy , ionloss ;
00285   G4double tau, Tmax, Tmin, Tkin, deltaLow, /*gamma,*/ bg2 ;
00286 
00287   fdEdxVector = new G4PhysicsLogVector( fLowestKineticEnergy,
00288                                         fHighestKineticEnergy,
00289                                         fTotBin);
00290   G4SandiaTable* sandia = fMaterial->GetSandiaTable();
00291 
00292   Tmin = sandia->GetSandiaCofForMaterialPAI(0,0)*keV;
00293   deltaLow = 100.*eV; // 0.5*eV ;
00294 
00295   for (G4int i = 0 ; i <= fTotBin ; i++)  //The loop for the kinetic energy
00296   {
00297     LowEdgeEnergy = fParticleEnergyVector->GetLowEdgeEnergy(i) ;
00298     tau = LowEdgeEnergy/fMass ;
00299     //gamma = tau +1. ;
00300     // G4cout<<"gamma = "<<gamma<<endl ;
00301     bg2 = tau*( tau + 2. );
00302     Tmax = MaxSecondaryEnergy(fParticle, LowEdgeEnergy); 
00303     //    Tmax = std::min(fDeltaCutInKinEnergy, Tmax);
00304     Tkin = Tmax ;
00305 
00306     if ( Tmax < Tmin + deltaLow )  // low energy safety
00307       Tkin = Tmin + deltaLow ;
00308 
00309     fPAIySection.Initialize(fMaterial, Tkin, bg2);
00310 
00311     // G4cout<<"ionloss = "<<ionloss*cm/keV<<" keV/cm"<<endl ;
00312     // G4cout<<"n1 = "<<protonPAI.GetIntegralPAIxSection(1)*cm<<" 1/cm"<<endl ;
00313     // G4cout<<"protonPAI.GetSplineSize() = "<<
00314     //    protonPAI.GetSplineSize()<<G4endl<<G4endl ;
00315 
00316     G4int n = fPAIySection.GetSplineSize();
00317     G4PhysicsFreeVector* transferVector = new G4PhysicsFreeVector(n) ;
00318     G4PhysicsFreeVector* dEdxVector = new G4PhysicsFreeVector(n);
00319 
00320     for( G4int k = 0 ; k < n; k++ )
00321     {
00322       transferVector->PutValue( k ,
00323                                 fPAIySection.GetSplineEnergy(k+1),
00324                                 fPAIySection.GetIntegralPAIySection(k+1) ) ;
00325       dEdxVector->PutValue( k ,
00326                                 fPAIySection.GetSplineEnergy(k+1),
00327                                 fPAIySection.GetIntegralPAIdEdx(k+1) ) ;
00328     }
00329     ionloss = fPAIySection.GetMeanEnergyLoss() ;   //  total <dE/dx>
00330 
00331     if ( ionloss < DBL_MIN) { ionloss = 0.0; }
00332     fdEdxVector->PutValue(i,ionloss) ;
00333 
00334     fPAItransferTable->insertAt(i,transferVector) ;
00335     fPAIdEdxTable->insertAt(i,dEdxVector) ;
00336 
00337   }                                        // end of Tkin loop
00338 }
00339 
00341 //
00342 // Build mean free path tables for the delta ray production process
00343 //     tables are built for MATERIALS
00344 //
00345 
00346 void G4PAIModel::BuildLambdaVector()
00347 {
00348   fLambdaVector = new G4PhysicsLogVector( fLowestKineticEnergy,
00349                                           fHighestKineticEnergy,
00350                                           fTotBin                ) ;
00351   fdNdxCutVector = new G4PhysicsLogVector( fLowestKineticEnergy,
00352                                           fHighestKineticEnergy,
00353                                           fTotBin                ) ;
00354   if(fVerbose > 1)
00355   {
00356     G4cout<<"PAIModel DeltaCutInKineticEnergyNow = "
00357           <<fDeltaCutInKinEnergy/keV<<" keV"<<G4endl;
00358   }
00359   for (G4int i = 0 ; i <= fTotBin ; i++ )
00360   {
00361     G4double dNdxCut = GetdNdxCut(i,fDeltaCutInKinEnergy) ;
00362     //G4cout << "i= " << i << " x= " << dNdxCut << G4endl;
00363     if(dNdxCut < 0.0) dNdxCut = 0.0; 
00364     //    G4double lambda = dNdxCut <= DBL_MIN ? DBL_MAX: 1.0/dNdxCut ;
00365     G4double lambda = DBL_MAX;
00366     if(dNdxCut > 0.0) lambda = 1.0/dNdxCut;
00367 
00368     fLambdaVector->PutValue(i, lambda) ;
00369     fdNdxCutVector->PutValue(i, dNdxCut) ;
00370   }
00371 }
00372 
00374 //
00375 // Returns integral PAI cross section for energy transfers >= transferCut
00376 
00377 G4double  
00378 G4PAIModel::GetdNdxCut( G4int iPlace, G4double transferCut)
00379 { 
00380   G4int iTransfer;
00381   G4double x1, x2, y1, y2, dNdxCut;
00382   // G4cout<<"iPlace = "<<iPlace<<"; "<<"transferCut = "<<transferCut<<G4endl;
00383   // G4cout<<"size = "<<G4int((*fPAItransferTable)(iPlace)->GetVectorLength())
00384   //           <<G4endl;  
00385   for( iTransfer = 0 ; 
00386        iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()) ; 
00387        iTransfer++)
00388   {
00389     if(transferCut <= (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer))
00390     {
00391       break ;
00392     }
00393   }  
00394   if ( iTransfer >= G4int((*fPAItransferTable)(iPlace)->GetVectorLength()) )
00395   {
00396       iTransfer = (*fPAItransferTable)(iPlace)->GetVectorLength() - 1 ;
00397   }
00398   y1 = (*(*fPAItransferTable)(iPlace))(iTransfer-1) ;
00399   y2 = (*(*fPAItransferTable)(iPlace))(iTransfer) ;
00400   if(y1 < 0.0) y1 = 0.0;
00401   if(y2 < 0.0) y2 = 0.0;
00402   // G4cout<<"y1 = "<<y1<<"; "<<"y2 = "<<y2<<G4endl;
00403   x1 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
00404   x2 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
00405   // G4cout<<"x1 = "<<x1<<"; "<<"x2 = "<<x2<<G4endl;
00406 
00407   if ( y1 == y2 )    dNdxCut = y2 ;
00408   else
00409   {
00410     //  if ( x1 == x2  ) dNdxCut = y1 + (y2 - y1)*G4UniformRand() ;
00411     //    if ( std::abs(x1-x2) <= eV  ) dNdxCut = y1 + (y2 - y1)*G4UniformRand() ;
00412     if ( std::abs(x1-x2) <= eV  ) dNdxCut = y1 + (y2 - y1)*0.5 ;
00413     else             dNdxCut = y1 + (transferCut - x1)*(y2 - y1)/(x2 - x1) ;      
00414   }
00415   //  G4cout<<""<<dNdxCut<<G4endl;
00416   if(dNdxCut < 0.0) dNdxCut = 0.0; 
00417   return dNdxCut ;
00418 }
00420 //
00421 // Returns integral dEdx for energy transfers >= transferCut
00422 
00423 G4double  
00424 G4PAIModel::GetdEdxCut( G4int iPlace, G4double transferCut)
00425 { 
00426   G4int iTransfer;
00427   G4double x1, x2, y1, y2, dEdxCut;
00428   //G4cout<<"iPlace = "<<iPlace<<"; "<<"transferCut = "<<transferCut<<G4endl;
00429   // G4cout<<"size = "<<G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength())
00430   //           <<G4endl;  
00431   for( iTransfer = 0 ; 
00432        iTransfer < G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength()) ; 
00433        iTransfer++)
00434   {
00435     if(transferCut <= (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer))
00436     {
00437       break ;
00438     }
00439   }  
00440   if ( iTransfer >= G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength()) )
00441   {
00442       iTransfer = (*fPAIdEdxTable)(iPlace)->GetVectorLength() - 1 ;
00443   }
00444   y1 = (*(*fPAIdEdxTable)(iPlace))(iTransfer-1) ;
00445   y2 = (*(*fPAIdEdxTable)(iPlace))(iTransfer) ;
00446   if(y1 < 0.0) y1 = 0.0;
00447   if(y2 < 0.0) y2 = 0.0;
00448   //G4cout<<"y1 = "<<y1<<"; "<<"y2 = "<<y2<<G4endl;
00449   x1 = (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
00450   x2 = (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
00451   //G4cout<<"x1 = "<<x1<<"; "<<"x2 = "<<x2<<G4endl;
00452 
00453   if ( y1 == y2 )    dEdxCut = y2 ;
00454   else
00455   {
00456     //  if ( x1 == x2  ) dEdxCut = y1 + (y2 - y1)*G4UniformRand() ;
00457     //    if ( std::abs(x1-x2) <= eV  ) dEdxCut = y1 + (y2 - y1)*G4UniformRand() ;
00458     if ( std::abs(x1-x2) <= eV  ) dEdxCut = y1 + (y2 - y1)*0.5 ;
00459     else             dEdxCut = y1 + (transferCut - x1)*(y2 - y1)/(x2 - x1) ;      
00460   }
00461   //G4cout<<""<<dEdxCut<<G4endl;
00462   if(dEdxCut < 0.0) dEdxCut = 0.0; 
00463   return dEdxCut ;
00464 }
00465 
00467 
00468 G4double G4PAIModel::ComputeDEDXPerVolume(const G4Material*,
00469                                           const G4ParticleDefinition* p,
00470                                           G4double kineticEnergy,
00471                                           G4double cutEnergy)
00472 {
00473   G4int iTkin,iPlace;
00474   
00475   //G4double cut = std::min(MaxSecondaryEnergy(p, kineticEnergy), cutEnergy);
00476   G4double cut = cutEnergy;
00477 
00478   G4double massRatio  = fMass/p->GetPDGMass();
00479   G4double scaledTkin = kineticEnergy*massRatio;
00480   G4double charge     = p->GetPDGCharge();
00481   G4double charge2    = charge*charge;
00482   const G4MaterialCutsCouple* matCC = CurrentCouple();
00483 
00484   size_t jMat = 0;
00485   for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
00486   {
00487     if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
00488   }
00489   //G4cout << "jMat= " << jMat 
00490   //     << " jMax= " << fMaterialCutsCoupleVector.size()
00491   //       << " matCC: " << matCC;
00492   //if(matCC) G4cout << " mat: " << matCC->GetMaterial()->GetName();
00493   //  G4cout << G4endl;
00494   if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
00495 
00496   fPAIdEdxTable = fPAIdEdxBank[jMat];
00497   fdEdxVector = fdEdxTable[jMat];
00498   for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++)
00499   {
00500     if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;    
00501   }
00502   //G4cout << "E= " << scaledTkin << " iTkin= " << iTkin 
00503   //     << "  " << fdEdxVector->GetVectorLength()<<G4endl; 
00504   iPlace = iTkin - 1;
00505   if(iPlace < 0) iPlace = 0;
00506   else if(iPlace >= fTotBin) iPlace = fTotBin-1;
00507   G4double dEdx = charge2*( (*fdEdxVector)(iPlace) - GetdEdxCut(iPlace,cut) );
00508   if( dEdx < 0.) dEdx = 0.;
00509   return dEdx;
00510 }
00511 
00513 
00514 G4double G4PAIModel::CrossSectionPerVolume( const G4Material*,
00515                                             const G4ParticleDefinition* p,
00516                                             G4double kineticEnergy,
00517                                             G4double cutEnergy,
00518                                             G4double maxEnergy  ) 
00519 {
00520   G4int iTkin,iPlace;
00521   G4double tmax = std::min(MaxSecondaryEnergy(p, kineticEnergy), maxEnergy);
00522   if(tmax <= cutEnergy) return 0.0;
00523   G4double massRatio  = fMass/p->GetPDGMass();
00524   G4double scaledTkin = kineticEnergy*massRatio;
00525   G4double charge     = p->GetPDGCharge();
00526   G4double charge2    = charge*charge, cross, cross1, cross2;
00527   const G4MaterialCutsCouple* matCC = CurrentCouple();
00528 
00529   size_t jMat = 0;
00530   for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
00531   {
00532     if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
00533   }
00534   if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
00535 
00536   fPAItransferTable = fPAIxscBank[jMat];
00537 
00538   for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++)
00539   {
00540     if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;    
00541   }
00542   iPlace = iTkin - 1;
00543   if(iPlace < 0) iPlace = 0;
00544   else if(iPlace >= fTotBin) iPlace = fTotBin-1; 
00545 
00546   //G4cout<<"iPlace = "<<iPlace<<"; tmax = "
00547   // <<tmax<<"; cutEnergy = "<<cutEnergy<<G4endl;  
00548   cross1 = GetdNdxCut(iPlace,tmax) ;
00549   //G4cout<<"cross1 = "<<cross1<<G4endl;  
00550   cross2 = GetdNdxCut(iPlace,cutEnergy) ;  
00551   //G4cout<<"cross2 = "<<cross2<<G4endl;  
00552   cross  = (cross2-cross1)*charge2;
00553   //G4cout<<"cross = "<<cross<<G4endl;  
00554   if( cross < DBL_MIN) cross = 0.0;
00555   //  if( cross2 < DBL_MIN) cross2 = DBL_MIN;
00556 
00557   // return cross2;
00558   return cross;
00559 }
00560 
00562 //
00563 // It is analog of PostStepDoIt in terms of secondary electron.
00564 //
00565  
00566 void G4PAIModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
00567                                    const G4MaterialCutsCouple* matCC,
00568                                    const G4DynamicParticle* dp,
00569                                    G4double tmin,
00570                                    G4double maxEnergy)
00571 {
00572   size_t jMat = 0;
00573   for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
00574   {
00575     if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
00576   }
00577   if(jMat == fMaterialCutsCoupleVector.size()) return;
00578 
00579   fPAItransferTable = fPAIxscBank[jMat];
00580   fdNdxCutVector    = fdNdxCutTable[jMat];
00581 
00582   G4double tmax = std::min(MaxSecondaryKinEnergy(dp), maxEnergy);
00583   if( tmin >= tmax && fVerbose > 0)
00584   {
00585     G4cout<<"G4PAIModel::SampleSecondary: tmin >= tmax "<<G4endl;
00586   }
00587   G4ThreeVector direction= dp->GetMomentumDirection();
00588   G4double particleMass  = dp->GetMass();
00589   G4double kineticEnergy = dp->GetKineticEnergy();
00590 
00591   G4double massRatio     = fMass/particleMass;
00592   G4double scaledTkin    = kineticEnergy*massRatio;
00593   G4double totalEnergy   = kineticEnergy + particleMass;
00594   G4double pSquare       = kineticEnergy*(totalEnergy+particleMass);
00595  
00596   G4double deltaTkin     = GetPostStepTransfer(scaledTkin);
00597 
00598   // G4cout<<"G4PAIModel::SampleSecondaries; deltaKIn = "<<deltaTkin/keV<<" keV "<<G4endl;
00599 
00600   if( deltaTkin <= 0. && fVerbose > 0) 
00601   {
00602     G4cout<<"G4PAIModel::SampleSecondary e- deltaTkin = "<<deltaTkin<<G4endl;
00603   }
00604   if( deltaTkin <= 0.) return;
00605 
00606   if( deltaTkin > tmax) deltaTkin = tmax;
00607 
00608   G4double deltaTotalMomentum = sqrt(deltaTkin*(deltaTkin + 2. * electron_mass_c2 ));
00609   G4double totalMomentum      = sqrt(pSquare);
00610   G4double costheta           = deltaTkin*(totalEnergy + electron_mass_c2)
00611                                 /(deltaTotalMomentum * totalMomentum);
00612 
00613   if( costheta > 0.99999 ) costheta = 0.99999;
00614   G4double sintheta = 0.0;
00615   G4double sin2 = 1. - costheta*costheta;
00616   if( sin2 > 0.) sintheta = sqrt(sin2);
00617 
00618   //  direction of the delta electron
00619   G4double phi  = twopi*G4UniformRand(); 
00620   G4double dirx = sintheta*cos(phi), diry = sintheta*sin(phi), dirz = costheta;
00621 
00622   G4ThreeVector deltaDirection(dirx,diry,dirz);
00623   deltaDirection.rotateUz(direction);
00624   deltaDirection.unit();
00625 
00626   // primary change
00627   kineticEnergy -= deltaTkin;
00628   G4ThreeVector dir = totalMomentum*direction - deltaTotalMomentum*deltaDirection;
00629   direction = dir.unit();
00630   fParticleChange->SetProposedKineticEnergy(kineticEnergy);
00631   fParticleChange->SetProposedMomentumDirection(direction);
00632 
00633   // create G4DynamicParticle object for e- delta ray 
00634   G4DynamicParticle* deltaRay = new G4DynamicParticle;
00635   deltaRay->SetDefinition(G4Electron::Electron());
00636   deltaRay->SetKineticEnergy( deltaTkin );  //  !!! trick for last steps /2.0 ???
00637   deltaRay->SetMomentumDirection(deltaDirection); 
00638 
00639   vdp->push_back(deltaRay);
00640 }
00641 
00642 
00644 //
00645 // Returns post step PAI energy transfer > cut electron energy according to passed 
00646 // scaled kinetic energy of particle
00647 
00648 G4double  
00649 G4PAIModel::GetPostStepTransfer( G4double scaledTkin )
00650 {  
00651   // G4cout<<"G4PAIModel::GetPostStepTransfer"<<G4endl ;
00652 
00653   G4int iTkin, iTransfer, iPlace  ;
00654   G4double transfer = 0.0, position, dNdxCut1, dNdxCut2, E1, E2, W1, W2, W ;
00655 
00656   for(iTkin=0;iTkin<=fTotBin;iTkin++)
00657   {
00658     if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin))  break ;
00659   }
00660   iPlace = iTkin - 1 ;
00661   // G4cout<<"from search, iPlace = "<<iPlace<<G4endl ;
00662   if(iPlace < 0) iPlace = 0;
00663   else if(iPlace >= fTotBin) iPlace = fTotBin-1; 
00664   dNdxCut1 = (*fdNdxCutVector)(iPlace) ;  
00665   // G4cout<<"dNdxCut1 = "<<dNdxCut1<<G4endl ;
00666 
00667 
00668   if(iTkin == fTotBin) // Fermi plato, try from left
00669   {
00670       position = dNdxCut1*G4UniformRand() ;
00671 
00672       for( iTransfer = 0;
00673  iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
00674       {
00675         if(position >= (*(*fPAItransferTable)(iPlace))(iTransfer)) break ;
00676       }
00677       transfer = GetEnergyTransfer(iPlace,position,iTransfer);
00678   }
00679   else
00680   {
00681     dNdxCut2 = (*fdNdxCutVector)(iPlace+1) ;  
00682     // G4cout<<"dNdxCut2 = "<<dNdxCut2<<G4endl ;
00683     if(iTkin == 0) // Tkin is too small, trying from right only
00684     {
00685       position = dNdxCut2*G4UniformRand() ;
00686 
00687       for( iTransfer = 0;
00688   iTransfer < G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength()); iTransfer++ )
00689       {
00690         if(position >= (*(*fPAItransferTable)(iPlace+1))(iTransfer)) break ;
00691       }
00692       transfer = GetEnergyTransfer(iPlace+1,position,iTransfer);
00693     } 
00694     else // general case: Tkin between two vectors of the material
00695     {
00696       E1 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin - 1) ; 
00697       E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin)     ;
00698       W  = 1.0/(E2 - E1) ;
00699       W1 = (E2 - scaledTkin)*W ;
00700       W2 = (scaledTkin - E1)*W ;
00701 
00702       position = ( dNdxCut1*W1 + dNdxCut2*W2 )*G4UniformRand() ;
00703 
00704         // G4cout<<position<<"\t" ;
00705 
00706       G4int iTrMax1, iTrMax2, iTrMax;
00707 
00708       iTrMax1 = G4int((*fPAItransferTable)(iPlace)->GetVectorLength());
00709       iTrMax2 = G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength());
00710 
00711       if (iTrMax1 >= iTrMax2) iTrMax = iTrMax2;
00712       else                    iTrMax = iTrMax1;
00713 
00714 
00715       for( iTransfer = 0; iTransfer < iTrMax; iTransfer++ )
00716       {
00717           if( position >=
00718           ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 +
00719             (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) ) break ;
00720       }
00721       transfer = GetEnergyTransfer(iPlace,position,iTransfer);
00722     }
00723   } 
00724   // G4cout<<"PAImodel PostStepTransfer = "<<transfer/keV<<" keV"<<G4endl ; 
00725   if(transfer < 0.0 ) transfer = 0.0 ;
00726   // if(transfer < DBL_MIN ) transfer = DBL_MIN;
00727 
00728   return transfer ;
00729 }
00730 
00732 //
00733 // Returns random PAI energy transfer according to passed 
00734 // indexes of particle kinetic
00735 
00736 G4double
00737 G4PAIModel::GetEnergyTransfer( G4int iPlace, G4double position, G4int iTransfer )
00738 { 
00739   G4int iTransferMax;
00740   G4double x1, x2, y1, y2, energyTransfer;
00741 
00742   if(iTransfer == 0)
00743   {
00744     energyTransfer = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer);
00745   }  
00746   else
00747   {
00748     iTransferMax = G4int((*fPAItransferTable)(iPlace)->GetVectorLength());
00749 
00750     if ( iTransfer >= iTransferMax )  iTransfer = iTransferMax - 1;
00751     
00752     y1 = (*(*fPAItransferTable)(iPlace))(iTransfer-1);
00753     y2 = (*(*fPAItransferTable)(iPlace))(iTransfer);
00754 
00755     x1 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1);
00756     x2 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer);
00757 
00758     if ( x1 == x2 )    energyTransfer = x2;
00759     else
00760     {
00761       if ( y1 == y2  ) energyTransfer = x1 + (x2 - x1)*G4UniformRand();
00762       else
00763       {
00764         energyTransfer = x1 + (position - y1)*(x2 - x1)/(y2 - y1);
00765       }
00766     }
00767   }
00768   return energyTransfer;
00769 }
00770 
00772 
00773 G4double G4PAIModel::SampleFluctuations( const G4Material* material,
00774                                          const G4DynamicParticle* aParticle,
00775                                                G4double&,
00776                                                G4double& step,
00777                                                G4double&)
00778 {
00779   size_t jMat = 0;
00780   for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
00781   {
00782     if( material == fMaterialCutsCoupleVector[jMat]->GetMaterial() ) break;
00783   }
00784   if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
00785 
00786   fPAItransferTable = fPAIxscBank[jMat];
00787   fdNdxCutVector   = fdNdxCutTable[jMat];
00788 
00789   G4int iTkin, iTransfer, iPlace;
00790   G4long numOfCollisions=0;
00791 
00792   //G4cout<<"G4PAIModel::SampleFluctuations"<<G4endl ;
00793   //G4cout<<"in: "<<fMaterialCutsCoupleVector[jMat]->GetMaterial()->GetName()<<G4endl;
00794   G4double loss = 0.0, charge2 ;
00795   G4double stepSum = 0., stepDelta, lambda, omega; 
00796   G4double position, E1, E2, W1, W2, W, dNdxCut1, dNdxCut2, meanNumber;
00797   G4bool numb = true;
00798   G4double Tkin       = aParticle->GetKineticEnergy() ;
00799   G4double MassRatio  = fMass/aParticle->GetDefinition()->GetPDGMass() ;
00800   G4double charge     = aParticle->GetDefinition()->GetPDGCharge() ;
00801   charge2             = charge*charge ;
00802   G4double TkinScaled = Tkin*MassRatio ;
00803 
00804   for(iTkin=0;iTkin<=fTotBin;iTkin++)
00805   {
00806     if(TkinScaled < fParticleEnergyVector->GetLowEdgeEnergy(iTkin))   break ;
00807   }
00808   iPlace = iTkin - 1 ; 
00809   if(iPlace < 0) iPlace = 0;
00810   else if(iPlace >= fTotBin) iPlace = fTotBin - 1;
00811   //G4cout<<"from search, iPlace = "<<iPlace<<G4endl ;
00812   dNdxCut1 = (*fdNdxCutVector)(iPlace) ;  
00813   //G4cout<<"dNdxCut1 = "<<dNdxCut1<<G4endl ;
00814 
00815   if(iTkin == fTotBin) // Fermi plato, try from left
00816   {
00817     meanNumber =((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*step*charge2;
00818     if(meanNumber < 0.) meanNumber = 0. ;
00819     //  numOfCollisions = RandPoisson::shoot(meanNumber) ;
00820     // numOfCollisions = G4Poisson(meanNumber) ;
00821     if( meanNumber > 0.) lambda = step/meanNumber;
00822     else                 lambda = DBL_MAX;
00823     while(numb)
00824     {
00825      stepDelta = CLHEP::RandExponential::shoot(lambda);
00826      stepSum += stepDelta;
00827      if(stepSum >= step) break;
00828      numOfCollisions++;
00829     }   
00830     //G4cout<<"##1 numOfCollisions = "<<numOfCollisions<<G4endl ;
00831 
00832     while(numOfCollisions)
00833     {
00834       position = dNdxCut1+
00835                  ((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*G4UniformRand() ;
00836 
00837       for( iTransfer = 0;
00838    iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
00839       {
00840         if(position >= (*(*fPAItransferTable)(iPlace))(iTransfer)) break ;
00841       }
00842       omega = GetEnergyTransfer(iPlace,position,iTransfer);
00843       //G4cout<<"G4PAIModel::SampleFluctuations, omega = "<<omega/keV<<" keV; "<<"\t";
00844       loss += omega;
00845       numOfCollisions-- ;
00846     }
00847   }
00848   else
00849   {
00850     dNdxCut2 = (*fdNdxCutVector)(iPlace+1) ; 
00851     //G4cout<<"dNdxCut2 = "<<dNdxCut2<< " iTkin= "<<iTkin<<" iPlace= "<<iPlace<<G4endl;
00852  
00853     if(iTkin == 0) // Tkin is too small, trying from right only
00854     {
00855       meanNumber =((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*step*charge2;
00856       if( meanNumber < 0. ) meanNumber = 0. ;
00857       //  numOfCollisions = CLHEP::RandPoisson::shoot(meanNumber) ;
00858       //  numOfCollisions = G4Poisson(meanNumber) ;
00859       if( meanNumber > 0.) lambda = step/meanNumber;
00860       else                 lambda = DBL_MAX;
00861       while(numb)
00862         {
00863           stepDelta = CLHEP::RandExponential::shoot(lambda);
00864           stepSum += stepDelta;
00865           if(stepSum >= step) break;
00866           numOfCollisions++;
00867         }   
00868 
00869       //G4cout<<"##2 numOfCollisions = "<<numOfCollisions<<G4endl ;
00870 
00871       while(numOfCollisions)
00872       {
00873         position = dNdxCut2+
00874                    ((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*G4UniformRand();
00875    
00876         for( iTransfer = 0;
00877    iTransfer < G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength()); iTransfer++ )
00878         {
00879           if(position >= (*(*fPAItransferTable)(iPlace+1))(iTransfer)) break ;
00880         }
00881         omega = GetEnergyTransfer(iPlace,position,iTransfer);
00882         //G4cout<<omega/keV<<"\t";
00883         loss += omega;
00884         numOfCollisions-- ;
00885       }
00886     } 
00887     else // general case: Tkin between two vectors of the material
00888     {
00889       E1 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin - 1) ; 
00890       E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin)     ;
00891        W = 1.0/(E2 - E1) ;
00892       W1 = (E2 - TkinScaled)*W ;
00893       W2 = (TkinScaled - E1)*W ;
00894 
00895       //G4cout << fPAItransferTable->size() << G4endl;
00896       //G4cout<<"(*(*fPAItransferTable)(iPlace))(0) = "<<
00897       //   (*(*fPAItransferTable)(iPlace))(0)<<G4endl ;
00898       //G4cout<<"(*(*fPAItransferTable)(iPlace+1))(0) = "<<
00899       //     (*(*fPAItransferTable)(iPlace+1))(0)<<G4endl ;
00900 
00901       meanNumber=( ((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*W1 + 
00902                    ((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*W2 )*step*charge2;
00903       if(meanNumber<0.0) meanNumber = 0.0;
00904       //  numOfCollisions = RandPoisson::shoot(meanNumber) ;
00905       // numOfCollisions = G4Poisson(meanNumber) ;
00906       if( meanNumber > 0.) lambda = step/meanNumber;
00907       else                 lambda = DBL_MAX;
00908       while(numb)
00909         {
00910           stepDelta = CLHEP::RandExponential::shoot(lambda);
00911           stepSum += stepDelta;
00912           if(stepSum >= step) break;
00913           numOfCollisions++;
00914         }   
00915 
00916       //G4cout<<"##3 numOfCollisions = "<<numOfCollisions<<endl ;
00917 
00918       while(numOfCollisions)
00919       {
00920         position = dNdxCut1*W1 + dNdxCut2*W2 +
00921                  ( ( (*(*fPAItransferTable)(iPlace))(0)-dNdxCut1 )*W1 + 
00922                     dNdxCut2+
00923                   ( (*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2 )*W2 )*G4UniformRand();
00924 
00925         // G4cout<<position<<"\t" ;
00926 
00927         for( iTransfer = 0;
00928     iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
00929         {
00930           if( position >=
00931           ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 + 
00932             (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) )
00933           {
00934               break ;
00935           }
00936         }
00937         omega =  GetEnergyTransfer(iPlace,position,iTransfer);
00938         //  G4cout<<omega/keV<<"\t";
00939         loss += omega;
00940         numOfCollisions-- ;    
00941       }
00942     }
00943   } 
00944   //G4cout<<"PAIModel AlongStepLoss = "<<loss/keV<<" keV, on step = "
00945   //  <<step/mm<<" mm"<<G4endl ; 
00946   if(loss > Tkin) loss=Tkin;
00947   if(loss < 0.  ) loss = 0.;
00948   return loss ;
00949 
00950 }
00951 
00953 //
00954 // Returns the statistical estimation of the energy loss distribution variance
00955 //
00956 
00957 
00958 G4double G4PAIModel::Dispersion( const G4Material* material, 
00959                                  const G4DynamicParticle* aParticle,
00960                                        G4double& tmax, 
00961                                        G4double& step       )
00962 {
00963   G4double loss, sumLoss=0., sumLoss2=0., sigma2, meanLoss=0.;
00964   for(G4int i = 0 ; i < fMeanNumber; i++)
00965   {
00966     loss      = SampleFluctuations(material,aParticle,tmax,step,meanLoss);
00967     sumLoss  += loss;
00968     sumLoss2 += loss*loss;
00969   }
00970   meanLoss = sumLoss/fMeanNumber;
00971   sigma2   = meanLoss*meanLoss + (sumLoss2-2*sumLoss*meanLoss)/fMeanNumber;
00972   return sigma2;
00973 }
00974 
00976 
00977 G4double G4PAIModel::MaxSecondaryEnergy( const G4ParticleDefinition* p,
00978                                          G4double kinEnergy) 
00979 {
00980   G4double tmax = kinEnergy;
00981   if(p == fElectron) tmax *= 0.5;
00982   else if(p != fPositron) { 
00983     G4double mass = p->GetPDGMass();
00984     G4double ratio= electron_mass_c2/mass;
00985     G4double gamma= kinEnergy/mass + 1.0;
00986     tmax = 2.0*electron_mass_c2*(gamma*gamma - 1.) /
00987                   (1. + 2.0*gamma*ratio + ratio*ratio);
00988   }
00989   return tmax;
00990 }
00991 
00993 
00994 void G4PAIModel::DefineForRegion(const G4Region* r) 
00995 {
00996   fPAIRegionVector.push_back(r);
00997 }
00998 
00999 //
01000 //
01002 
01003 
01004 
01005 
01006 
01007 

Generated on Mon May 27 17:49:13 2013 for Geant4 by  doxygen 1.4.7