// // ******************************************************************** // * 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: G4RPGStrangeProduction.cc,v 1.1 2007/07/18 21:04:21 dennis Exp $ // GEANT4 tag $Name: geant4-09-02 $ // #include "G4RPGStrangeProduction.hh" // #include "G4AntiProton.hh" // #include "G4AntiNeutron.hh" #include "Randomize.hh" #include #include "G4HadReentrentException.hh" #include G4RPGStrangeProduction::G4RPGStrangeProduction() : G4RPGReaction() {} G4bool G4RPGStrangeProduction:: ReactionStage(const G4HadProjectile* /*originalIncident*/, G4ReactionProduct& modifiedOriginal, G4bool& incidentHasChanged, const G4DynamicParticle* originalTarget, G4ReactionProduct& targetParticle, G4bool& targetHasChanged, const G4Nucleus& /*targetNucleus*/, G4ReactionProduct& currentParticle, G4FastVector& vec, G4int& vecLen, G4bool /*leadFlag*/, G4ReactionProduct& /*leadingStrangeParticle*/) { // Derived from H. Fesefeldt's original FORTRAN code STPAIR // // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-, // K+ Y0, K0 Y+, K0 Y- // For antibaryon induced reactions half of the cross sections KB YB // pairs are produced. Charge is not conserved, no experimental data available // for exclusive reactions, therefore some average behaviour assumed. // The ratio L/SIGMA is taken as 3:1 (from experimental low energy) // if( vecLen == 0 )return true; // // the following protects against annihilation processes // if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return true; const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV; const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV; G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV; G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal + targetMass*targetMass + 2.0*targetMass*etOriginal ); // GeV G4double currentMass = currentParticle.GetMass()/GeV; G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass); if( availableEnergy <= 1.0 )return true; G4ParticleDefinition *aProton = G4Proton::Proton(); G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton(); G4ParticleDefinition *aNeutron = G4Neutron::Neutron(); G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron(); G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus(); G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus(); G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero(); G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus(); G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus(); G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero(); G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus(); G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus(); G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong(); G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort(); G4ParticleDefinition *aLambda = G4Lambda::Lambda(); G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda(); const G4double protonMass = aProton->GetPDGMass()/GeV; const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV; // // determine the center of mass energy bin // const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.}; G4int ibin, i3, i4; G4double avk, avy, avn, ran; G4int i = 1; while( (i<12) && (centerofmassEnergy>avrs[i]) )++i; if( i == 12 ) ibin = 11; else ibin = i; // // the fortran code chooses a random replacement of produced kaons // but does not take into account charge conservation // if( vecLen == 1 ) // we know that vecLen > 0 { i3 = 0; i4 = 1; // note that we will be adding a new secondary particle in this case only } else // otherwise 0 <= i3,i4 < vecLen { G4double ran = G4UniformRand(); while( ran == 1.0 )ran = G4UniformRand(); i4 = i3 = G4int( vecLen*ran ); while( i3 == i4 ) { ran = G4UniformRand(); while( ran == 1.0 )ran = G4UniformRand(); i4 = G4int( vecLen*ran ); } } // // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b // const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075, 0.0975, 0.123, 0.28, 0.398, 0.495, 0.573 }; const G4double avky[] = { 0.005, 0.03, 0.064, 0.095, 0.115, 0.13, 0.145, 0.155, 0.20, 0.205, 0.210, 0.212 }; const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02, 0.04, 0.05, 0.12, 0.15, 0.18, 0.20 }; avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1]) /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]); avk = std::exp(avk); avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1]) /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]); avy = std::exp(avy); avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1]) /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]); avn = std::exp(avn); if( avk+avy+avn <= 0.0 )return true; if( currentMass < protonMass )avy /= 2.0; if( targetMass < protonMass )avy = 0.0; avy += avk+avn; avk += avn; ran = G4UniformRand(); if( ran < avn ) { if( availableEnergy < 2.0 )return true; if( vecLen == 1 ) // add a new secondary { G4ReactionProduct *p1 = new G4ReactionProduct; if( G4UniformRand() < 0.5 ) { vec[0]->SetDefinition( aNeutron ); p1->SetDefinition( anAntiNeutron ); (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 ); vec[0]->SetMayBeKilled(false); p1->SetMayBeKilled(false); } else { vec[0]->SetDefinition( aProton ); p1->SetDefinition( anAntiProton ); (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 ); vec[0]->SetMayBeKilled(false); p1->SetMayBeKilled(false); } vec.SetElement( vecLen++, p1 ); // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen); } else { // replace two secondaries if( G4UniformRand() < 0.5 ) { vec[i3]->SetDefinition( aNeutron ); vec[i4]->SetDefinition( anAntiNeutron ); vec[i3]->SetMayBeKilled(false); vec[i4]->SetMayBeKilled(false); } else { vec[i3]->SetDefinition( aProton ); vec[i4]->SetDefinition( anAntiProton ); vec[i3]->SetMayBeKilled(false); vec[i4]->SetMayBeKilled(false); } } } else if( ran < avk ) { if( availableEnergy < 1.0 )return true; const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250, 0.6875, 0.7500, 0.8750, 1.000 }; const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 }; const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 }; ran = G4UniformRand(); i = 0; while( (i<9) && (ran>=kkb[i]) )++i; if( i == 9 )return true; // // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 }; // charge + - + 0 + 0 0 0 0 0 0 0 0 0 0 - 0 - // switch( ipakkb1[i] ) { case 10: vec[i3]->SetDefinition( aKaonPlus ); vec[i3]->SetMayBeKilled(false); break; case 11: vec[i3]->SetDefinition( aKaonZS ); vec[i3]->SetMayBeKilled(false); break; case 12: vec[i3]->SetDefinition( aKaonZL ); vec[i3]->SetMayBeKilled(false); break; } if( vecLen == 1 ) // add a secondary { G4ReactionProduct *p1 = new G4ReactionProduct; switch( ipakkb2[i] ) { case 11: p1->SetDefinition( aKaonZS ); p1->SetMayBeKilled(false); break; case 12: p1->SetDefinition( aKaonZL ); p1->SetMayBeKilled(false); break; case 13: p1->SetDefinition( aKaonMinus ); p1->SetMayBeKilled(false); break; } (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 ); vec.SetElement( vecLen++, p1 ); } else // replace { switch( ipakkb2[i] ) { case 11: vec[i4]->SetDefinition( aKaonZS ); vec[i4]->SetMayBeKilled(false); break; case 12: vec[i4]->SetDefinition( aKaonZL ); vec[i4]->SetMayBeKilled(false); break; case 13: vec[i4]->SetDefinition( aKaonMinus ); vec[i4]->SetMayBeKilled(false); break; } } } else if( ran < avy ) { if( availableEnergy < 1.6 )return true; const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700, 0.800, 0.850, 0.900, 0.950, 0.975, 1.000 }; const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 }; const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 }; const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 }; const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 }; ran = G4UniformRand(); i = 0; while( (i<12) && (ran>ky[i]) )++i; if( i == 12 )return true; if( (currentMassSetDefinition( aKaonPlus ); vec[i3]->SetMayBeKilled(false); break; case 11: vec[i3]->SetDefinition( aKaonZS ); vec[i3]->SetMayBeKilled(false); break; case 12: vec[i3]->SetDefinition( aKaonZL ); vec[i3]->SetMayBeKilled(false); break; } } else // (currentMass >= protonMass) && (G4UniformRand() >= 0.5) { // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11, // 24,13, 24,12, 24,11, 25,13, 25,12, 25,11 }; if( (currentParticle.GetDefinition() == anAntiProton) || (currentParticle.GetDefinition() == anAntiNeutron) || (currentParticle.GetDefinition() == anAntiLambda) || (currentMass > sigmaMinusMass) ) { switch( ipakyb1[i] ) { case 19: currentParticle.SetDefinitionAndUpdateE( anAntiLambda ); break; case 23: currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus ); break; case 24: currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero ); break; case 25: currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus ); break; } incidentHasChanged = true; switch( ipakyb2[i] ) { case 11: vec[i3]->SetDefinition( aKaonZS ); vec[i3]->SetMayBeKilled(false); break; case 12: vec[i3]->SetDefinition( aKaonZL ); vec[i3]->SetMayBeKilled(false); break; case 13: vec[i3]->SetDefinition( aKaonMinus ); vec[i3]->SetMayBeKilled(false); break; } } else { switch( ipaky1[i] ) { case 18: currentParticle.SetDefinitionAndUpdateE( aLambda ); break; case 20: currentParticle.SetDefinitionAndUpdateE( aSigmaPlus ); break; case 21: currentParticle.SetDefinitionAndUpdateE( aSigmaZero ); break; case 22: currentParticle.SetDefinitionAndUpdateE( aSigmaMinus ); break; } incidentHasChanged = true; switch( ipaky2[i] ) { case 10: vec[i3]->SetDefinition( aKaonPlus ); vec[i3]->SetMayBeKilled(false); break; case 11: vec[i3]->SetDefinition( aKaonZS ); vec[i3]->SetMayBeKilled(false); break; case 12: vec[i3]->SetDefinition( aKaonZL ); vec[i3]->SetMayBeKilled(false); break; } } } } else return true; // // check the available energy // if there is not enough energy for kkb/ky pair production // then reduce the number of secondary particles // NOTE: // the number of secondaries may have been changed // the incident and/or target particles may have changed // charge conservation is ignored (as well as strangness conservation) // currentMass = currentParticle.GetMass()/GeV; targetMass = targetParticle.GetMass()/GeV; G4double energyCheck = centerofmassEnergy-(currentMass+targetMass); for( i=0; iGetMass()/GeV; if( energyCheck < 0.0 ) // chop off the secondary List { vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@ G4int j; for(j=i; j