// // ******************************************************************** // * 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: G4PAIPhotonModel.cc,v 1.24 2010/06/03 07:28:39 grichine Exp $ // GEANT4 tag $Name: geant4-09-04-beta-cand-01 $ // // ------------------------------------------------------------------- // // GEANT4 Class // File name: G4PAIPhotonModel.cc // // Author: Vladimir.Grichine@cern.ch based on G4PAIModel class // // Creation date: 20.05.2004 // // 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 // 11.04.05 Major optimisation of internal interfaces (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 "G4PAIxSection.hh" #include "G4PAIPhotonModel.hh" #include "Randomize.hh" #include "G4Electron.hh" #include "G4Positron.hh" #include "G4Gamma.hh" #include "G4Poisson.hh" #include "G4Step.hh" #include "G4Material.hh" #include "G4DynamicParticle.hh" #include "G4ParticleDefinition.hh" #include "G4ParticleChangeForLoss.hh" #include "G4GeometryTolerance.hh" //////////////////////////////////////////////////////////////////////// using namespace std; G4PAIPhotonModel::G4PAIPhotonModel(const G4ParticleDefinition* p, const G4String& nam) : G4VEmModel(nam),G4VEmFluctuationModel(nam), fLowestKineticEnergy(10.0*keV), fHighestKineticEnergy(100.*TeV), fTotBin(200), fMeanNumber(20), fParticle(0), fHighKinEnergy(100.*TeV), fLowKinEnergy(2.0*MeV), fTwoln10(2.0*log(10.0)), fBg2lim(0.0169), fTaulim(8.4146e-3) { if(p) SetParticle(p); fVerbose = 0; fElectron = G4Electron::Electron(); fPositron = G4Positron::Positron(); fProtonEnergyVector = new G4PhysicsLogVector(fLowestKineticEnergy, fHighestKineticEnergy, fTotBin); fPAItransferTable = 0; fPAIphotonTable = 0; fPAIplasmonTable = 0; fPAIdEdxTable = 0; fSandiaPhotoAbsCof = 0; fdEdxVector = 0; fLambdaVector = 0; fdNdxCutVector = 0; fdNdxCutPhotonVector = 0; fdNdxCutPlasmonVector = 0; isInitialised = false; } //////////////////////////////////////////////////////////////////////////// G4PAIPhotonModel::~G4PAIPhotonModel() { if(fProtonEnergyVector) delete fProtonEnergyVector; if(fdEdxVector) delete fdEdxVector ; if ( fLambdaVector) delete fLambdaVector; if ( fdNdxCutVector) delete fdNdxCutVector; if( fPAItransferTable ) { fPAItransferTable->clearAndDestroy(); delete fPAItransferTable ; } if( fPAIphotonTable ) { fPAIphotonTable->clearAndDestroy(); delete fPAIphotonTable ; } if( fPAIplasmonTable ) { fPAIplasmonTable->clearAndDestroy(); delete fPAIplasmonTable ; } if(fSandiaPhotoAbsCof) { for(G4int i=0;iGetPDGMass(); fSpin = fParticle->GetPDGSpin(); G4double q = fParticle->GetPDGCharge()/eplus; fChargeSquare = q*q; fLowKinEnergy *= fMass/proton_mass_c2; fRatio = electron_mass_c2/fMass; fQc = fMass/fRatio; } //////////////////////////////////////////////////////////////////////////// void G4PAIPhotonModel::Initialise(const G4ParticleDefinition* p, const G4DataVector&) { G4cout<<"G4PAIPhotonModel::Initialise for "<GetParticleName()<::const_iterator matIter = curReg->GetMaterialIterator(); size_t jMat; size_t numOfMat = curReg->GetNumberOfMaterials(); // for(size_t jMat = 0; jMat < curReg->GetNumberOfMaterials();++jMat){} const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); size_t numberOfMat = G4Material::GetNumberOfMaterials(); for(jMat = 0 ; jMat < numOfMat; ++jMat) // region material loop { const G4MaterialCutsCouple* matCouple = theCoupleTable-> GetMaterialCutsCouple( *matIter, curReg->GetProductionCuts() ); fMaterialCutsCoupleVector.push_back(matCouple); size_t iMatGlob; for(iMatGlob = 0 ; iMatGlob < numberOfMat ; iMatGlob++ ) { if( *matIter == (*theMaterialTable)[iMatGlob]) break ; } fMatIndex = iMatGlob; ComputeSandiaPhotoAbsCof(); BuildPAIonisationTable(); fPAIxscBank.push_back(fPAItransferTable); fPAIphotonBank.push_back(fPAIphotonTable); fPAIplasmonBank.push_back(fPAIplasmonTable); fPAIdEdxBank.push_back(fPAIdEdxTable); fdEdxTable.push_back(fdEdxVector); BuildLambdaVector(matCouple); fdNdxCutTable.push_back(fdNdxCutVector); fdNdxCutPhotonTable.push_back(fdNdxCutPhotonVector); fdNdxCutPlasmonTable.push_back(fdNdxCutPlasmonVector); fLambdaTable.push_back(fLambdaVector); matIter++; } } } ////////////////////////////////////////////////////////////////// void G4PAIPhotonModel::InitialiseMe(const G4ParticleDefinition*) {} ////////////////////////////////////////////////////////////////// void G4PAIPhotonModel::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 G4PAIPhotonModel::BuildPAIonisationTable() { G4double LowEdgeEnergy , ionloss ; G4double massRatio, tau, Tmax, Tmin, Tkin, deltaLow, gamma, bg2 ; /* if( fPAItransferTable ) { fPAItransferTable->clearAndDestroy() ; delete fPAItransferTable ; } */ fPAItransferTable = new G4PhysicsTable(fTotBin); /* if( fPAIratioTable ) { fPAIratioTable->clearAndDestroy() ; delete fPAIratioTable ; } */ fPAIphotonTable = new G4PhysicsTable(fTotBin); fPAIplasmonTable = new G4PhysicsTable(fTotBin); /* if( fPAIdEdxTable ) { fPAIdEdxTable->clearAndDestroy() ; delete fPAIdEdxTable ; } */ fPAIdEdxTable = new G4PhysicsTable(fTotBin); // if(fdEdxVector) delete fdEdxVector ; fdEdxVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin ) ; Tmin = fSandiaPhotoAbsCof[0][0] ; // low energy Sandia interval deltaLow = 100.*eV; // 0.5*eV ; for (G4int i = 0 ; i <= fTotBin ; i++) //The loop for the kinetic energy { LowEdgeEnergy = fProtonEnergyVector->GetLowEdgeEnergy(i) ; tau = LowEdgeEnergy/proton_mass_c2 ; // if(tau < 0.01) tau = 0.01 ; gamma = tau +1. ; // G4cout<<"gamma = "< Tmax) // was < Tkin = Tmax ; if ( Tkin < Tmin + deltaLow ) // low energy safety { Tkin = Tmin + deltaLow ; } G4PAIxSection protonPAI( fMatIndex, Tkin, bg2, fSandiaPhotoAbsCof, fSandiaIntervalNumber ) ; // G4cout<<"ionloss = "<GetSurfaceTolerance(); const G4ProductionCutsTable* theCoupleTable= G4ProductionCutsTable::GetProductionCutsTable(); size_t numOfCouples = theCoupleTable->GetTableSize(); size_t jMatCC; for (jMatCC = 0 ; jMatCC < numOfCouples ; jMatCC++ ) { if( matCutsCouple == theCoupleTable->GetMaterialCutsCouple(jMatCC) ) break; } if( jMatCC == numOfCouples && jMatCC > 0 ) jMatCC--; const vector* deltaCutInKineticEnergy = theCoupleTable-> GetEnergyCutsVector(idxG4ElectronCut); const vector* photonCutInKineticEnergy = theCoupleTable-> GetEnergyCutsVector(idxG4GammaCut); if (fLambdaVector) delete fLambdaVector; if (fdNdxCutVector) delete fdNdxCutVector; if (fdNdxCutPhotonVector) delete fdNdxCutPhotonVector; if (fdNdxCutPlasmonVector) delete fdNdxCutPlasmonVector; fLambdaVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin ); fdNdxCutVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin ); fdNdxCutPhotonVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin ); fdNdxCutPlasmonVector = new G4PhysicsLogVector( fLowestKineticEnergy, fHighestKineticEnergy, fTotBin ); G4double deltaCutInKineticEnergyNow = (*deltaCutInKineticEnergy)[jMatCC]; G4double photonCutInKineticEnergyNow = (*photonCutInKineticEnergy)[jMatCC]; if(fVerbose > 0) { G4cout<<"PAIPhotonModel deltaCutInKineticEnergyNow = " <PutValue(i, lambda); fdNdxCutVector->PutValue(i, dNdxCut); fdNdxCutPhotonVector->PutValue(i, dNdxPhotonCut); fdNdxCutPlasmonVector->PutValue(i, dNdxPlasmonCut); } } /////////////////////////////////////////////////////////////////////// // // Returns integral PAI cross section for energy transfers >= transferCut G4double G4PAIPhotonModel::GetdNdxCut( G4int iPlace, G4double transferCut) { G4int iTransfer; G4double x1, x2, y1, y2, dNdxCut; // G4cout<<"iPlace = "<= transferCut G4double G4PAIPhotonModel::GetdNdxPhotonCut( G4int iPlace, G4double transferCut) { G4int iTransfer; G4double x1, x2, y1, y2, dNdxCut; // G4cout<<"iPlace = "<= transferCut G4double G4PAIPhotonModel::GetdNdxPlasmonCut( G4int iPlace, G4double transferCut) { G4int iTransfer; G4double x1, x2, y1, y2, dNdxCut; // G4cout<<"iPlace = "<= transferCut G4double G4PAIPhotonModel::GetdEdxCut( G4int iPlace, G4double transferCut) { G4int iTransfer; G4double x1, x2, y1, y2, dEdxCut; // G4cout<<"iPlace = "<GetPDGMass(); G4double scaledTkin = kineticEnergy*proton_mass_c2/particleMass; G4double charge = p->GetPDGCharge()/eplus; G4double charge2 = charge*charge; G4double dEdx = 0.; const G4MaterialCutsCouple* matCC = CurrentCouple(); for( jMat = 0 ;jMat < fMaterialCutsCoupleVector.size() ; ++jMat ) { if( matCC == fMaterialCutsCoupleVector[jMat] ) break; } if(jMat == fMaterialCutsCoupleVector.size() && jMat > 0) jMat--; fPAIdEdxTable = fPAIdEdxBank[jMat]; fdEdxVector = fdEdxTable[jMat]; for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++) { if(scaledTkin < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1; if(iPlace < 0) iPlace = 0; dEdx = charge2*( (*fdEdxVector)(iPlace) - GetdEdxCut(iPlace,cut) ) ; if( dEdx < 0.) dEdx = 0.; return dEdx; } ///////////////////////////////////////////////////////////////////////// G4double G4PAIPhotonModel::CrossSectionPerVolume( const G4Material*, const G4ParticleDefinition* p, G4double kineticEnergy, G4double cutEnergy, G4double maxEnergy ) { G4int iTkin,iPlace; size_t jMat, jMatCC; G4double tmax = std::min(MaxSecondaryEnergy(p, kineticEnergy), maxEnergy); if(cutEnergy >= tmax) return 0.0; G4double particleMass = p->GetPDGMass(); G4double scaledTkin = kineticEnergy*proton_mass_c2/particleMass; G4double charge = p->GetPDGCharge(); G4double charge2 = charge*charge, cross, cross1, cross2; G4double photon1, photon2, plasmon1, plasmon2; const G4MaterialCutsCouple* matCC = CurrentCouple(); const G4ProductionCutsTable* theCoupleTable= G4ProductionCutsTable::GetProductionCutsTable(); size_t numOfCouples = theCoupleTable->GetTableSize(); for (jMatCC = 0 ; jMatCC < numOfCouples ; jMatCC++ ) { if( matCC == theCoupleTable->GetMaterialCutsCouple(jMatCC) ) break; } if( jMatCC == numOfCouples && jMatCC > 0 ) jMatCC--; const vector* photonCutInKineticEnergy = theCoupleTable-> GetEnergyCutsVector(idxG4GammaCut); G4double photonCut = (*photonCutInKineticEnergy)[jMatCC] ; for( jMat = 0 ;jMat < fMaterialCutsCoupleVector.size() ; ++jMat ) { if( matCC == fMaterialCutsCoupleVector[jMat] ) break; } if(jMat == fMaterialCutsCoupleVector.size() && jMat > 0) jMat--; fPAItransferTable = fPAIxscBank[jMat]; fPAIphotonTable = fPAIphotonBank[jMat]; fPAIplasmonTable = fPAIplasmonBank[jMat]; for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++) { if(scaledTkin < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1; if(iPlace < 0) iPlace = 0; // G4cout<<"iPlace = "<= tmax "<GetMomentumDirection(); G4double particleMass = dp->GetMass(); G4double kineticEnergy = dp->GetKineticEnergy(); G4double scaledTkin = kineticEnergy*fMass/particleMass; G4double totalEnergy = kineticEnergy + particleMass; G4double pSquare = kineticEnergy*(totalEnergy+particleMass); G4int iTkin; for(iTkin=0;iTkin<=fTotBin;iTkin++) { if(scaledTkin < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } G4int iPlace = iTkin - 1 ; if(iPlace < 0) iPlace = 0; G4double dNdxPhotonCut = (*fdNdxCutPhotonVector)(iPlace) ; G4double dNdxPlasmonCut = (*fdNdxCutPlasmonVector)(iPlace) ; G4double dNdxCut = dNdxPhotonCut + dNdxPlasmonCut; G4double ratio; if (dNdxCut > 0.) ratio = dNdxPhotonCut/dNdxCut; else ratio = 0.; if(ratio < G4UniformRand() ) // secondary e- { G4double deltaTkin = GetPostStepTransfer(fPAIplasmonTable, fdNdxCutPlasmonVector, iPlace, scaledTkin); // G4cout<<"PAIPhotonModel PlasmonPostStepTransfer = "<GetVectorLength()); iTrMax2 = G4int((*pTable)(iPlace+1)->GetVectorLength()); if (iTrMax1 >= iTrMax2) iTrMax = iTrMax2; else iTrMax = iTrMax1; for( iTransfer = 0; iTransfer < iTrMax; iTransfer++ ) { if( position >= ( (*(*pTable)(iPlace))(iTransfer)*W1 + (*(*pTable)(iPlace+1))(iTransfer)*W2) ) break ; } transfer = GetEnergyTransfer(pTable, iPlace, position, iTransfer); } } // G4cout<<"PAIPhotonModel PostStepTransfer = "<GetLowEdgeEnergy(iTransfer); } else { iTransferMax = G4int((*pTable)(iPlace)->GetVectorLength()); if ( iTransfer >= iTransferMax) iTransfer = iTransferMax - 1; y1 = (*(*pTable)(iPlace))(iTransfer-1); y2 = (*(*fPAItransferTable)(iPlace))(iTransfer); x1 = (*pTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1); x2 = (*pTable)(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; } /////////////////////////////////////////////////////////////////////// // // Works like AlongStepDoIt method of process family G4double G4PAIPhotonModel::SampleFluctuations( const G4Material* material, const G4DynamicParticle* aParticle, G4double&, G4double& step, G4double&) { size_t jMat; for( jMat = 0 ;jMat < fMaterialCutsCoupleVector.size() ; ++jMat ) { if( material == fMaterialCutsCoupleVector[jMat]->GetMaterial() ) break; } if(jMat == fMaterialCutsCoupleVector.size() && jMat > 0) jMat--; fPAItransferTable = fPAIxscBank[jMat]; fPAIphotonTable = fPAIphotonBank[jMat]; fPAIplasmonTable = fPAIplasmonBank[jMat]; fdNdxCutVector = fdNdxCutTable[jMat]; fdNdxCutPhotonVector = fdNdxCutPhotonTable[jMat]; fdNdxCutPlasmonVector = fdNdxCutPlasmonTable[jMat]; G4int iTkin, iPlace ; // G4cout<<"G4PAIPhotonModel::SampleFluctuations"<GetKineticEnergy() ; G4double MassRatio = proton_mass_c2/aParticle->GetDefinition()->GetPDGMass() ; G4double charge = aParticle->GetDefinition()->GetPDGCharge() ; charge2 = charge*charge ; G4double scaledTkin = Tkin*MassRatio ; G4double cof = step*charge2; for( iTkin = 0; iTkin <= fTotBin; iTkin++) { if(scaledTkin < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break ; } iPlace = iTkin - 1 ; if( iPlace < 0 ) iPlace = 0; photonLoss = GetAlongStepTransfer(fPAIphotonTable,fdNdxCutPhotonVector, iPlace,scaledTkin,step,cof); // G4cout<<"PAIPhotonModel AlongStepPhotonLoss = "<GetVectorLength()); iTransfer++ ) { if( position >= ( (*(*pTable)(iPlace))(iTransfer)*W1 + (*(*pTable)(iPlace+1))(iTransfer)*W2) ) { break ; } } // loss += (*pTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ; loss += GetEnergyTransfer(pTable,iPlace,position,iTransfer); numOfCollisions-- ; } } } return loss ; } ////////////////////////////////////////////////////////////////////// // // Returns the statistical estimation of the energy loss distribution variance // G4double G4PAIPhotonModel::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 G4PAIPhotonModel::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 G4PAIPhotonModel::DefineForRegion(const G4Region* r) { fPAIRegionVector.push_back(r); } // // /////////////////////////////////////////////////