// This code implementation is the intellectual property of // the RD44 GEANT4 collaboration. // // By copying, distributing or modifying the Program (or any work // based on the Program) you indicate your acceptance of this statement, // and all its terms. // // $Id: G4Decay.cc,v 2.5 1998/12/15 09:40:26 kurasige Exp $ // GEANT4 tag $Name: geant4-00 $ // // // -------------------------------------------------------------- // GEANT 4 class implementation file // // For information related to this code contact: // CERN, CN Division, ASD group // History: first implementation, based on object model of // 2nd December 1995, G.Cosmo // 7 July 1996 H.Kurashige // ------------------------------------------------------------ // remove BuildPhysicsTable() 28 Nov. 1997 H.Kurashige // change DBL_EPSIRON to DBL_MIN 14 Dec. 1997 H.Kurashige // modified for new ParticleChange 12 Mar. 1998 H.Kurashige // modified for "GoodForTrackingFlag" 19 June 1998 H.Kurashige // rename thePhysicsTable to aPhyscisTable 2 Aug. 1998 H.Kurashige // modified IsApplicable in order to protect the decay from registered // to resonances 12 Dec. 1998 H.Kurashige #include "G4Decay.hh" #include "G4DynamicParticle.hh" #include "G4DecayProducts.hh" #include "G4DecayTable.hh" #include "G4PhysicsLogVector.hh" #include "G4ParticleChangeForDecay.hh" // constructor G4Decay::G4Decay(const G4String& processName) :G4VRestDiscreteProcess(processName, fDecay), HighestBinValue(10.0), LowestBinValue(1.0e-3), TotBin(200), verboseLevel(1) { #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay constructor " << " Name:" << processName << endl; } #endif aPhysicsTable = NULL; pParticleChange = &fParticleChangeForDecay; } G4Decay::~G4Decay() { if (aPhysicsTable != NULL) { aPhysicsTable->clearAndDestroy(); delete aPhysicsTable; } } G4bool G4Decay::IsApplicable(const G4ParticleDefinition& aParticleType) { // return false if resonances if (aParticleType.IsShortLived()) return false; // check if the particle is stable? if (aParticleType.GetPDGLifeTime() <0.0) { return false; } else if (aParticleType.GetPDGMass() <= 0.0*MeV) { return false; } else { return true; } } G4double G4Decay::GetMeanLifeTime(const G4Track& aTrack, G4ForceCondition*) { // get particle type const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); // returns the mean free path in GEANT4 internal units G4double meanlife; G4ParticleDefinition* aParticleDef = aParticle->GetDefinition(); G4double aLife = aParticleDef->GetPDGLifeTime(); #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay::GetMeanLifeTime() "<< endl; G4cerr << "KineticEnergy:" << aParticle->GetKineticEnergy()/GeV <<"[GeV]"; G4cerr << "Mass:" << aParticle->GetMass()/GeV <<"[GeV]"; G4cerr << "Life time: "<< aLife/ns << "[ns]" << endl; } #endif // check if the particle is stable? if (aParticleDef->GetPDGStable()) { meanlife = DBL_MAX; } else if (aLife < 0.0) { meanlife = DBL_MAX; } else { meanlife = aLife; } #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "mean life time: "<< meanlife/ns << "[ns]" << endl; } #endif return meanlife; } G4double G4Decay::GetMeanFreePath(const G4Track& aTrack,G4double, G4ForceCondition*) { // constants G4bool isOutRange ; // get particle const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); // returns the mean free path in GEANT4 internal units G4double pathlength; G4ParticleDefinition* aParticleDef = aParticle->GetDefinition(); G4double aCtau = c_light * aParticleDef->GetPDGLifeTime(); G4double aMass = aParticle->GetMass(); #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay::GetMeanFreePath() "<< endl; G4cerr << "KineticEnergy:" << aParticle->GetKineticEnergy()/GeV <<"[GeV]"; G4cerr << "Mass:" << aMass/GeV <<"[GeV]"; G4cerr << "c*Tau:" << aCtau/m <<"[m]" <GetPDGStable()) { pathlength = DBL_MAX; } else if (aCtau < 0.0) { pathlength = DBL_MAX; //check if the particle has very short life time ? } else if (aCtau < DBL_MIN) { pathlength = DBL_MIN; //check if zero mass } else if (aMass < DBL_MIN) { pathlength = DBL_MAX; #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << " Zero Mass particle " << endl; } #endif } else { //calculate the mean free path // by using normalized kinetic energy (= Ekin/mass) G4double rKineticEnergy = aParticle->GetKineticEnergy()/aMass; if ( rKineticEnergy > HighestBinValue) { // beta >> 1 pathlength = ( rKineticEnergy + 1.0)* aCtau; } else if ( rKineticEnergy > LowestBinValue) { // check if aPhysicsTable exists if (aPhysicsTable == NULL) BuildPhysicsTable(*aParticleDef); // beta is in the range valid for PhysicsTable pathlength = aCtau * ((*aPhysicsTable)(0))-> GetValue(rKineticEnergy,isOutRange); } else if ( rKineticEnergy < DBL_MIN ) { // too slow particle #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay::GetMeanFreePath() !!particle stops!!"; G4cerr << aParticleDef->GetParticleName() << endl; G4cerr << "KineticEnergy:" << aParticle->GetKineticEnergy()/GeV <<"[GeV]"; } #endif pathlength = DBL_MIN; } else { // beta << 1 pathlength = (aParticle->GetTotalMomentum())/aMass*aCtau ; } } #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "mean free path: "<< pathlength/m << "[m]" << endl; } #endif return pathlength; } void G4Decay::BuildPhysicsTable(const G4ParticleDefinition&) { // if aPhysicsTableis has already been created, do nothing if (aPhysicsTable != NULL) return; // create aPhysicsTable if (GetVerboseLevel()>1) G4cerr <<" G4Decay::BuildPhysicsTable() "<< endl; aPhysicsTable = new G4PhysicsTable(1); //create physics vector G4PhysicsLogVector* aVector = new G4PhysicsLogVector( LowestBinValue, HighestBinValue, TotBin); G4double beta, gammainv; // fill physics Vector G4int i; for ( i = 0 ; i < TotBin ; i++ ) { gammainv = 1.0/(aVector->GetLowEdgeEnergy(i) + 1.0); beta = sqrt((1.0 - gammainv)*(1.0 +gammainv)); aVector->PutValue(i, beta/gammainv); } aPhysicsTable->insert(aVector); } G4VParticleChange* G4Decay::DecayIt(const G4Track& aTrack, const G4Step& ) { // The DecayIt() method returns by pointer a particle-change object. // Units are expressed in GEANT4 internal units. // Initialize ParticleChange // all members of G4VParticleChange are set to equal to // corresponding member in G4Track fParticleChangeForDecay.Initialize(aTrack); // get particle const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); //check if thePreAssignedDecayProducts exists G4DecayProducts* products = aParticle->GetPreAssignedDecayProducts(); G4bool isPreAssigned = (products != NULL); if (!isPreAssigned) { // decay acoording to decay table G4DecayTable *decaytable = aParticle->GetDefinition()->GetDecayTable(); if (decaytable == NULL){ #ifdef G4VERBOSE if (GetVerboseLevel()>0) { G4cerr << "G4Decay::DoIt : decay table not defined for"; G4cerr << aParticle->GetDefinition()->GetParticleName()<< endl; } #endif fParticleChangeForDecay.SetNumberOfSecondaries(0); // Kill the parent particle fParticleChangeForDecay.SetStatusChange( fStopAndKill ) ; fParticleChangeForDecay.SetLocalEnergyDeposit(0.0); ClearNumberOfInteractionLengthLeft(); return &fParticleChangeForDecay ; } else { // choose a decay channel G4VDecayChannel *decaychannel = decaytable->SelectADecayChannel(); if (decaychannel == NULL){ // decay channel not found #ifdef G4VERBOSE if (GetVerboseLevel()>0) { G4cerr << "G4Decay::DoIt : can not determine decay channel " <DumpInfo(); } #endif } else { G4int temp; // execute DecayIt() #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay::DoIt : selected decay channel addr:" << decaychannel <GetVerboseLevel(); decaychannel->SetVerboseLevel(GetVerboseLevel()); } #endif products = decaychannel->DecayIt(aParticle->GetMass()); #ifdef G4VERBOSE if (GetVerboseLevel()>1) { decaychannel->SetVerboseLevel(temp); } #endif #ifdef G4VERBOSE // for debug //if (! products->IsChecked() ) products->DumpInfo(); #endif } } } // get parent particle information ................................... G4double ParentEnergy = aParticle->GetTotalEnergy(); G4ParticleMomentum ParentDirection(aParticle->GetMomentumDirection()); //boost all decay products to laboratory frame G4double energyDeposit = 0.0; G4double finalGlobalTime = aTrack.GetGlobalTime(); if (aTrack.GetTrackStatus() == fStopButAlive ){ // AtRest case finalGlobalTime += fRemainderLifeTime; energyDeposit += aParticle->GetKineticEnergy(); } else { // PostStep case products->Boost( ParentEnergy, ParentDirection); } //add products in fParticleChangeForDecay G4int numberOfSecondaries = products->entries(); fParticleChangeForDecay.SetNumberOfSecondaries(numberOfSecondaries); #ifdef G4VERBOSE if (GetVerboseLevel()>1) { G4cerr << "G4Decay::DoIt : Decay vertex :"; G4cerr << " Time: " << finalGlobalTime/ns << "[ns]"; G4cerr << " X:" << (aTrack.GetPosition()).x() /cm << "[cm]"; G4cerr << " Y:" << (aTrack.GetPosition()).y() /cm << "[cm]"; G4cerr << " Z:" << (aTrack.GetPosition()).z() /cm << "[cm]"; G4cerr << endl; G4cerr << "G4Decay::DoIt : decay products in Lab. Frame" << endl; products->DumpInfo(); } #endif G4int index; G4ThreeVector currentPosition; for (index=0; index < numberOfSecondaries; index++) { // get current position of the track currentPosition = aTrack.GetPosition(); // create a new track object G4Track* secondary = new G4Track( products->PopProducts(), finalGlobalTime , currentPosition ); // switch on good for tracking flag secondary->SetGoodForTrackingFlag(); // add the secondary track in the List fParticleChangeForDecay.AddSecondary(secondary); } if (!isPreAssigned) delete products; // Kill the parent particle fParticleChangeForDecay.SetStatusChange( fStopAndKill ) ; fParticleChangeForDecay.SetLocalEnergyDeposit(energyDeposit); fParticleChangeForDecay.SetTimeChange( finalGlobalTime ); // reset NumberOfInteractionLengthLeft ClearNumberOfInteractionLengthLeft(); return &fParticleChangeForDecay ; }