// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // $Id: G4PAIModel.cc,v 1.52 2010/06/03 07:28:39 grichine Exp $ // GEANT4 tag $Name: geant4-09-04-beta-cand-01 $ // // ------------------------------------------------------------------- // // GEANT4 Class // File name: G4PAIModel.cc // // Author: Vladimir.Grichine@cern.ch on base of Vladimir Ivanchenko model interface // // Creation date: 05.10.2003 // // Modifications: // // 17.08.04 V.Grichine, bug fixed for Tkin<=0 in SampleSecondary // 16.08.04 V.Grichine, bug fixed in massRatio for DEDX, CrossSection, SampleSecondary // 08.04.05 Major optimisation of internal interfaces (V.Ivantchenko) // 26.07.09 Fixed logic to work with several materials (V.Ivantchenko) // #include "G4Region.hh" #include "G4PhysicsLogVector.hh" #include "G4PhysicsFreeVector.hh" #include "G4PhysicsTable.hh" #include "G4ProductionCutsTable.hh" #include "G4MaterialCutsCouple.hh" #include "G4MaterialTable.hh" #include "G4SandiaTable.hh" #include "G4OrderedTable.hh" #include "G4PAIModel.hh" #include "Randomize.hh" #include "G4Electron.hh" #include "G4Positron.hh" #include "G4Poisson.hh" #include "G4Step.hh" #include "G4Material.hh" #include "G4DynamicParticle.hh" #include "G4ParticleDefinition.hh" #include "G4ParticleChangeForLoss.hh" //////////////////////////////////////////////////////////////////////// using namespace std; G4PAIModel::G4PAIModel(const G4ParticleDefinition* p, const G4String& nam) : G4VEmModel(nam),G4VEmFluctuationModel(nam), fVerbose(0), fLowestGamma(1.005), fHighestGamma(10000.), fTotBin(200), fMeanNumber(20), fParticle(0), fHighKinEnergy(100.*TeV), fTwoln10(2.0*log(10.0)), fBg2lim(0.0169), fTaulim(8.4146e-3) { if(p) SetParticle(p); fElectron = G4Electron::Electron(); fPositron = G4Positron::Positron(); fPAItransferTable = 0; fPAIdEdxTable = 0; fSandiaPhotoAbsCof = 0; fdEdxVector = 0; fLambdaVector = 0; fdNdxCutVector = 0; isInitialised = false; } //////////////////////////////////////////////////////////////////////////// G4PAIModel::~G4PAIModel() { // G4cout << "PAI: start destruction" << G4endl; if(fParticleEnergyVector) delete fParticleEnergyVector; if(fdEdxVector) delete fdEdxVector ; if(fLambdaVector) delete fLambdaVector; if(fdNdxCutVector) delete fdNdxCutVector; if( fPAItransferTable ) { fPAItransferTable->clearAndDestroy(); delete fPAItransferTable ; } if( fPAIdEdxTable ) { fPAIdEdxTable->clearAndDestroy(); delete fPAIdEdxTable ; } if(fSandiaPhotoAbsCof) { for(G4int i=0;iGetPDGMass(); fSpin = fParticle->GetPDGSpin(); G4double q = fParticle->GetPDGCharge()/eplus; fChargeSquare = q*q; fLowKinEnergy = 0.2*MeV*fMass/proton_mass_c2; fRatio = electron_mass_c2/fMass; fQc = fMass/fRatio; } //////////////////////////////////////////////////////////////////////////// void G4PAIModel::Initialise(const G4ParticleDefinition* p, const G4DataVector&) { G4cout<<"G4PAIModel::Initialise for "<GetParticleName()<GetMaterialCutsCouple( fMaterial, curReg->GetProductionCuts() ); //G4cout << "Reg <" <GetName() << "> mat <" // << fMaterial->GetName() << "> fCouple= " // << fCutCouple<<" " << p->GetParticleName() <GetEnergyCutsVector(1))[fCutCouple->GetIndex()]; //ComputeSandiaPhotoAbsCof(); BuildPAIonisationTable(); fPAIxscBank.push_back(fPAItransferTable); fPAIdEdxBank.push_back(fPAIdEdxTable); fdEdxTable.push_back(fdEdxVector); BuildLambdaVector(); fdNdxCutTable.push_back(fdNdxCutVector); fLambdaTable.push_back(fLambdaVector); } } } } ////////////////////////////////////////////////////////////////// void G4PAIModel::InitialiseMe(const G4ParticleDefinition*) {} ////////////////////////////////////////////////////////////////// void G4PAIModel::ComputeSandiaPhotoAbsCof() { G4int i, j, numberOfElements ; static const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4SandiaTable thisMaterialSandiaTable(fMatIndex) ; numberOfElements = (*theMaterialTable)[fMatIndex]-> GetNumberOfElements(); G4int* thisMaterialZ = new G4int[numberOfElements] ; for(i=0;iGetElement(i)->GetZ() ; } fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaIntervals (thisMaterialZ,numberOfElements) ; fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaMixing ( thisMaterialZ , (*theMaterialTable)[fMatIndex]->GetFractionVector() , numberOfElements,fSandiaIntervalNumber) ; fSandiaPhotoAbsCof = new G4double*[fSandiaIntervalNumber] ; for(i=0;iGetDensity() ; } } // delete[] thisMaterialZ ; } //////////////////////////////////////////////////////////////////////////// // // Build tables for the ionization energy loss // the tables are built for MATERIALS // ********* void G4PAIModel::BuildPAIonisationTable() { G4double LowEdgeEnergy , ionloss ; G4double tau, Tmax, Tmin, Tkin, deltaLow, gamma, bg2 ; fdEdxVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin); G4SandiaTable* sandia = fMaterial->GetSandiaTable(); Tmin = sandia->GetSandiaCofForMaterialPAI(0,0)*keV; deltaLow = 100.*eV; // 0.5*eV ; for (G4int i = 0 ; i <= fTotBin ; i++) //The loop for the kinetic energy { LowEdgeEnergy = fParticleEnergyVector->GetLowEdgeEnergy(i) ; tau = LowEdgeEnergy/fMass ; gamma = tau +1. ; // G4cout<<"gamma = "<= transferCut G4double G4PAIModel::GetdEdxCut( G4int iPlace, G4double transferCut) { G4int iTransfer; G4double x1, x2, y1, y2, dEdxCut; //G4cout<<"iPlace = "<GetPDGMass(); G4double scaledTkin = kineticEnergy*massRatio; G4double charge = p->GetPDGCharge(); G4double charge2 = charge*charge; const G4MaterialCutsCouple* matCC = CurrentCouple(); size_t jMat = 0; for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat ) { if( matCC == fMaterialCutsCoupleVector[jMat] ) break; } //G4cout << "jMat= " << jMat // << " jMax= " << fMaterialCutsCoupleVector.size() // << " matCC: " << matCC; //if(matCC) G4cout << " mat: " << matCC->GetMaterial()->GetName(); // G4cout << G4endl; if(jMat == fMaterialCutsCoupleVector.size()) return 0.0; fPAIdEdxTable = fPAIdEdxBank[jMat]; fdEdxVector = fdEdxTable[jMat]; for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++) { if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } //G4cout << "E= " << scaledTkin << " iTkin= " << iTkin // << " " << fdEdxVector->GetVectorLength()<= fTotBin) iPlace = fTotBin-1; G4double dEdx = charge2*( (*fdEdxVector)(iPlace) - GetdEdxCut(iPlace,cut) ); if( dEdx < 0.) dEdx = 0.; return dEdx; } ///////////////////////////////////////////////////////////////////////// G4double G4PAIModel::CrossSectionPerVolume( const G4Material*, const G4ParticleDefinition* p, G4double kineticEnergy, G4double cutEnergy, G4double maxEnergy ) { G4int iTkin,iPlace; G4double tmax = std::min(MaxSecondaryEnergy(p, kineticEnergy), maxEnergy); if(tmax <= cutEnergy) return 0.0; G4double massRatio = fMass/p->GetPDGMass(); G4double scaledTkin = kineticEnergy*massRatio; G4double charge = p->GetPDGCharge(); G4double charge2 = charge*charge, cross, cross1, cross2; const G4MaterialCutsCouple* matCC = CurrentCouple(); size_t jMat = 0; for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat ) { if( matCC == fMaterialCutsCoupleVector[jMat] ) break; } if(jMat == fMaterialCutsCoupleVector.size()) return 0.0; fPAItransferTable = fPAIxscBank[jMat]; for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++) { if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1; if(iPlace < 0) iPlace = 0; else if(iPlace >= fTotBin) iPlace = fTotBin-1; //G4cout<<"iPlace = "<= tmax "<GetMomentumDirection(); G4double particleMass = dp->GetMass(); G4double kineticEnergy = dp->GetKineticEnergy(); G4double massRatio = fMass/particleMass; G4double scaledTkin = kineticEnergy*massRatio; G4double totalEnergy = kineticEnergy + particleMass; G4double pSquare = kineticEnergy*(totalEnergy+particleMass); G4double deltaTkin = GetPostStepTransfer(scaledTkin); // G4cout<<"G4PAIModel::SampleSecondaries; deltaKIn = "< 0) { G4cout<<"G4PAIModel::SampleSecondary e- deltaTkin = "< tmax) deltaTkin = tmax; G4double deltaTotalMomentum = sqrt(deltaTkin*(deltaTkin + 2. * electron_mass_c2 )); G4double totalMomentum = sqrt(pSquare); G4double costheta = deltaTkin*(totalEnergy + electron_mass_c2) /(deltaTotalMomentum * totalMomentum); if( costheta > 0.99999 ) costheta = 0.99999; G4double sintheta = 0.0; G4double sin2 = 1. - costheta*costheta; if( sin2 > 0.) sintheta = sqrt(sin2); // direction of the delta electron G4double phi = twopi*G4UniformRand(); G4double dirx = sintheta*cos(phi), diry = sintheta*sin(phi), dirz = costheta; G4ThreeVector deltaDirection(dirx,diry,dirz); deltaDirection.rotateUz(direction); deltaDirection.unit(); // primary change kineticEnergy -= deltaTkin; G4ThreeVector dir = totalMomentum*direction - deltaTotalMomentum*deltaDirection; direction = dir.unit(); fParticleChange->SetProposedKineticEnergy(kineticEnergy); fParticleChange->SetProposedMomentumDirection(direction); // create G4DynamicParticle object for e- delta ray G4DynamicParticle* deltaRay = new G4DynamicParticle; deltaRay->SetDefinition(G4Electron::Electron()); deltaRay->SetKineticEnergy( deltaTkin ); // !!! trick for last steps /2.0 ??? deltaRay->SetMomentumDirection(deltaDirection); vdp->push_back(deltaRay); } /////////////////////////////////////////////////////////////////////// // // Returns post step PAI energy transfer > cut electron energy according to passed // scaled kinetic energy of particle G4double G4PAIModel::GetPostStepTransfer( G4double scaledTkin ) { // G4cout<<"G4PAIModel::GetPostStepTransfer"<GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1 ; // G4cout<<"from search, iPlace = "<= fTotBin) iPlace = fTotBin-1; dNdxCut1 = (*fdNdxCutVector)(iPlace) ; // G4cout<<"dNdxCut1 = "<GetVectorLength()); iTransfer++ ) { if(position >= (*(*fPAItransferTable)(iPlace))(iTransfer)) break ; } transfer = GetEnergyTransfer(iPlace,position,iTransfer); } else { dNdxCut2 = (*fdNdxCutVector)(iPlace+1) ; // G4cout<<"dNdxCut2 = "<GetVectorLength()); iTransfer++ ) { if(position >= (*(*fPAItransferTable)(iPlace+1))(iTransfer)) break ; } transfer = GetEnergyTransfer(iPlace+1,position,iTransfer); } else // general case: Tkin between two vectors of the material { E1 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin - 1) ; E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin) ; W = 1.0/(E2 - E1) ; W1 = (E2 - scaledTkin)*W ; W2 = (scaledTkin - E1)*W ; position = ( dNdxCut1*W1 + dNdxCut2*W2 )*G4UniformRand() ; // G4cout<GetVectorLength()); iTrMax2 = G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength()); if (iTrMax1 >= iTrMax2) iTrMax = iTrMax2; else iTrMax = iTrMax1; for( iTransfer = 0; iTransfer < iTrMax; iTransfer++ ) { if( position >= ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 + (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) ) break ; } transfer = GetEnergyTransfer(iPlace,position,iTransfer); } } // G4cout<<"PAImodel PostStepTransfer = "<GetLowEdgeEnergy(iTransfer); } else { iTransferMax = G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); if ( iTransfer >= iTransferMax ) iTransfer = iTransferMax - 1; y1 = (*(*fPAItransferTable)(iPlace))(iTransfer-1); y2 = (*(*fPAItransferTable)(iPlace))(iTransfer); x1 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1); x2 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer); if ( x1 == x2 ) energyTransfer = x2; else { if ( y1 == y2 ) energyTransfer = x1 + (x2 - x1)*G4UniformRand(); else { energyTransfer = x1 + (position - y1)*(x2 - x1)/(y2 - y1); } } } return energyTransfer; } /////////////////////////////////////////////////////////////////////// G4double G4PAIModel::SampleFluctuations( const G4Material* material, const G4DynamicParticle* aParticle, G4double&, G4double& step, G4double&) { size_t jMat = 0; for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat ) { if( material == fMaterialCutsCoupleVector[jMat]->GetMaterial() ) break; } if(jMat == fMaterialCutsCoupleVector.size()) return 0.0; fPAItransferTable = fPAIxscBank[jMat]; fdNdxCutVector = fdNdxCutTable[jMat]; G4int iTkin, iTransfer, iPlace; G4long numOfCollisions=0; //G4cout<<"G4PAIModel::SampleFluctuations"<GetMaterial()->GetName()<GetKineticEnergy() ; G4double MassRatio = fMass/aParticle->GetDefinition()->GetPDGMass() ; G4double charge = aParticle->GetDefinition()->GetPDGCharge() ; charge2 = charge*charge ; G4double TkinScaled = Tkin*MassRatio ; for(iTkin=0;iTkin<=fTotBin;iTkin++) { if(TkinScaled < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1 ; if(iPlace < 0) iPlace = 0; else if(iPlace >= fTotBin) iPlace = fTotBin - 1; //G4cout<<"from search, iPlace = "<GetLowEdgeEnergy(iTkin - 1) ; E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin) ; W = 1.0/(E2 - E1) ; W1 = (E2 - TkinScaled)*W ; W2 = (TkinScaled - E1)*W ; //G4cout << fPAItransferTable->size() << G4endl; //G4cout<<"(*(*fPAItransferTable)(iPlace))(0) = "<< // (*(*fPAItransferTable)(iPlace))(0)<GetVectorLength()); iTransfer++ ) { if( position >= ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 + (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) ) { break ; } } omega = GetEnergyTransfer(iPlace,position,iTransfer); // G4cout< Tkin) loss=Tkin; if(loss < 0. ) loss = 0.; return loss ; } ////////////////////////////////////////////////////////////////////// // // Returns the statistical estimation of the energy loss distribution variance // G4double G4PAIModel::Dispersion( const G4Material* material, const G4DynamicParticle* aParticle, G4double& tmax, G4double& step ) { G4double loss, sumLoss=0., sumLoss2=0., sigma2, meanLoss=0.; for(G4int i = 0 ; i < fMeanNumber; i++) { loss = SampleFluctuations(material,aParticle,tmax,step,meanLoss); sumLoss += loss; sumLoss2 += loss*loss; } meanLoss = sumLoss/fMeanNumber; sigma2 = meanLoss*meanLoss + (sumLoss2-2*sumLoss*meanLoss)/fMeanNumber; return sigma2; } ///////////////////////////////////////////////////////////////////// G4double G4PAIModel::MaxSecondaryEnergy( const G4ParticleDefinition* p, G4double kinEnergy) { G4double tmax = kinEnergy; if(p == fElectron) tmax *= 0.5; else if(p != fPositron) { G4double mass = p->GetPDGMass(); G4double ratio= electron_mass_c2/mass; G4double gamma= kinEnergy/mass + 1.0; tmax = 2.0*electron_mass_c2*(gamma*gamma - 1.) / (1. + 2.0*gamma*ratio + ratio*ratio); } return tmax; } /////////////////////////////////////////////////////////////// void G4PAIModel::DefineForRegion(const G4Region* r) { fPAIRegionVector.push_back(r); } // // /////////////////////////////////////////////////