// // ******************************************************************** // * 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. * // ******************************************************************** // // #include "G4Types.hh" //#include //#include //#include #include "G4HadronicProcess.hh" #include "G4HadProjectile.hh" #include "G4ElementVector.hh" #include "G4Track.hh" #include "G4Step.hh" #include "G4Element.hh" #include "G4ParticleChange.hh" #include "G4TransportationManager.hh" #include "G4Navigator.hh" #include "G4ProcessVector.hh" #include "G4ProcessManager.hh" #include "G4StableIsotopes.hh" #include "G4HadTmpUtil.hh" #include "G4HadLeadBias.hh" #include "G4HadronicException.hh" #include "G4HadReentrentException.hh" #include "G4HadronicWhiteBoard.hh" #include "G4HadSignalHandler.hh" #include "G4HadronicProcessStore.hh" #include namespace G4HadronicProcess_local { extern "C" void G4HadronicProcessHandler_1(int) { G4HadronicWhiteBoard::Instance().Dump(); } } G4IsoParticleChange * G4HadronicProcess::theIsoResult = 0; G4IsoParticleChange * G4HadronicProcess::theOldIsoResult = 0; G4bool G4HadronicProcess::isoIsEnabled = true; void G4HadronicProcess:: EnableIsotopeProductionGlobally() {isoIsEnabled = true;} void G4HadronicProcess:: DisableIsotopeProductionGlobally() {isoIsEnabled = false;} ////////////////////////////////////////////////////////////////// G4HadronicProcess::G4HadronicProcess( const G4String &processName, G4ProcessType aType ) : G4VDiscreteProcess( processName, aType) { ModelingState = 0; isoIsOnAnyway = -1; theTotalResult = new G4ParticleChange(); theCrossSectionDataStore = new G4CrossSectionDataStore(); G4HadronicProcessStore::Instance()->Register(this); aScaleFactor = 1; xBiasOn = false; G4HadronicProcess_debug_flag = false; if(getenv("SwitchLeadBiasOn")) theBias.push_back(new G4HadLeadBias()); } G4HadronicProcess::~G4HadronicProcess() { G4HadronicProcessStore::Instance()->DeRegister(this); delete theTotalResult; std::for_each(theProductionModels.begin(), theProductionModels.end(), G4Delete()); std::for_each(theBias.begin(), theBias.end(), G4Delete()); delete theOldIsoResult; delete theIsoResult; delete theCrossSectionDataStore; } void G4HadronicProcess::RegisterMe( G4HadronicInteraction *a ) { try{GetManagerPointer()->RegisterMe( a );} catch(G4HadronicException & aE) { aE.Report(std::cout); G4Exception("G4HadronicProcess", "007", FatalException, "Could not register G4HadronicInteraction"); } G4HadronicProcessStore::Instance()->RegisterInteraction(this, a); } void G4HadronicProcess::PreparePhysicsTable(const G4ParticleDefinition& p) { if(getenv("G4HadronicProcess_debug")) G4HadronicProcess_debug_flag = true; G4HadronicProcessStore::Instance()->RegisterParticle(this, &p); } void G4HadronicProcess::BuildPhysicsTable(const G4ParticleDefinition& p) { theCrossSectionDataStore->BuildPhysicsTable(p); G4HadronicProcessStore::Instance()->PrintInfo(&p); } G4double G4HadronicProcess:: GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *) { try { ModelingState = 1; theLastCrossSection = aScaleFactor* theCrossSectionDataStore->GetCrossSection(aTrack.GetDynamicParticle(), aTrack.GetMaterial()); } catch(G4HadronicException aR) { aR.Report(G4cout); G4Exception("G4HadronicProcess", "007", FatalException, "G4HadronicProcess::GetMeanFreePath failed"); } G4double res = DBL_MAX; if( theLastCrossSection > 0.0 ) res = 1.0/theLastCrossSection; return res; } G4double G4HadronicProcess:: GetMicroscopicCrossSection(const G4DynamicParticle *aParticle, const G4Element *anElement, G4double aTemp ) { return theCrossSectionDataStore->GetCrossSection(aParticle, anElement, aTemp); } G4VParticleChange *G4HadronicProcess::PostStepDoIt( const G4Track &aTrack, const G4Step &) { // Debugging stuff if(G4HadronicProcess_debug_flag) std::cout << "@@@@ hadronic process start "<< std::endl; // G4cout << theNumberOfInteractionLengthLeft<Clear(); theTotalResult->Initialize(aTrack); return theTotalResult; } const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); G4Material* aMaterial = aTrack.GetMaterial(); G4double originalEnergy = aParticle->GetKineticEnergy(); G4double kineticEnergy = originalEnergy; /* // It is not needed with standard NaN check // More debugging G4Nancheck go_wild; if(go_wild(originalEnergy) || go_wild(aParticle->Get4Momentum().x()) || go_wild(aParticle->Get4Momentum().y()) || go_wild(aParticle->Get4Momentum().z()) || go_wild(aParticle->Get4Momentum().t()) ) { G4Exception("G4HadronicProcess", "001", JustWarning, "NaN in input energy or momentum - bailing out."); theTotalResult->Clear(); theTotalResult->Initialize(aTrack); return theTotalResult; } */ // Get kinetic energy per nucleon for ions if(aParticle->GetDefinition()->GetBaryonNumber() > 1.5) kineticEnergy/=aParticle->GetDefinition()->GetBaryonNumber(); G4Element* anElement = 0; try { // anElement = ChooseAandZ( aParticle, aMaterial ); anElement = theCrossSectionDataStore->SampleZandA(aParticle, aMaterial, targetNucleus); } catch(G4HadronicException & aR) { aR.Report(G4cout); G4cout << "Unrecoverable error for:"<ApplyYourself( thePro, targetNucleus); } catch(G4HadReentrentException aR) { G4HadronicWhiteBoard & theBoard = G4HadronicWhiteBoard::Instance(); theBoard.SetProjectile(thePro); theBoard.SetTargetNucleus(targetNucleus); theBoard.SetProcessName(GetProcessName()); theBoard.SetModelName(theInteraction->GetModelName()); aR.Report(G4cout); G4cout << " G4HadronicProcess re-entering the ApplyYourself call for " <GetModelName()); aR.Report(G4cout); G4cout << " G4HadronicProcess failed in ApplyYourself call for" << G4endl; G4cout << " - Particle energy[GeV] = "<< originalEnergy/GeV<GetStatusChange() == isAlive && thePro.GetDefinition() != aTrack.GetDefinition()) { G4DynamicParticle * aP = const_cast(aTrack.GetDynamicParticle()); aP->SetDefinition(const_cast(thePro.GetDefinition())); } result->SetTrafoToLab(thePro.GetTrafoToLab()); if(getenv("HadronicDoitLogging") ) { G4cout << "HadronicDoitLogging " << GetProcessName() <<" " << aParticle->GetDefinition()->GetPDGEncoding()<<" " << originalEnergy<<" " << aParticle->GetMomentum()<<" " << targetNucleus.GetN()<<" " << targetNucleus.GetZ()<<" " << G4endl; } ClearNumberOfInteractionLengthLeft(); if(isoIsOnAnyway!=-1) { if(isoIsEnabled||isoIsOnAnyway) { result = DoIsotopeCounting(result, aTrack, targetNucleus); } } G4double e=aTrack.GetKineticEnergy(); ModelingState = 0; if(e<5*GeV) { for(size_t i=0; iBias(result); } } // Put hadronic final state particles into G4ParticleChange FillTotalResult(result, aTrack); if(G4HadronicProcess_debug_flag) std::cout << "@@@@ hadronic process end "<< std::endl; return theTotalResult; } G4HadFinalState* G4HadronicProcess::DoIsotopeCounting(G4HadFinalState * aResult, const G4Track & aTrack, const G4Nucleus & aNucleus) { // get the PC from iso-production delete theOldIsoResult; theOldIsoResult = 0; delete theIsoResult; theIsoResult = new G4IsoParticleChange; G4bool done = false; G4IsoResult * anIsoResult = 0; for(unsigned int i=0; iGetIsotope(aTrack, aNucleus); if(anIsoResult!=0) { done = true; break; } } // If no production models active, use default iso production if(!done) anIsoResult = ExtractResidualNucleus(aTrack, aNucleus, aResult); // Add all info explicitely and add typename from model called. theIsoResult->SetIsotope(anIsoResult->GetIsotope()); theIsoResult->SetProductionPosition(aTrack.GetPosition()); theIsoResult->SetProductionTime(aTrack.GetGlobalTime()); theIsoResult->SetParentParticle(*aTrack.GetDynamicParticle()); theIsoResult->SetMotherNucleus(anIsoResult->GetMotherNucleus()); theIsoResult->SetProducer(typeid(*theInteraction).name()); delete anIsoResult; // If isotope production is enabled the GetIsotopeProductionInfo() // method must be called or else a memory leak will result // // The following code will fix the memory leak, but remove the // isotope information: // // if(theIsoResult) { // delete theIsoResult; // theIsoResult = 0; // } return aResult; } G4IsoResult* G4HadronicProcess::ExtractResidualNucleus(const G4Track&, const G4Nucleus& aNucleus, G4HadFinalState* aResult) { G4double A = aNucleus.GetN(); G4double Z = aNucleus.GetZ(); G4double bufferA = 0; G4double bufferZ = 0; // loop over aResult, and decrement A, Z accordingly // cash the max for(G4int i=0; iGetNumberOfSecondaries(); i++) { G4HadSecondary* aSecTrack = aResult->GetSecondary(i); if(bufferAGetParticle()->GetDefinition()->GetBaryonNumber()) { bufferA = aSecTrack->GetParticle()->GetDefinition()->GetBaryonNumber(); bufferZ = aSecTrack->GetParticle()->GetDefinition()->GetPDGCharge(); } Z-=aSecTrack->GetParticle()->GetDefinition()->GetPDGCharge(); A-=aSecTrack->GetParticle()->GetDefinition()->GetBaryonNumber(); } // if the fragment was part of the final state, it is // assumed to be the heaviest secondary. if(A<0.1) { A = bufferA; Z = bufferZ; } // prepare the IsoResult. std::ostringstream ost1; ost1 <Clear(); theTotalResult->ProposeLocalEnergyDeposit(0.); theTotalResult->Initialize(aT); theTotalResult->SetSecondaryWeightByProcess(true); theTotalResult->ProposeTrackStatus(fAlive); G4double rotation = 2.*pi*G4UniformRand(); G4ThreeVector it(0., 0., 1.); /* if(xBiasOn) { G4cout << "BiasDebug "<GetStatusChange()<GetStatusChange()==stopAndKill) { if( xBiasOn && G4UniformRand()ProposeParentWeight( XBiasSurvivalProbability()*aT.GetWeight() ); } else { theTotalResult->ProposeTrackStatus(fStopAndKill); theTotalResult->ProposeEnergy( 0.0 ); } } else if(aR->GetStatusChange()!=stopAndKill ) { if(aR->GetStatusChange()==suspend) { theTotalResult->ProposeTrackStatus(fSuspend); if(xBiasOn) { G4Exception("G4HadronicProcess", "007", FatalException, "Cannot cross-section bias a process that suspends tracks."); } } else if (aT.GetKineticEnergy() == 0) { theTotalResult->ProposeTrackStatus(fStopButAlive); } if(xBiasOn && G4UniformRand()ProposeParentWeight( XBiasSurvivalProbability()*aT.GetWeight() ); G4double newWeight = aR->GetWeightChange()*aT.GetWeight(); /* if(go_wild(aR->GetEnergyChange())) { G4Exception("G4HadronicProcess", "007", FatalException, "surviving track received NaN energy."); } if(go_wild(aR->GetMomentumChange().x()) || go_wild(aR->GetMomentumChange().y()) || go_wild(aR->GetMomentumChange().z())) { G4Exception("G4HadronicProcess", "007", FatalException, "surviving track received NaN momentum."); } */ G4double newM=aT.GetDefinition()->GetPDGMass(); G4double newE=aR->GetEnergyChange() + newM; G4double newP=std::sqrt(newE*newE - newM*newM); G4DynamicParticle * aNew = new G4DynamicParticle(aT.GetDefinition(), newE, newP*aR->GetMomentumChange()); G4HadSecondary * theSec = new G4HadSecondary(aNew, newWeight); aR->AddSecondary(theSec); } else { G4double newWeight = aR->GetWeightChange()*aT.GetWeight(); theTotalResult->ProposeParentWeight(newWeight); // This is multiplicative if(aR->GetEnergyChange()>-.5) { /* if(go_wild(aR->GetEnergyChange())) { G4Exception("G4HadronicProcess", "007", FatalException, "track received NaN energy."); } */ theTotalResult->ProposeEnergy(aR->GetEnergyChange()); } G4LorentzVector newDirection(aR->GetMomentumChange().unit(), 1.); newDirection*=aR->GetTrafoToLab(); theTotalResult->ProposeMomentumDirection(newDirection.vect()); } } else { G4cerr << "Track status is "<< aR->GetStatusChange()<GetTrackStatus()==fAlive && aR->GetStatusChange()==isAlive) { // Use for debugging: G4double newWeight = theTotalResult->GetParentWeight(); G4double newKE = std::max(DBL_MIN, aR->GetEnergyChange()); G4DynamicParticle* aNew = new G4DynamicParticle(aT.GetDefinition(), aR->GetMomentumChange(), newKE); G4HadSecondary* theSec = new G4HadSecondary(aNew, 1.0); aR->AddSecondary(theSec); aR->SetStatusChange(stopAndKill); theTotalResult->ProposeTrackStatus(fStopAndKill); theTotalResult->ProposeEnergy( 0.0 ); } theTotalResult->ProposeLocalEnergyDeposit(aR->GetLocalEnergyDeposit()); theTotalResult->SetNumberOfSecondaries(aR->GetNumberOfSecondaries()); if(aR->GetStatusChange() != stopAndKill) { G4double newM=aT.GetDefinition()->GetPDGMass(); G4double newE=aR->GetEnergyChange() + newM; G4double newP=std::sqrt(newE*newE - newM*newM); G4ThreeVector newPV = newP*aR->GetMomentumChange(); G4LorentzVector newP4(newE, newPV); newP4.rotate(rotation, it); newP4*=aR->GetTrafoToLab(); theTotalResult->ProposeMomentumDirection(newP4.vect().unit()); } for(G4int i=0; iGetNumberOfSecondaries(); i++) { G4LorentzVector theM = aR->GetSecondary(i)->GetParticle()->Get4Momentum(); theM.rotate(rotation, it); theM*=aR->GetTrafoToLab(); /* if(go_wild(theM.e())) { G4Exception("G4HadronicProcess", "007", FatalException, "secondary track received NaN energy."); } if(go_wild(theM.x()) || go_wild(theM.y()) || go_wild(theM.z())) { G4Exception("G4HadronicProcess", "007", FatalException, "secondary track received NaN momentum."); } */ aR->GetSecondary(i)->GetParticle()->Set4Momentum(theM); G4double time = aR->GetSecondary(i)->GetTime(); if(time<0) time = aT.GetGlobalTime(); G4Track* track = new G4Track(aR->GetSecondary(i)->GetParticle(), time, aT.GetPosition()); G4double newWeight = aT.GetWeight()*aR->GetSecondary(i)->GetWeight(); //static G4double pinelcount=0; if(xBiasOn) newWeight *= XBiasSecondaryWeight(); // G4cout << "#### ParticleDebug " // <GetSecondary(i)->GetParticle()->GetDefinition()->GetParticleName()<<" " // <GetSecondary(i)->GetWeight()<<" " // <GetSecondary(i)->GetParticle()->Get4Momentum()<<" " // <SetWeight(newWeight); /* G4double trackDeb = track->GetKineticEnergy(); if( ( trackDeb<0 || (trackDeb>aT.GetKineticEnergy()+1*GeV) ) && getenv("GHADEnergyBalanceDebug") ) { G4cout << "Debugging hadronic processes: "<GetKineticEnergy() <<" "<GetParticleName() <SetTouchableHandle(aT.GetTouchableHandle()); theTotalResult->AddSecondary(track); } aR->Clear(); return; } G4IsoParticleChange* G4HadronicProcess::GetIsotopeProductionInfo() { G4IsoParticleChange * anIsoResult = theIsoResult; if(theIsoResult) theOldIsoResult = theIsoResult; theIsoResult = 0; return anIsoResult; } void G4HadronicProcess::BiasCrossSectionByFactor(G4double aScale) { xBiasOn = true; aScaleFactor = aScale; G4String it = GetProcessName(); if( (it != "PhotonInelastic") && (it != "ElectroNuclear") && (it != "PositronNuclear") ) { G4Exception("G4HadronicProcess", "007", FatalException, "Cross-section biasing available only for gamma and electro nuclear reactions."); } if(aScale<100) { G4Exception("G4HadronicProcess", "001", JustWarning, "Cross-section bias readjusted to be above safe limit. New value is 100"); aScaleFactor = 100.; } } /* end of file */