G4ReactionDynamics Class Reference

#include <G4ReactionDynamics.hh>


Public Member Functions

 G4ReactionDynamics ()
virtual ~G4ReactionDynamics ()
virtual G4double FindInelasticity ()
virtual G4double FindTimeDelay ()
G4bool GenerateXandPt (G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen, G4ReactionProduct &modifiedOriginal, const G4HadProjectile *originalIncident, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, const G4DynamicParticle *originalTarget, const G4Nucleus &targetNucleus, G4bool &incidentHasChanged, G4bool &targetHasChanged, G4bool leadFlag, G4ReactionProduct &leadingStrangeParticle)
void SuppressChargedPions (G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen, const G4ReactionProduct &modifiedOriginal, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, const G4Nucleus &targetNucleus, G4bool &incidentHasChanged, G4bool &targetHasChanged)
G4bool TwoCluster (G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen, G4ReactionProduct &modifiedOriginal, const G4HadProjectile *originalIncident, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, const G4DynamicParticle *originalTarget, const G4Nucleus &targetNucleus, G4bool &incidentHasChanged, G4bool &targetHasChanged, G4bool leadFlag, G4ReactionProduct &leadingStrangeParticle)
void TwoBody (G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen, G4ReactionProduct &modifiedOriginal, const G4DynamicParticle *originalTarget, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, const G4Nucleus &targetNucleus, G4bool &targetHasChanged)
G4int Factorial (G4int n)
G4double GenerateNBodyEvent (const G4double totalEnergy, const G4bool constantCrossSection, G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen)
void ProduceStrangeParticlePairs (G4FastVector< G4ReactionProduct, GHADLISTSIZE > &vec, G4int &vecLen, const G4ReactionProduct &modifiedOriginal, const G4DynamicParticle *originalTarget, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, G4bool &incidentHasChanged, G4bool &targetHasChanged)
void NuclearReaction (G4FastVector< G4ReactionProduct, 4 > &vec, G4int &vecLen, const G4HadProjectile *originalIncident, const G4Nucleus &aNucleus, const G4double theAtomicMass, const G4double *massVec)


Detailed Description

Definition at line 48 of file G4ReactionDynamics.hh.


Constructor & Destructor Documentation

G4ReactionDynamics::G4ReactionDynamics (  )  [inline]

Definition at line 52 of file G4ReactionDynamics.hh.

00052 {}

virtual G4ReactionDynamics::~G4ReactionDynamics (  )  [inline, virtual]

Definition at line 54 of file G4ReactionDynamics.hh.

00054 {}


Member Function Documentation

G4int G4ReactionDynamics::Factorial ( G4int  n  ) 

Definition at line 2743 of file G4ReactionDynamics.cc.

02744    {   // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
02745      G4int mn = std::min(n,10);
02746      G4int result = 1;
02747      if( mn <= 1 )return result;
02748      for( G4int i=2; i<=mn; ++i )result *= i;
02749      return result;
02750    }

virtual G4double G4ReactionDynamics::FindInelasticity (  )  [inline, virtual]

Definition at line 56 of file G4ReactionDynamics.hh.

00057     { return 0.0; }

virtual G4double G4ReactionDynamics::FindTimeDelay (  )  [inline, virtual]

Definition at line 59 of file G4ReactionDynamics.hh.

00060     { return 0.0; }

G4double G4ReactionDynamics::GenerateNBodyEvent ( const G4double  totalEnergy,
const G4bool  constantCrossSection,
G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen 
)

Definition at line 2491 of file G4ReactionDynamics.cc.

References G4cerr, G4endl, G4UniformRand, G4InuclParticleNames::s0, and G4InuclParticleNames::sm.

Referenced by GenerateXandPt(), NuclearReaction(), and TwoCluster().

02496   {
02497       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02498     // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
02499     // Returns the weight of the event
02500     //
02501     G4int i;
02502     const G4double expxu =  82.;           // upper bound for arg. of exp
02503     const G4double expxl = -expxu;         // lower bound for arg. of exp
02504     if( vecLen < 2 )
02505     {
02506       G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
02507       G4cerr << "    number of particles < 2" << G4endl;
02508       G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
02509       return -1.0;
02510     }
02511     G4double mass[18];    // mass of each particle
02512     G4double energy[18];  // total energy of each particle
02513     G4double pcm[3][18];           // pcm is an array with 3 rows and vecLen columns
02514     
02515     G4double totalMass = 0.0;
02516     G4double extraMass = 0;
02517     G4double sm[18];
02518     
02519     for( i=0; i<vecLen; ++i )
02520     {
02521       mass[i] = vec[i]->GetMass()/GeV;
02522       if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
02523       vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
02524       pcm[0][i] = 0.0;      // x-momentum of i-th particle
02525       pcm[1][i] = 0.0;      // y-momentum of i-th particle
02526       pcm[2][i] = 0.0;      // z-momentum of i-th particle
02527       energy[i] = mass[i];  // total energy of i-th particle
02528       totalMass += mass[i];
02529       sm[i] = totalMass;
02530     }
02531     G4double totalE = totalEnergy/GeV;
02532     if( totalMass > totalE )
02533     {
02534       //G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
02535       //G4cerr << "    total mass (" << totalMass*GeV << "MeV) > total energy ("
02536       //     << totalEnergy << "MeV)" << G4endl;
02537       totalE = totalMass;
02538       return -1.0;
02539     }
02540     G4double kineticEnergy = totalE - totalMass;
02541     G4double emm[18];
02542     //G4double *emm = new G4double [vecLen];
02543     emm[0] = mass[0];
02544     emm[vecLen-1] = totalE;
02545     if( vecLen > 2 )          // the random numbers are sorted
02546     {
02547       G4double ran[18];
02548       for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
02549       for( i=0; i<vecLen-2; ++i )
02550       {
02551         for( G4int j=vecLen-2; j>i; --j )
02552         {
02553           if( ran[i] > ran[j] )
02554           {
02555             G4double temp = ran[i];
02556             ran[i] = ran[j];
02557             ran[j] = temp;
02558           }
02559         }
02560       }
02561       for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
02562     }
02563     //   Weight is the sum of logarithms of terms instead of the product of terms
02564     G4bool lzero = true;    
02565     G4double wtmax = 0.0;
02566     if( constantCrossSection )     // this is KGENEV=1 in PHASP
02567     {
02568       G4double emmax = kineticEnergy + mass[0];
02569       G4double emmin = 0.0;
02570       for( i=1; i<vecLen; ++i )
02571       {
02572         emmin += mass[i-1];
02573         emmax += mass[i];
02574         G4double wtfc = 0.0;
02575         if( emmax*emmax > 0.0 )
02576         {
02577           G4double arg = emmax*emmax
02578             + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
02579             - 2.0*(emmin*emmin+mass[i]*mass[i]);
02580           if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
02581         }
02582         if( wtfc == 0.0 )
02583         {
02584           lzero = false;
02585           break;
02586         }
02587         wtmax += std::log( wtfc );
02588       }
02589       if( lzero )
02590         wtmax = -wtmax;
02591       else
02592         wtmax = expxu;
02593     }
02594     else
02595     {
02596       //   ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
02597       const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
02598                                  256.3704, 268.4705, 240.9780, 189.2637,
02599                                  132.1308,  83.0202,  47.4210,  24.8295,
02600                                  12.0006,   5.3858,   2.2560,   0.8859 };
02601       wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
02602     }
02603     lzero = true;
02604     G4double pd[50];
02605     //G4double *pd = new G4double [vecLen-1];
02606     for( i=0; i<vecLen-1; ++i )
02607     {
02608       pd[i] = 0.0;
02609       if( emm[i+1]*emm[i+1] > 0.0 )
02610       {
02611         G4double arg = emm[i+1]*emm[i+1]
02612           + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
02613             /(emm[i+1]*emm[i+1])
02614           - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
02615         if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
02616       }
02617       if( pd[i] <= 0.0 )    //  changed from  ==  on 02 April 98
02618         lzero = false;
02619       else
02620         wtmax += std::log( pd[i] );
02621     }
02622     G4double weight = 0.0;           // weight is returned by GenerateNBodyEvent
02623     if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
02624     
02625     G4double bang, cb, sb, s0, s1, s2, c, ss, esys, a, b, gama, beta;
02626     pcm[0][0] = 0.0;
02627     pcm[1][0] = pd[0];
02628     pcm[2][0] = 0.0;
02629     for( i=1; i<vecLen; ++i )
02630     {
02631       pcm[0][i] = 0.0;
02632       pcm[1][i] = -pd[i-1];
02633       pcm[2][i] = 0.0;
02634       bang = twopi*G4UniformRand();
02635       cb = std::cos(bang);
02636       sb = std::sin(bang);
02637       c = 2.0*G4UniformRand() - 1.0;
02638       ss = std::sqrt( std::fabs( 1.0-c*c ) );
02639       if( i < vecLen-1 )
02640       {
02641         esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
02642         beta = pd[i]/esys;
02643         gama = esys/emm[i];
02644         for( G4int j=0; j<=i; ++j )
02645         {
02646           s0 = pcm[0][j];
02647           s1 = pcm[1][j];
02648           s2 = pcm[2][j];
02649           energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
02650           a = s0*c - s1*ss;                           //  rotation
02651           pcm[1][j] = s0*ss + s1*c;
02652           b = pcm[2][j];
02653           pcm[0][j] = a*cb - b*sb;
02654           pcm[2][j] = a*sb + b*cb;
02655           pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
02656         }
02657       }
02658       else
02659       {
02660         for( G4int j=0; j<=i; ++j )
02661         {
02662           s0 = pcm[0][j];
02663           s1 = pcm[1][j];
02664           s2 = pcm[2][j];
02665           energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
02666           a = s0*c - s1*ss;                           //  rotation
02667           pcm[1][j] = s0*ss + s1*c;
02668           b = pcm[2][j];
02669           pcm[0][j] = a*cb - b*sb;
02670           pcm[2][j] = a*sb + b*cb;
02671         }
02672       }
02673     }
02674     for( i=0; i<vecLen; ++i )
02675     {
02676       vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
02677       vec[i]->SetTotalEnergy( energy[i]*GeV );
02678     }
02679 
02680       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02681     return weight;
02682   }

G4bool G4ReactionDynamics::GenerateXandPt ( G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen,
G4ReactionProduct modifiedOriginal,
const G4HadProjectile originalIncident,
G4ReactionProduct currentParticle,
G4ReactionProduct targetParticle,
const G4DynamicParticle originalTarget,
const G4Nucleus targetNucleus,
G4bool incidentHasChanged,
G4bool targetHasChanged,
G4bool  leadFlag,
G4ReactionProduct leadingStrangeParticle 
)

Definition at line 105 of file G4ReactionDynamics.cc.

References FatalException, G4cerr, G4endl, G4Exception(), G4UniformRand, GenerateNBodyEvent(), G4Nucleus::GetA_asInt(), G4Nucleus::GetAnnihilationDTABlackTrackEnergy(), G4Nucleus::GetAnnihilationPNBlackTrackEnergy(), G4ParticleDefinition::GetBaryonNumber(), G4HadProjectile::GetDefinition(), G4ReactionProduct::GetDefinition(), G4Nucleus::GetDTABlackTrackEnergy(), G4HadProjectile::GetKineticEnergy(), G4ReactionProduct::GetKineticEnergy(), G4ReactionProduct::GetMass(), G4ReactionProduct::GetMomentum(), G4Nucleus::GetN_asInt(), G4ParticleDefinition::GetParticleSubType(), G4ParticleDefinition::GetPDGMass(), G4Nucleus::GetPNBlackTrackEnergy(), G4ReactionProduct::GetSide(), G4ReactionProduct::GetTotalEnergy(), G4ReactionProduct::GetTotalMomentum(), G4Nucleus::GetZ_asInt(), G4FastVector< Type, N >::Initialize(), G4Lambda::Lambda(), G4ReactionProduct::Lorentz(), G4Neutron::Neutron(), G4INCL::Math::pi, G4PionMinus::PionMinus(), G4PionPlus::PionPlus(), G4PionZero::PionZero(), G4InuclParticleNames::pp, G4Proton::Proton(), G4ReactionProduct::SetDefinitionAndUpdateE(), G4FastVector< Type, N >::SetElement(), G4ReactionProduct::SetKineticEnergy(), G4ReactionProduct::SetMass(), G4ReactionProduct::SetMomentum(), G4ReactionProduct::SetSide(), G4ReactionProduct::SetTotalEnergy(), G4ReactionProduct::SetZero(), and sqr().

Referenced by G4InelasticInteraction::CalculateMomenta().

00118   {
00119     // 
00120     // derived from original FORTRAN code GENXPT by H. Fesefeldt (11-Oct-1987)
00121     //
00122     //  Generation of X- and PT- values for incident, target, and all secondary particles 
00123     //  A simple single variable description E D3S/DP3= F(Q) with
00124     //  Q^2 = (M*X)^2 + PT^2 is used. Final state kinematic is produced
00125     //  by an FF-type iterative cascade method
00126     //
00127     //  internal units are GeV
00128     //
00129     // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00130     
00131     // Protection in case no secondary has been created; cascades down to two-body.
00132     if(vecLen == 0) return false;
00133 
00134     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
00135     G4ParticleDefinition *aProton = G4Proton::Proton();
00136     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
00137     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
00138     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
00139 
00140     G4int i, l;
00141     G4bool veryForward = false;
00142     
00143     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
00144     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
00145     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
00146     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
00147     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
00148     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
00149                                         targetMass*targetMass +
00150                                         2.0*targetMass*etOriginal );  // GeV
00151     G4double currentMass = currentParticle.GetMass()/GeV;
00152     targetMass = targetParticle.GetMass()/GeV;
00153     //
00154     //  randomize the order of the secondary particles
00155     //  note that the current and target particles are not affected
00156     //
00157     for( i=0; i<vecLen; ++i )
00158     {
00159       G4int itemp = G4int( G4UniformRand()*vecLen );
00160       G4ReactionProduct pTemp = *vec[itemp];
00161       *vec[itemp] = *vec[i];
00162       *vec[i] = pTemp;
00163       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00164     }
00165 
00166     if( currentMass == 0.0 && targetMass == 0.0 )
00167     {
00168       // Target and projectile have annihilated.  Replace them with the first 
00169       // two secondaries in the list.  Current particle KE is maintained.
00170  
00171       G4double ek = currentParticle.GetKineticEnergy();
00172       G4ThreeVector mom = currentParticle.GetMomentum();
00173       currentParticle = *vec[0];
00174       targetParticle = *vec[1];
00175       for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
00176       G4ReactionProduct *temp = vec[vecLen-1];
00177       delete temp;
00178       temp = vec[vecLen-2];
00179       delete temp;
00180       vecLen -= 2;
00181       currentMass = currentParticle.GetMass()/GeV;
00182       targetMass = targetParticle.GetMass()/GeV;
00183       incidentHasChanged = true;
00184       targetHasChanged = true;
00185       currentParticle.SetKineticEnergy( ek );
00186       currentParticle.SetMomentum( mom );
00187       veryForward = true;
00188     }
00189     const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
00190     const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
00191     const G4double protonMass = aProton->GetPDGMass()/MeV;
00192 
00193     if (originalIncident->GetDefinition()->GetParticleSubType() == "kaon"
00194         && G4UniformRand() >= 0.7) {
00195       G4ReactionProduct temp = currentParticle;
00196       currentParticle = targetParticle;
00197       targetParticle = temp;
00198       incidentHasChanged = true;
00199       targetHasChanged = true;
00200       currentMass = currentParticle.GetMass()/GeV;
00201       targetMass = targetParticle.GetMass()/GeV;
00202     }
00203     const G4double afc = std::min( 0.75,
00204           0.312+0.200*std::log(std::log(centerofmassEnergy*centerofmassEnergy))+
00205           std::pow(centerofmassEnergy*centerofmassEnergy,1.5)/6000.0 );
00206     
00207     G4double freeEnergy = centerofmassEnergy-currentMass-targetMass;
00208     G4double forwardEnergy = freeEnergy/2.;
00209     G4int forwardCount = 1;         // number of particles in forward hemisphere
00210     
00211     G4double backwardEnergy = freeEnergy/2.;
00212     G4int backwardCount = 1;        // number of particles in backward hemisphere
00213 
00214     if(veryForward)
00215     {
00216       if(currentParticle.GetSide()==-1)
00217       {
00218         forwardEnergy += currentMass;
00219         forwardCount --;
00220         backwardEnergy -= currentMass;
00221         backwardCount ++;
00222       }
00223       if(targetParticle.GetSide()!=-1)
00224       {
00225         backwardEnergy += targetMass;
00226         backwardCount --;
00227         forwardEnergy -= targetMass;
00228         forwardCount ++;
00229       }
00230     }
00231 
00232     for( i=0; i<vecLen; ++i )
00233     {
00234       if( vec[i]->GetSide() == -1 )
00235       {
00236         ++backwardCount;
00237         backwardEnergy -= vec[i]->GetMass()/GeV;
00238       } else {
00239         ++forwardCount;
00240         forwardEnergy -= vec[i]->GetMass()/GeV;
00241       }
00242     }
00243     //
00244     //  Add particles from intranuclear cascade.
00245     //  nuclearExcitationCount = number of new secondaries produced by nuclear excitation
00246     //  extraCount = number of nucleons within these new secondaries
00247     //
00248     G4double xtarg;
00249     if( centerofmassEnergy < (2.0+G4UniformRand()) )
00250       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount+vecLen+2)/2.0;
00251     else
00252       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount);
00253     if( xtarg <= 0.0 )xtarg = 0.01;
00254     G4int nuclearExcitationCount = Poisson( xtarg );
00255     if(atomicWeight<1.0001) nuclearExcitationCount = 0;
00256     G4int extraNucleonCount = 0;
00257     G4double extraNucleonMass = 0.0;
00258     if( nuclearExcitationCount > 0 )
00259     {
00260       const G4double nucsup[] = { 1.00, 0.7, 0.5, 0.4, 0.35, 0.3 };
00261       const G4double psup[] = { 3., 6., 20., 50., 100., 1000. };
00262       G4int momentumBin = 0;
00263       while( (momentumBin < 6) &&
00264              (modifiedOriginal.GetTotalMomentum()/GeV > psup[momentumBin]) )
00265         ++momentumBin;
00266       momentumBin = std::min( 5, momentumBin );
00267       //
00268       //  NOTE: in GENXPT, these new particles were given negative codes
00269       //        here I use  NewlyAdded = true  instead
00270       //
00271 
00272       for( i=0; i<nuclearExcitationCount; ++i )
00273       {
00274         G4ReactionProduct * pVec = new G4ReactionProduct();
00275         if( G4UniformRand() < nucsup[momentumBin] )
00276         {
00277           if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
00278             pVec->SetDefinition( aProton );
00279           else
00280             pVec->SetDefinition( aNeutron );
00281           pVec->SetSide( -2 );                // -2 means backside nucleon
00282           ++extraNucleonCount;
00283           backwardEnergy += pVec->GetMass()/GeV;
00284           extraNucleonMass += pVec->GetMass()/GeV;
00285         }
00286         else
00287         {
00288           G4double ran = G4UniformRand();
00289           if( ran < 0.3181 )
00290             pVec->SetDefinition( aPiPlus );
00291           else if( ran < 0.6819 )
00292             pVec->SetDefinition( aPiZero );
00293           else
00294             pVec->SetDefinition( aPiMinus );
00295           pVec->SetSide( -1 );                // backside particle, but not a nucleon
00296         }
00297         pVec->SetNewlyAdded( true );                // true is the same as IPA(i)<0
00298         vec.SetElement( vecLen++, pVec );    
00299         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00300         backwardEnergy -= pVec->GetMass()/GeV;
00301         ++backwardCount;
00302       }
00303     }
00304     //
00305     //  assume conservation of kinetic energy in forward & backward hemispheres
00306     //
00307     G4int is, iskip;
00308     while( forwardEnergy <= 0.0 )  // must eliminate a particle from the forward side
00309     {
00310       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00311       iskip = G4int(G4UniformRand()*forwardCount) + 1; // 1 <= iskip <= forwardCount
00312       is = 0;
00313       G4int forwardParticlesLeft = 0;
00314       for( i=(vecLen-1); i>=0; --i )
00315       {
00316         if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
00317         {
00318           forwardParticlesLeft = 1;  
00319           if( ++is == iskip )
00320           { 
00321             forwardEnergy += vec[i]->GetMass()/GeV;
00322             for( G4int j=i; j<(vecLen-1); j++ )*vec[j] = *vec[j+1];    // shift up
00323             --forwardCount;
00324             delete vec[vecLen-1];
00325             if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00326             break;  // --+
00327           }         //   |
00328         }           //   |
00329       }             // break goes down to here
00330       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00331       if( forwardParticlesLeft == 0 )
00332       {
00333         G4int iremove = -1;
00334         for (i = 0; i < vecLen; i++) {
00335           if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
00336             iremove = i;
00337             break;
00338           }
00339         }
00340         if (iremove == -1) {
00341           for (i = 0; i < vecLen; i++) {
00342             if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
00343               iremove = i;
00344               break;
00345             }
00346           }
00347         }
00348         if (iremove == -1) iremove = 0;
00349 
00350         forwardEnergy += vec[iremove]->GetMass()/GeV;
00351         if (vec[iremove]->GetSide() > 0) --forwardCount;
00352  
00353         for (i = iremove; i < vecLen-1; i++) *vec[i] = *vec[i+1];
00354         delete vec[vecLen-1];
00355         vecLen--;
00356         if (vecLen == 0) return false;  // all secondaries have been eliminated
00357         break;
00358       }
00359     } // while
00360 
00361       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00362     while( backwardEnergy <= 0.0 )  // must eliminate a particle from the backward side
00363     {
00364       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00365       iskip = G4int(G4UniformRand()*backwardCount) + 1; // 1 <= iskip <= backwardCount
00366       is = 0;
00367       G4int backwardParticlesLeft = 0;
00368       for( i=(vecLen-1); i>=0; --i )
00369       {
00370         if( vec[i]->GetSide() < 0 && vec[i]->GetMayBeKilled())
00371         {
00372           backwardParticlesLeft = 1;
00373           if( ++is == iskip )        // eliminate the i'th particle
00374           {
00375             if( vec[i]->GetSide() == -2 )
00376             {
00377               --extraNucleonCount;
00378               extraNucleonMass -= vec[i]->GetMass()/GeV;
00379               backwardEnergy -= vec[i]->GetTotalEnergy()/GeV;
00380             }
00381             backwardEnergy += vec[i]->GetTotalEnergy()/GeV;
00382             for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];   // shift up
00383             --backwardCount;
00384             delete vec[vecLen-1];
00385             if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00386             break;
00387           }
00388         }
00389       }
00390       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00391       if( backwardParticlesLeft == 0 )
00392       {
00393         G4int iremove = -1;
00394         for (i = 0; i < vecLen; i++) {
00395           if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
00396             iremove = i;
00397             break;
00398           }
00399         }
00400         if (iremove == -1) {
00401           for (i = 0; i < vecLen; i++) {
00402             if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
00403               iremove = i;
00404               break;
00405             }
00406           }
00407         }
00408         if (iremove == -1) iremove = 0;
00409  
00410         backwardEnergy += vec[iremove]->GetMass()/GeV;
00411         if (vec[iremove]->GetSide() > 0) --backwardCount;
00412  
00413         for (i = iremove; i < vecLen-1; i++) *vec[i] = *vec[i+1];
00414         delete vec[vecLen-1];
00415         vecLen--;
00416         if (vecLen == 0) return false;  // all secondaries have been eliminated
00417         break;
00418       }
00419     } // while
00420 
00421       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00422     //
00423     //  define initial state vectors for Lorentz transformations
00424     //  the pseudoParticles have non-standard masses, hence the "pseudo"
00425     //
00426     G4ReactionProduct pseudoParticle[10];
00427     for( i=0; i<10; ++i )pseudoParticle[i].SetZero();
00428     
00429     pseudoParticle[0].SetMass( mOriginal*GeV );
00430     pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
00431     pseudoParticle[0].SetTotalEnergy(
00432      std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
00433     
00434     pseudoParticle[1].SetMass( protonMass*MeV );        // this could be targetMass
00435     pseudoParticle[1].SetTotalEnergy( protonMass*MeV );
00436     
00437     pseudoParticle[3].SetMass( protonMass*(1+extraNucleonCount)*MeV );
00438     pseudoParticle[3].SetTotalEnergy( protonMass*(1+extraNucleonCount)*MeV );
00439     
00440     pseudoParticle[8].SetMomentum( 1.0*GeV, 0.0, 0.0 );
00441     
00442     pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
00443     pseudoParticle[3] = pseudoParticle[3] + pseudoParticle[0];
00444     
00445     pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
00446     pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
00447     
00448     G4double dndl[20];
00449     //
00450     //  main loop for 4-momentum generation
00451     //  see Pitha-report (Aachen) for a detailed description of the method
00452     //
00453     G4double aspar, pt, et, x, pp, pp1, rmb, wgt;
00454     G4int    innerCounter, outerCounter;
00455     G4bool   eliminateThisParticle, resetEnergies, constantCrossSection;
00456     
00457     G4double forwardKinetic = 0.0, backwardKinetic = 0.0;
00458     //
00459     // process the secondary particles in reverse order
00460     // the incident particle is Done after the secondaries
00461     // nucleons, including the target, in the backward hemisphere are also Done later
00462     //
00463     G4double binl[20] = {0.,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.11,1.25,
00464                          1.43,1.67,2.0,2.5,3.33,5.00,10.00};
00465     G4int backwardNucleonCount = 0;       // number of nucleons in backward hemisphere
00466     G4double totalEnergy, kineticEnergy, vecMass;
00467 
00468     for( i=(vecLen-1); i>=0; --i )
00469     {
00470       G4double phi = G4UniformRand()*twopi;
00471       if( vec[i]->GetNewlyAdded() )           // added from intranuclear cascade
00472       {
00473         if( vec[i]->GetSide() == -2 )         //  is a nucleon
00474         {
00475           if( backwardNucleonCount < 18 )
00476           {
00477             if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
00478               for(G4int j=0; j<vecLen; j++) delete vec[j];
00479               vecLen = 0;
00480               throw G4HadReentrentException(__FILE__, __LINE__,
00481               "G4ReactionDynamics::GenerateXandPt : a pion has been counted as a backward nucleon");
00482             }
00483             vec[i]->SetSide( -3 );
00484             ++backwardNucleonCount;
00485             continue;
00486           }
00487         }
00488       }
00489       //
00490       //  set pt and phi values, they are changed somewhat in the iteration loop
00491       //  set mass parameter for lambda fragmentation model
00492       //
00493       vecMass = vec[i]->GetMass()/GeV;
00494       G4double ran = -std::log(1.0-G4UniformRand())/3.5;
00495       if( vec[i]->GetSide() == -2 )   // backward nucleon
00496       {
00497         if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon" ||
00498             vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
00499           aspar = 0.75;
00500           pt = std::sqrt( std::pow( ran, 1.7 ) );
00501         } else {                          // vec[i] must be a proton, neutron,
00502           aspar = 0.20;                   //  lambda, sigma, xsi, or ion
00503           pt = std::sqrt( std::pow( ran, 1.2 ) );
00504         }
00505 
00506       } else {                          // not a backward nucleon
00507 
00508         if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
00509           aspar = 0.75;
00510           pt = std::sqrt( std::pow( ran, 1.7 ) );
00511         } else if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
00512           aspar = 0.70;
00513           pt = std::sqrt( std::pow( ran, 1.7 ) );
00514         } else {                        // vec[i] must be a proton, neutron, 
00515           aspar = 0.65;                 //  lambda, sigma, xsi, or ion
00516           pt = std::sqrt( std::pow( ran, 1.5 ) );
00517         }
00518       }
00519       pt = std::max( 0.001, pt );
00520       vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00521       for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
00522       if( vec[i]->GetSide() > 0 )
00523         et = pseudoParticle[0].GetTotalEnergy()/GeV;
00524       else
00525         et = pseudoParticle[1].GetTotalEnergy()/GeV;
00526       dndl[0] = 0.0;
00527       //
00528       //   start of outer iteration loop
00529       //
00530       outerCounter = 0;
00531       eliminateThisParticle = true;
00532       resetEnergies = true;
00533       while( ++outerCounter < 3 )
00534       {
00535         for( l=1; l<20; ++l )
00536         {
00537           x = (binl[l]+binl[l-1])/2.;
00538           pt = std::max( 0.001, pt );
00539           if( x > 1.0/pt )
00540             dndl[l] += dndl[l-1];   //  changed from just  =  on 02 April 98
00541           else
00542             dndl[l] = et * aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) )
00543               * (binl[l]-binl[l-1]) / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass )
00544               + dndl[l-1];
00545         }
00546         innerCounter = 0;
00547         vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00548         //
00549         //   start of inner iteration loop
00550         //
00551         while( ++innerCounter < 7 )
00552         {
00553           ran = G4UniformRand()*dndl[19];
00554           l = 1;
00555           while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
00556           l = std::min( 19, l );
00557           x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1]) ) );
00558           if( vec[i]->GetSide() < 0 )x *= -1.;
00559           vec[i]->SetMomentum( x*et*GeV );              // set the z-momentum
00560           totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
00561           vec[i]->SetTotalEnergy( totalEnergy*GeV );
00562           kineticEnergy = vec[i]->GetKineticEnergy()/GeV;
00563           if( vec[i]->GetSide() > 0 )                            // forward side
00564           {
00565             if( (forwardKinetic+kineticEnergy) < 0.95*forwardEnergy )
00566             {
00567               pseudoParticle[4] = pseudoParticle[4] + (*vec[i]);
00568               forwardKinetic += kineticEnergy;
00569               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00570               pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
00571               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00572               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00573               phi += pi + normal()*pi/12.0;
00574               if( phi > twopi )phi -= twopi;
00575               if( phi < 0.0 )phi = twopi - phi;
00576               outerCounter = 2;                     // leave outer loop
00577               eliminateThisParticle = false;        // don't eliminate this particle
00578               resetEnergies = false;
00579               break;                                // leave inner loop
00580             }
00581             if( innerCounter > 5 )break;           // leave inner loop
00582             if( backwardEnergy >= vecMass )  // switch sides
00583             {
00584               vec[i]->SetSide( -1 );
00585               forwardEnergy += vecMass;
00586               backwardEnergy -= vecMass;
00587               ++backwardCount;
00588             }
00589           } else {                                                 // backward side
00590            if( extraNucleonCount > 19 )   // commented out to duplicate ?bug? in GENXPT
00591              x = 0.999;
00592            G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
00593            if( (backwardKinetic+kineticEnergy) < xxx*backwardEnergy )
00594             {
00595               pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
00596               backwardKinetic += kineticEnergy;
00597               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00598               pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
00599               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00600               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00601               phi += pi + normal() * pi / 12.0;
00602               if( phi > twopi )phi -= twopi;
00603               if( phi < 0.0 )phi = twopi - phi;
00604               outerCounter = 2;                    // leave outer loop
00605               eliminateThisParticle = false;       // don't eliminate this particle
00606               resetEnergies = false;
00607               break;                               // leave inner loop
00608             }
00609             if( innerCounter > 5 )break;           // leave inner loop
00610             if( forwardEnergy >= vecMass )  // switch sides
00611             {
00612               vec[i]->SetSide( 1 );
00613               forwardEnergy -= vecMass;
00614               backwardEnergy += vecMass;
00615               backwardCount--;
00616             }
00617           }
00618           G4ThreeVector momentum = vec[i]->GetMomentum();
00619           vec[i]->SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
00620           pt *= 0.9;
00621           dndl[19] *= 0.9;
00622         }                       // closes inner loop
00623         if( resetEnergies )
00624         {
00625           //   if we get to here, the inner loop has been Done 6 Times
00626           //   reset the kinetic energies of previously Done particles, if they are lighter
00627           //    than protons and in the forward hemisphere
00628           //   then continue with outer loop
00629           //
00630           forwardKinetic = 0.0;
00631           backwardKinetic = 0.0;
00632           pseudoParticle[4].SetZero();
00633           pseudoParticle[5].SetZero();
00634           for( l=i+1; l<vecLen; ++l )
00635           {
00636             if (vec[l]->GetSide() > 0 ||
00637                 vec[l]->GetDefinition()->GetParticleSubType() == "kaon" ||
00638                 vec[l]->GetDefinition()->GetParticleSubType() == "pi") {
00639 
00640               G4double tempMass = vec[l]->GetMass()/MeV;
00641               totalEnergy = 0.95*vec[l]->GetTotalEnergy()/MeV + 0.05*tempMass;
00642               totalEnergy = std::max( tempMass, totalEnergy );
00643               vec[l]->SetTotalEnergy( totalEnergy*MeV );
00644               pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) );
00645               pp1 = vec[l]->GetMomentum().mag()/MeV;
00646               if( pp1 < 1.0e-6*GeV )
00647               {
00648                 G4double costheta = 2.*G4UniformRand() - 1.;
00649                 G4double sintheta = std::sqrt(1. - costheta*costheta);
00650                 G4double phi2 = twopi*G4UniformRand();
00651                 vec[l]->SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
00652                                      pp*sintheta*std::sin(phi2)*MeV,
00653                                      pp*costheta*MeV ) ;
00654               } else {
00655                 vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
00656               }
00657               G4double px = vec[l]->GetMomentum().x()/MeV;
00658               G4double py = vec[l]->GetMomentum().y()/MeV;
00659               pt = std::max( 1.0, std::sqrt( px*px + py*py ) )/GeV;
00660               if( vec[l]->GetSide() > 0 )
00661               {
00662                 forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00663                 pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
00664               } else {
00665                 backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00666                 pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
00667               }
00668             } // if pi, K or forward
00669           } // for l
00670         } // if resetEnergies
00671       } // closes outer loop
00672               
00673       if( eliminateThisParticle && vec[i]->GetMayBeKilled())  // not enough energy, eliminate this particle
00674       {
00675         if( vec[i]->GetSide() > 0 )
00676         {
00677           --forwardCount;
00678           forwardEnergy += vecMass;
00679         } else {
00680           if( vec[i]->GetSide() == -2 )
00681           {
00682             --extraNucleonCount;
00683             extraNucleonMass -= vecMass;
00684             backwardEnergy -= vecMass;
00685           }
00686           --backwardCount;
00687           backwardEnergy += vecMass;
00688         }
00689         for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
00690         G4ReactionProduct *temp = vec[vecLen-1];
00691         delete temp;
00692         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00693         if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00694         pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00695         pseudoParticle[6].SetMomentum( 0.0 );                 // set z-momentum
00696         phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00697         if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00698         phi += pi + normal() * pi / 12.0;
00699         if( phi > twopi )phi -= twopi;
00700         if( phi < 0.0 )phi = twopi - phi;
00701       }
00702     }   // closes main for loop
00703 
00704     //
00705     //  for the incident particle:  it was placed in the forward hemisphere
00706     //   set pt and phi values, they are changed somewhat in the iteration loop
00707     //   set mass parameter for lambda fragmentation model
00708     //
00709     G4double phi = G4UniformRand()*twopi;
00710     G4double ran = -std::log(1.0-G4UniformRand());
00711     if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
00712       aspar = 0.60;
00713       pt = std::sqrt( std::pow( ran/6.0, 1.7 ) );
00714     } else if (currentParticle.GetDefinition()->GetParticleSubType() == "kaon") {
00715       aspar = 0.50;
00716       pt = std::sqrt( std::pow( ran/5.0, 1.4 ) );
00717     } else {
00718       aspar = 0.40;
00719       pt = std::sqrt( std::pow( ran/4.0, 1.2 ) );
00720     }
00721 
00722     for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
00723     currentParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00724     et = pseudoParticle[0].GetTotalEnergy()/GeV;
00725     dndl[0] = 0.0;
00726     vecMass = currentParticle.GetMass()/GeV;
00727     for( l=1; l<20; ++l )
00728     {
00729       x = (binl[l]+binl[l-1])/2.;
00730       if( x > 1.0/pt )
00731         dndl[l] += dndl[l-1];   //  changed from just  =   on 02 April 98
00732       else
00733         dndl[l] = aspar/std::sqrt( std::pow((1.+sqr(aspar*x)),3) ) *
00734           (binl[l]-binl[l-1]) * et / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass ) +
00735           dndl[l-1];
00736     }
00737     ran = G4UniformRand()*dndl[19];
00738     l = 1;
00739     while( (ran>dndl[l]) && (l<20) )l++;
00740     l = std::min( 19, l );
00741     x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1]) ) );
00742     currentParticle.SetMomentum( x*et*GeV );                 // set the z-momentum
00743     if( forwardEnergy < forwardKinetic )
00744       totalEnergy = vecMass + 0.04*std::fabs(normal());
00745     else
00746       totalEnergy = vecMass + forwardEnergy - forwardKinetic;
00747     currentParticle.SetTotalEnergy( totalEnergy*GeV );
00748     pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00749     pp1 = currentParticle.GetMomentum().mag()/MeV;
00750     if( pp1 < 1.0e-6*GeV )
00751     {
00752       G4double costheta = 2.*G4UniformRand() - 1.;
00753       G4double sintheta = std::sqrt(1. - costheta*costheta);
00754       G4double phi2 = twopi*G4UniformRand();
00755       currentParticle.SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
00756                                    pp*sintheta*std::sin(phi2)*MeV,
00757                                    pp*costheta*MeV ) ;
00758     } else {
00759       currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
00760     }
00761     pseudoParticle[4] = pseudoParticle[4] + currentParticle;
00762 
00763     //
00764     // Current particle now finished
00765     //
00766     // Begin target particle
00767     //
00768 
00769     if( backwardNucleonCount < 18 )
00770     {
00771       targetParticle.SetSide( -3 );
00772       ++backwardNucleonCount;
00773     }
00774     else
00775     {
00776       //  set pt and phi values, they are changed somewhat in the iteration loop
00777       //  set mass parameter for lambda fragmentation model
00778       //
00779       vecMass = targetParticle.GetMass()/GeV;
00780       ran = -std::log(1.0-G4UniformRand());
00781       aspar = 0.40;
00782       pt = std::max( 0.001, std::sqrt( std::pow( ran/4.0, 1.2 ) ) );
00783       targetParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00784       for( G4int j=0; j<20; ++j )binl[j] = (j-1.)/(19.*pt);
00785       et = pseudoParticle[1].GetTotalEnergy()/GeV;
00786       dndl[0] = 0.0;
00787       outerCounter = 0;
00788       eliminateThisParticle = true;     // should never eliminate the target particle
00789       resetEnergies = true;
00790       while( ++outerCounter < 3 )     // start of outer iteration loop
00791       {
00792         for( l=1; l<20; ++l )
00793         {
00794           x = (binl[l]+binl[l-1])/2.;
00795           if( x > 1.0/pt )
00796             dndl[l] += dndl[l-1];   // changed from just  =  on 02 April 98
00797           else
00798             dndl[l] = aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) ) *
00799               (binl[l]-binl[l-1])*et / std::sqrt( pt*x*et*pt*x*et+pt*pt+vecMass*vecMass ) +
00800               dndl[l-1];
00801         }
00802         innerCounter = 0;
00803         while( ++innerCounter < 7 )    // start of inner iteration loop
00804         {
00805           l = 1;
00806           ran = G4UniformRand()*dndl[19];
00807           while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
00808           l = std::min( 19, l );
00809           x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1]) ) );
00810           if( targetParticle.GetSide() < 0 )x *= -1.;
00811           targetParticle.SetMomentum( x*et*GeV );                // set the z-momentum
00812           totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
00813           targetParticle.SetTotalEnergy( totalEnergy*GeV );
00814           if( targetParticle.GetSide() < 0 )
00815           {
00816             if( extraNucleonCount > 19 )x=0.999;
00817             G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
00818             if( (backwardKinetic+totalEnergy-vecMass) < xxx*backwardEnergy )
00819             {
00820               pseudoParticle[5] = pseudoParticle[5] + targetParticle;
00821               backwardKinetic += totalEnergy - vecMass;
00822               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00823               pseudoParticle[6].SetMomentum( 0.0 );                      // set z-momentum
00824               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00825               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00826               phi += pi + normal() * pi / 12.0;
00827               if( phi > twopi )phi -= twopi;
00828               if( phi < 0.0 )phi = twopi - phi;
00829               outerCounter = 2;                    // leave outer loop
00830               eliminateThisParticle = false;       // don't eliminate this particle
00831               resetEnergies = false;
00832               break;                               // leave inner loop
00833             }
00834             if( innerCounter > 5 )break;           // leave inner loop
00835             if( forwardEnergy >= vecMass )  // switch sides
00836             {
00837               targetParticle.SetSide( 1 );
00838               forwardEnergy -= vecMass;
00839               backwardEnergy += vecMass;
00840               --backwardCount;
00841             }
00842             G4ThreeVector momentum = targetParticle.GetMomentum();
00843             targetParticle.SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
00844             pt *= 0.9;
00845             dndl[19] *= 0.9;
00846           }
00847           else                    // target has gone to forward side
00848           {
00849             if( forwardEnergy < forwardKinetic )
00850               totalEnergy = vecMass + 0.04*std::fabs(normal());
00851             else
00852               totalEnergy = vecMass + forwardEnergy - forwardKinetic;
00853             targetParticle.SetTotalEnergy( totalEnergy*GeV );
00854             pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00855             pp1 = targetParticle.GetMomentum().mag()/MeV;
00856             if( pp1 < 1.0e-6*GeV )
00857             {
00858               G4double costheta = 2.*G4UniformRand() - 1.;
00859               G4double sintheta = std::sqrt(1. - costheta*costheta);
00860               G4double phi2 = twopi*G4UniformRand();
00861               targetParticle.SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
00862                                           pp*sintheta*std::sin(phi2)*MeV,
00863                                           pp*costheta*MeV ) ;
00864             }
00865             else
00866               targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
00867 
00868             pseudoParticle[4] = pseudoParticle[4] + targetParticle;
00869             outerCounter = 2;                    // leave outer loop
00870             eliminateThisParticle = false;       // don't eliminate this particle
00871             resetEnergies = false;
00872             break;                               // leave inner loop
00873           }
00874         }    // closes inner loop
00875         if( resetEnergies )
00876         {
00877           //   if we get to here, the inner loop has been Done 6 Times
00878           //   reset the kinetic energies of previously Done particles, if they are lighter
00879           //    than protons and in the forward hemisphere
00880           //   then continue with outer loop
00881           
00882           forwardKinetic = backwardKinetic = 0.0;
00883           pseudoParticle[4].SetZero();
00884           pseudoParticle[5].SetZero();
00885           for( l=0; l<vecLen; ++l ) // changed from l=1  on 02 April 98
00886           {
00887             if (vec[l]->GetSide() > 0 ||
00888                 vec[l]->GetDefinition()->GetParticleSubType() == "kaon" ||
00889                 vec[l]->GetDefinition()->GetParticleSubType() == "pi") {
00890               G4double tempMass = vec[l]->GetMass()/GeV;
00891               totalEnergy =
00892                 std::max( tempMass, 0.95*vec[l]->GetTotalEnergy()/GeV + 0.05*tempMass );
00893               vec[l]->SetTotalEnergy( totalEnergy*GeV );
00894               pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) )*GeV;
00895               pp1 = vec[l]->GetMomentum().mag()/MeV;
00896               if( pp1 < 1.0e-6*GeV )
00897               {
00898                 G4double costheta = 2.*G4UniformRand() - 1.;
00899                 G4double sintheta = std::sqrt(1. - costheta*costheta);
00900                 G4double phi2 = twopi*G4UniformRand();
00901                 vec[l]->SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
00902                                      pp*sintheta*std::sin(phi2)*MeV,
00903                                      pp*costheta*MeV ) ;
00904               }
00905               else
00906                 vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
00907 
00908               pt = std::max( 0.001*GeV, std::sqrt( sqr(vec[l]->GetMomentum().x()/MeV) +
00909                                          sqr(vec[l]->GetMomentum().y()/MeV) ) )/GeV;
00910               if( vec[l]->GetSide() > 0)
00911               {
00912                 forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00913                 pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
00914               } else {
00915                 backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00916                 pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
00917               }
00918             } // if pi, K or forward
00919           } // for l
00920         } // if (resetEnergies)
00921       } // closes outer loop
00922     }
00923 
00924     //
00925     // Target particle finished.
00926     //
00927     // Now produce backward nucleons with a cluster model
00928     //
00929     pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
00930     pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
00931     pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
00932     if( backwardNucleonCount == 1 )  // target particle is the only backward nucleon
00933     {
00934       G4double ekin =
00935         std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
00936 
00937       if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
00938       vecMass = targetParticle.GetMass()/GeV;
00939       totalEnergy = ekin+vecMass;
00940       targetParticle.SetTotalEnergy( totalEnergy*GeV );
00941       pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00942       pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
00943       if( pp1 < 1.0e-6*GeV )
00944       { 
00945         G4double costheta = 2.*G4UniformRand() - 1.;
00946         G4double sintheta = std::sqrt(1. - costheta*costheta);
00947         G4double phi2 = twopi*G4UniformRand();
00948         targetParticle.SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
00949                                     pp*sintheta*std::sin(phi2)*MeV,
00950                                     pp*costheta*MeV ) ;
00951       } else {
00952         targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
00953       }
00954       pseudoParticle[5] = pseudoParticle[5] + targetParticle;
00955     }
00956     else  // more than one backward nucleon
00957     {
00958       const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
00959       const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
00960       // Replaced the following min function to get correct behaviour on DEC.
00961       // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
00962       G4int tempCount;
00963       if (backwardNucleonCount < 5)
00964         {
00965           tempCount = backwardNucleonCount;
00966         }
00967       else
00968         {
00969           tempCount = 5;
00970         }
00971       tempCount--;
00972       //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
00973       //cout << "tempCount " << tempCount << G4endl;
00974       G4double rmb0 = 0.0;
00975       if( targetParticle.GetSide() == -3 )
00976         rmb0 += targetParticle.GetMass()/GeV;
00977       for( i=0; i<vecLen; ++i )
00978       {
00979         if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
00980       }
00981       rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
00982       totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
00983       vecMass = std::min( rmb, totalEnergy );
00984       pseudoParticle[6].SetMass( vecMass*GeV );
00985       pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00986       pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
00987       if( pp1 < 1.0e-6*GeV )
00988       {
00989         G4double costheta = 2.*G4UniformRand() - 1.;
00990         G4double sintheta = std::sqrt(1. - costheta*costheta);
00991         G4double phi2 = twopi*G4UniformRand();
00992         pseudoParticle[6].SetMomentum( -pp*sintheta*std::cos(phi2)*MeV,
00993                                        -pp*sintheta*std::sin(phi2)*MeV,
00994                                        -pp*costheta*MeV ) ;
00995       }
00996       else
00997         pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
00998       
00999       G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;  // tempV contains the backward nucleons
01000       tempV.Initialize( backwardNucleonCount );
01001       G4int tempLen = 0;
01002       if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
01003       for( i=0; i<vecLen; ++i )
01004       {
01005         if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
01006       }
01007       if( tempLen != backwardNucleonCount )
01008       {
01009         G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
01010         G4cerr << "tempLen = " << tempLen;
01011         G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
01012         G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
01013         G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
01014         for( i=0; i<vecLen; ++i )
01015           G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
01016         G4Exception("G4ReactionDynamics::GenerateXandPt", "601", 
01017                     FatalException, "Mismatch in nucleon count");
01018       }
01019       constantCrossSection = true;
01020       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01021       if( tempLen >= 2 )
01022       {
01023         wgt = GenerateNBodyEvent(
01024          pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
01025          // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01026         if( targetParticle.GetSide() == -3 )
01027         {
01028           targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
01029           // tempV contains the real stuff
01030           pseudoParticle[5] = pseudoParticle[5] + targetParticle;
01031         }
01032         for( i=0; i<vecLen; ++i )
01033         {
01034           if( vec[i]->GetSide() == -3 )
01035           {
01036             vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
01037             pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
01038           }
01039         }
01040       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01041       }
01042     }
01043     //
01044     //  Lorentz transformation in lab system
01045     //
01046     if( vecLen == 0 )return false;  // all the secondaries have been eliminated
01047       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01048     
01049     currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
01050     targetParticle.Lorentz( targetParticle, pseudoParticle[1] );    
01051     for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
01052 
01053       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01054     //
01055     // leadFlag will be true
01056     //  iff original particle is at least as heavy as K+ and not a proton or 
01057     //  neutron AND if incident particle is at least as heavy as K+ and it is 
01058     //  not a proton or neutron leadFlag is set to the incident particle
01059     //  or
01060     //  target particle is at least as heavy as K+ and it is not a proton or 
01061     //  neutron leadFlag is set to the target particle
01062     //
01063     G4bool leadingStrangeParticleHasChanged = true;
01064     if( leadFlag )
01065     {
01066       if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
01067         leadingStrangeParticleHasChanged = false;
01068       if( leadingStrangeParticleHasChanged &&
01069           ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
01070         leadingStrangeParticleHasChanged = false;
01071       if( leadingStrangeParticleHasChanged )
01072       {
01073         for( i=0; i<vecLen; i++ )
01074         {
01075           if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
01076           {
01077             leadingStrangeParticleHasChanged = false;
01078             break;
01079           }
01080         }
01081       }
01082       if( leadingStrangeParticleHasChanged )
01083       {
01084         G4bool leadTest = 
01085           (leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
01086            leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "pi");
01087         G4bool targetTest =
01088           (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
01089            targetParticle.GetDefinition()->GetParticleSubType() == "pi");
01090         
01091         // following modified by JLC 22-Oct-97
01092           
01093         if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
01094         {
01095           targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
01096           targetHasChanged = true;
01097       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01098         }
01099         else
01100         {
01101           currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
01102           incidentHasChanged = false;
01103       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01104         }
01105       }
01106     }   // end of if( leadFlag )
01107 
01108     // Get number of final state nucleons and nucleons remaining in
01109     // target nucleus
01110     
01111     std::pair<G4int, G4int> finalStateNucleons = 
01112       GetFinalStateNucleons(originalTarget, vec, vecLen);
01113 
01114     G4int protonsInFinalState = finalStateNucleons.first;
01115     G4int neutronsInFinalState = finalStateNucleons.second;
01116 
01117     G4int numberofFinalStateNucleons = 
01118       protonsInFinalState + neutronsInFinalState;
01119 
01120     if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
01121         targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
01122         originalIncident->GetDefinition()->GetPDGMass() < 
01123                                    G4Lambda::Lambda()->GetPDGMass())
01124       numberofFinalStateNucleons++;
01125 
01126     numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
01127 
01128     G4int PinNucleus = std::max(0, 
01129       targetNucleus.GetZ_asInt() - protonsInFinalState);
01130     G4int NinNucleus = std::max(0,
01131       targetNucleus.GetN_asInt() - neutronsInFinalState);
01132 
01133     pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
01134     pseudoParticle[3].SetMass( mOriginal*GeV );
01135     pseudoParticle[3].SetTotalEnergy(
01136      std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
01137     
01138     G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
01139     G4int diff = 0;
01140     if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
01141     if(numberofFinalStateNucleons == 1) diff = 0;
01142     pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
01143     pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
01144     pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
01145     
01146     G4double theoreticalKinetic =
01147       pseudoParticle[3].GetTotalEnergy()/MeV +
01148       pseudoParticle[4].GetTotalEnergy()/MeV -
01149       currentParticle.GetMass()/MeV -
01150       targetParticle.GetMass()/MeV;
01151     
01152     G4double simulatedKinetic =
01153       currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
01154     
01155     pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
01156     pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
01157     pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
01158     
01159     pseudoParticle[7].SetZero();
01160     pseudoParticle[7] = pseudoParticle[7] + currentParticle;
01161     pseudoParticle[7] = pseudoParticle[7] + targetParticle;
01162 
01163     for( i=0; i<vecLen; ++i )
01164     {
01165       pseudoParticle[7] = pseudoParticle[7] + *vec[i];
01166       simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
01167       theoreticalKinetic -= vec[i]->GetMass()/MeV;
01168     }
01169 
01170     if( vecLen <= 16 && vecLen > 0 )
01171     {
01172       // must create a new set of ReactionProducts here because GenerateNBody will
01173       // modify the momenta for the particles, and we don't want to do this
01174       //
01175       G4ReactionProduct tempR[130];
01176       tempR[0] = currentParticle;
01177       tempR[1] = targetParticle;
01178       for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
01179       G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
01180       tempV.Initialize( vecLen+2 );
01181       G4int tempLen = 0;
01182       for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
01183       constantCrossSection = true;
01184 
01185       wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
01186                                 pseudoParticle[4].GetTotalEnergy()/MeV,
01187                                 constantCrossSection, tempV, tempLen );
01188       if (wgt == -1) {
01189         G4double Qvalue = 0;
01190         for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
01191         wgt = GenerateNBodyEvent( Qvalue/MeV,
01192                                   constantCrossSection, tempV, tempLen );
01193       }
01194       if(wgt>-.5)
01195       {
01196         theoreticalKinetic = 0.0;
01197         for( i=0; i<tempLen; ++i )
01198         {
01199           pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
01200           theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
01201         }
01202       }
01203       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01204     }
01205     //
01206     //  Make sure, that the kinetic energies are correct
01207     //
01208     if( simulatedKinetic != 0.0 )
01209     {
01210       wgt = (theoreticalKinetic)/simulatedKinetic;
01211       theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
01212       simulatedKinetic = theoreticalKinetic;
01213       currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
01214       pp = currentParticle.GetTotalMomentum()/MeV;
01215       pp1 = currentParticle.GetMomentum().mag()/MeV;
01216       if( pp1 < 1.0e-6*GeV )
01217       {
01218         G4double costheta = 2.*G4UniformRand() - 1.;
01219         G4double sintheta = std::sqrt(1. - costheta*costheta);
01220         G4double phi2 = twopi*G4UniformRand();
01221         currentParticle.SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
01222                                      pp*sintheta*std::sin(phi2)*MeV,
01223                                      pp*costheta*MeV ) ;
01224       }
01225       else
01226       {
01227         currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
01228       }
01229       theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
01230       targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
01231       simulatedKinetic += theoreticalKinetic;
01232       pp = targetParticle.GetTotalMomentum()/MeV;
01233       pp1 = targetParticle.GetMomentum().mag()/MeV;
01234       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01235       if( pp1 < 1.0e-6*GeV )
01236       {
01237         G4double costheta = 2.*G4UniformRand() - 1.;
01238         G4double sintheta = std::sqrt(1. - costheta*costheta);
01239         G4double phi2 = twopi*G4UniformRand();
01240         targetParticle.SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
01241                                     pp*sintheta*std::sin(phi2)*MeV,
01242                                     pp*costheta*MeV ) ;
01243       } else {
01244         targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
01245       }
01246       for( i=0; i<vecLen; ++i )
01247       {
01248         theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
01249         simulatedKinetic += theoreticalKinetic;
01250         vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
01251         pp = vec[i]->GetTotalMomentum()/MeV;
01252         pp1 = vec[i]->GetMomentum().mag()/MeV;
01253         if( pp1 < 1.0e-6*GeV )
01254         {
01255           G4double costheta = 2.*G4UniformRand() - 1.;
01256           G4double sintheta = std::sqrt(1. - costheta*costheta);
01257           G4double phi2 = twopi*G4UniformRand();
01258           vec[i]->SetMomentum( pp*sintheta*std::cos(phi2)*MeV,
01259                                pp*sintheta*std::sin(phi2)*MeV,
01260                                pp*costheta*MeV ) ;
01261         }
01262         else
01263           vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
01264       }
01265     }
01266       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01267 
01268     Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
01269             modifiedOriginal, originalIncident, targetNucleus,
01270             currentParticle, targetParticle, vec, vecLen );
01271       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01272     //
01273     // add black track particles
01274     // the total number of particles produced is restricted to 198
01275     // this may have influence on very high energies
01276     //
01277     if( atomicWeight >= 1.5 )
01278     {
01279       // npnb is number of proton/neutron black track particles
01280       // ndta is the number of deuterons, tritons, and alphas produced
01281       // epnb is the kinetic energy available for proton/neutron black track particles
01282       // edta is the kinetic energy available for deuteron/triton/alpha particles
01283       //
01284       G4int npnb = 0;
01285       G4int ndta = 0;
01286       
01287       G4double epnb, edta;
01288       if (veryForward) {
01289         epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
01290         edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
01291       } else {
01292         epnb = targetNucleus.GetPNBlackTrackEnergy();
01293         edta = targetNucleus.GetDTABlackTrackEnergy();
01294       }
01295 
01296       const G4double pnCutOff = 0.001;
01297       const G4double dtaCutOff = 0.001;
01298       const G4double kineticMinimum = 1.e-6;
01299       const G4double kineticFactor = -0.010;
01300       G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
01301       const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
01302       if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
01303       if( epnb >= pnCutOff )
01304       {
01305         npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
01306         if( numberofFinalStateNucleons + npnb > atomicWeight )
01307           npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
01308         npnb = std::min( npnb, 127-vecLen );
01309       }
01310       if( edta >= dtaCutOff )
01311       {
01312         ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
01313         ndta = std::min( ndta, 127-vecLen );
01314       }
01315       if (npnb == 0 && ndta == 0) npnb = 1;
01316 
01317       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01318 
01319       AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
01320                              kineticFactor, modifiedOriginal,
01321                              PinNucleus, NinNucleus, targetNucleus,
01322                              vec, vecLen);
01323 
01324       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01325     }
01326     //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
01327     //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
01328     //
01329     //  calculate time delay for nuclear reactions
01330     //
01331     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
01332       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
01333     else
01334       currentParticle.SetTOF( 1.0 );
01335     return true;
01336       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01337   }

void G4ReactionDynamics::NuclearReaction ( G4FastVector< G4ReactionProduct, 4 > &  vec,
G4int vecLen,
const G4HadProjectile originalIncident,
const G4Nucleus aNucleus,
const G4double  theAtomicMass,
const G4double massVec 
)

Definition at line 3777 of file G4ReactionDynamics.cc.

References G4Alpha::Alpha(), G4Deuteron::Deuteron(), G4UniformRand, G4Gamma::Gamma(), GenerateNBodyEvent(), G4Nucleus::GetA_asInt(), G4ReactionProduct::GetDefinition(), G4ReactionProduct::GetKineticEnergy(), G4ReactionProduct::GetMass(), G4ReactionProduct::GetMomentum(), G4ParticleDefinition::GetPDGMass(), G4ReactionProduct::GetTotalMomentum(), G4FastVector< Type, N >::Initialize(), G4ReactionProduct::Lorentz(), G4Neutron::Neutron(), G4Proton::Proton(), G4ReactionProduct::SetDefinition(), G4FastVector< Type, N >::SetElement(), G4ReactionProduct::SetKineticEnergy(), G4ReactionProduct::SetMass(), G4ReactionProduct::SetMomentum(), G4ReactionProduct::SetTotalEnergy(), and G4Triton::Triton().

Referenced by G4LETritonInelastic::ApplyYourself(), G4LEDeuteronInelastic::ApplyYourself(), and G4LEAlphaInelastic::ApplyYourself().

03784   {
03785     // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
03786     //
03787     // Nuclear reaction kinematics at low energies
03788     //
03789     G4ParticleDefinition *aGamma = G4Gamma::Gamma();
03790     G4ParticleDefinition *aProton = G4Proton::Proton();
03791     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
03792     G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
03793     G4ParticleDefinition *aTriton = G4Triton::Triton();
03794     G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
03795     
03796     const G4double aProtonMass = aProton->GetPDGMass()/MeV;
03797     const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
03798     const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
03799     const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
03800     const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
03801 
03802     G4ReactionProduct currentParticle;
03803     currentParticle = *originalIncident;
03804     //
03805     // Set beam particle, take kinetic energy of current particle as the
03806     // fundamental quantity.  Due to the difficult kinematic, all masses have to
03807     // be assigned the best measured values
03808     //
03809     G4double p = currentParticle.GetTotalMomentum();
03810     G4double pp = currentParticle.GetMomentum().mag();
03811     if( pp <= 0.001*MeV )
03812     {
03813       G4double phinve = twopi*G4UniformRand();
03814       G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
03815       currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
03816                                    p*std::sin(rthnve)*std::sin(phinve),
03817                                    p*std::cos(rthnve) );
03818     }
03819     else
03820       currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
03821     //
03822     // calculate Q-value of reactions
03823     //
03824     G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
03825     G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
03826     G4double qv = currentKinetic + theAtomicMass + currentMass;
03827     
03828     G4double qval[9];
03829     qval[0] = qv - mass[0];
03830     qval[1] = qv - mass[1] - aNeutronMass;
03831     qval[2] = qv - mass[2] - aProtonMass;
03832     qval[3] = qv - mass[3] - aDeuteronMass;
03833     qval[4] = qv - mass[4] - aTritonMass;
03834     qval[5] = qv - mass[5] - anAlphaMass;
03835     qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
03836     qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
03837     qval[8] = qv - mass[8] - aProtonMass  - aProtonMass;
03838     
03839     if( currentParticle.GetDefinition() == aNeutron )
03840     {
03841       const G4double A = G4double(targetNucleus.GetA_asInt());    // atomic weight
03842       if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
03843         qval[0] = 0.0;
03844       if( G4UniformRand() >= currentKinetic/7.9254*A )
03845         qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
03846     }
03847     else
03848       qval[0] = 0.0;
03849     
03850     G4int i;
03851     qv = 0.0;
03852     for( i=0; i<9; ++i )
03853     {
03854       if( mass[i] < 500.0*MeV )qval[i] = 0.0;
03855       if( qval[i] < 0.0 )qval[i] = 0.0;
03856       qv += qval[i];
03857     }
03858     G4double qv1 = 0.0;
03859     G4double ran = G4UniformRand();
03860     G4int index;
03861     for( index=0; index<9; ++index )
03862     {
03863       if( qval[index] > 0.0 )
03864       {
03865         qv1 += qval[index]/qv;
03866         if( ran <= qv1 )break;
03867       }
03868     }
03869     if( index == 9 )  // loop continued to the end
03870     {
03871       throw G4HadronicException(__FILE__, __LINE__,
03872            "G4ReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
03873     }
03874     G4double ke = currentParticle.GetKineticEnergy()/GeV;
03875     G4int nt = 2;
03876     if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
03877     
03878     G4ReactionProduct **v = new G4ReactionProduct * [3];
03879     v[0] =  new G4ReactionProduct;
03880     v[1] =  new G4ReactionProduct;
03881     v[2] =  new G4ReactionProduct;
03882     
03883     v[0]->SetMass( mass[index]*MeV );
03884     switch( index )
03885     {
03886      case 0:
03887        v[1]->SetDefinition( aGamma );
03888        v[2]->SetDefinition( aGamma );
03889        break;
03890      case 1:
03891        v[1]->SetDefinition( aNeutron );
03892        v[2]->SetDefinition( aGamma );
03893        break;
03894      case 2:
03895        v[1]->SetDefinition( aProton );
03896        v[2]->SetDefinition( aGamma );
03897        break;
03898      case 3:
03899        v[1]->SetDefinition( aDeuteron );
03900        v[2]->SetDefinition( aGamma );
03901        break;
03902      case 4:
03903        v[1]->SetDefinition( aTriton );
03904        v[2]->SetDefinition( aGamma );
03905        break;
03906      case 5:
03907        v[1]->SetDefinition( anAlpha );
03908        v[2]->SetDefinition( aGamma );
03909        break;
03910      case 6:
03911        v[1]->SetDefinition( aNeutron );
03912        v[2]->SetDefinition( aNeutron );
03913        break;
03914      case 7:
03915        v[1]->SetDefinition( aNeutron );
03916        v[2]->SetDefinition( aProton );
03917        break;
03918      case 8:
03919        v[1]->SetDefinition( aProton );
03920        v[2]->SetDefinition( aProton );
03921        break;
03922     }
03923     //
03924     // calculate centre of mass energy
03925     //
03926     G4ReactionProduct pseudo1;
03927     pseudo1.SetMass( theAtomicMass*MeV );
03928     pseudo1.SetTotalEnergy( theAtomicMass*MeV );
03929     G4ReactionProduct pseudo2 = currentParticle + pseudo1;
03930     pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
03931     //
03932     // use phase space routine in centre of mass system
03933     //
03934     G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
03935     tempV.Initialize( nt );
03936     G4int tempLen = 0;
03937     tempV.SetElement( tempLen++, v[0] );
03938     tempV.SetElement( tempLen++, v[1] );
03939     if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
03940     G4bool constantCrossSection = true;
03941     GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
03942     v[0]->Lorentz( *v[0], pseudo2 );
03943     v[1]->Lorentz( *v[1], pseudo2 );
03944     if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
03945     
03946     G4bool particleIsDefined = false;
03947     if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
03948     {
03949       v[0]->SetDefinition( aProton );
03950       particleIsDefined = true;
03951     }
03952     else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
03953     {
03954       v[0]->SetDefinition( aNeutron );
03955       particleIsDefined = true;
03956     }
03957     else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
03958     {
03959       v[0]->SetDefinition( aDeuteron );
03960       particleIsDefined = true;
03961     }
03962     else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
03963     {
03964       v[0]->SetDefinition( aTriton );
03965       particleIsDefined = true;
03966     }
03967     else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
03968     {
03969       v[0]->SetDefinition( anAlpha );
03970       particleIsDefined = true;
03971     }
03972     currentParticle.SetKineticEnergy(
03973      std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
03974     p = currentParticle.GetTotalMomentum();
03975     pp = currentParticle.GetMomentum().mag();
03976     if( pp <= 0.001*MeV )
03977     {
03978       G4double phinve = twopi*G4UniformRand();
03979       G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
03980       currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
03981                                    p*std::sin(rthnve)*std::sin(phinve),
03982                                    p*std::cos(rthnve) );
03983     }
03984     else
03985       currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
03986     
03987     if( particleIsDefined )
03988     {
03989       v[0]->SetKineticEnergy(
03990        std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
03991       p = v[0]->GetTotalMomentum();
03992       pp = v[0]->GetMomentum().mag();
03993       if( pp <= 0.001*MeV )
03994       {
03995         G4double phinve = twopi*G4UniformRand();
03996         G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
03997         v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
03998                           p*std::sin(rthnve)*std::sin(phinve),
03999                           p*std::cos(rthnve) );
04000       }
04001       else
04002         v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
04003     }
04004     if( (v[1]->GetDefinition() == aDeuteron) ||
04005         (v[1]->GetDefinition() == aTriton)   ||
04006         (v[1]->GetDefinition() == anAlpha) ) 
04007       v[1]->SetKineticEnergy(
04008        std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
04009     else
04010       v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
04011     
04012     p = v[1]->GetTotalMomentum();
04013     pp = v[1]->GetMomentum().mag();
04014     if( pp <= 0.001*MeV )
04015     {
04016       G4double phinve = twopi*G4UniformRand();
04017       G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
04018       v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04019                         p*std::sin(rthnve)*std::sin(phinve),
04020                         p*std::cos(rthnve) );
04021     }
04022     else
04023       v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
04024     
04025     if( nt == 3 )
04026     {
04027       if( (v[2]->GetDefinition() == aDeuteron) ||
04028           (v[2]->GetDefinition() == aTriton)   ||
04029           (v[2]->GetDefinition() == anAlpha) ) 
04030         v[2]->SetKineticEnergy(
04031          std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
04032       else
04033         v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
04034       
04035       p = v[2]->GetTotalMomentum();
04036       pp = v[2]->GetMomentum().mag();
04037       if( pp <= 0.001*MeV )
04038       {
04039         G4double phinve = twopi*G4UniformRand();
04040         G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
04041         v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04042                           p*std::sin(rthnve)*std::sin(phinve),
04043                           p*std::cos(rthnve) );
04044       }
04045       else
04046         v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
04047     }
04048     G4int del;
04049     for(del=0; del<vecLen; del++) delete vec[del];
04050     vecLen = 0;
04051     if( particleIsDefined )
04052     {
04053       vec.SetElement( vecLen++, v[0] );
04054     }
04055     else
04056     {
04057       delete v[0];
04058     }
04059     vec.SetElement( vecLen++, v[1] );
04060     if( nt == 3 )
04061     {
04062       vec.SetElement( vecLen++, v[2] );
04063     }
04064     else
04065     {
04066       delete v[2];
04067     }
04068     delete [] v;
04069     return;
04070   }

void G4ReactionDynamics::ProduceStrangeParticlePairs ( G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen,
const G4ReactionProduct modifiedOriginal,
const G4DynamicParticle originalTarget,
G4ReactionProduct currentParticle,
G4ReactionProduct targetParticle,
G4bool incidentHasChanged,
G4bool targetHasChanged 
)

Definition at line 3386 of file G4ReactionDynamics.cc.

References G4AntiLambda::AntiLambda(), G4AntiNeutron::AntiNeutron(), G4AntiProton::AntiProton(), G4AntiSigmaMinus::AntiSigmaMinus(), G4AntiSigmaPlus::AntiSigmaPlus(), G4AntiSigmaZero::AntiSigmaZero(), G4UniformRand, G4DynamicParticle::GetDefinition(), G4ReactionProduct::GetDefinition(), G4ReactionProduct::GetMass(), G4ParticleDefinition::GetPDGMass(), G4ReactionProduct::GetTotalEnergy(), G4KaonMinus::KaonMinus(), G4KaonPlus::KaonPlus(), G4KaonZeroLong::KaonZeroLong(), G4KaonZeroShort::KaonZeroShort(), G4Lambda::Lambda(), G4Neutron::Neutron(), G4Proton::Proton(), G4ReactionProduct::SetDefinition(), G4ReactionProduct::SetDefinitionAndUpdateE(), G4FastVector< Type, N >::SetElement(), G4ReactionProduct::SetMayBeKilled(), G4ReactionProduct::SetSide(), G4SigmaMinus::SigmaMinus(), G4SigmaPlus::SigmaPlus(), and G4SigmaZero::SigmaZero().

Referenced by G4InelasticInteraction::CalculateMomenta().

03395   {
03396     // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
03397     //
03398     // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
03399     //                            K+ Y0, K0 Y+,  K0 Y-
03400     // For antibaryon induced reactions half of the cross sections KB YB
03401     // pairs are produced.  Charge is not conserved, no experimental data available
03402     // for exclusive reactions, therefore some average behaviour assumed.
03403     // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
03404     //
03405     if( vecLen == 0 )return;
03406     //
03407     // the following protects against annihilation processes
03408     //
03409     if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
03410     
03411     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
03412     const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
03413     G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
03414     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
03415                                         targetMass*targetMass +
03416                                         2.0*targetMass*etOriginal );  // GeV
03417     G4double currentMass = currentParticle.GetMass()/GeV;
03418     G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
03419     if( availableEnergy <= 1.0 )return;
03420     
03421     G4ParticleDefinition *aProton = G4Proton::Proton();
03422     G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
03423     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
03424     G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
03425     G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
03426     G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
03427     G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
03428     G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
03429     G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
03430     G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
03431     G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
03432     G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
03433     G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
03434     G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
03435     G4ParticleDefinition *aLambda = G4Lambda::Lambda();
03436     G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
03437     
03438     const G4double protonMass = aProton->GetPDGMass()/GeV;
03439     const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
03440     //
03441     // determine the center of mass energy bin
03442     //
03443     const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
03444 
03445     G4int ibin, i3, i4;
03446     G4double avk, avy, avn, ran;
03447     G4int i = 1;
03448     while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
03449     if( i == 12 )
03450       ibin = 11;
03451     else
03452       ibin = i;
03453     //
03454     // the fortran code chooses a random replacement of produced kaons
03455     //  but does not take into account charge conservation 
03456     //
03457     if( vecLen == 1 )  // we know that vecLen > 0
03458     {
03459       i3 = 0;
03460       i4 = 1;   // note that we will be adding a new secondary particle in this case only
03461     }
03462     else               // otherwise  0 <= i3,i4 < vecLen
03463     {
03464       ran = G4UniformRand();
03465       while( ran == 1.0 )ran = G4UniformRand();
03466       i4 = i3 = G4int( vecLen*ran );
03467       while( i3 == i4 )
03468       {
03469         ran = G4UniformRand();
03470         while( ran == 1.0 )ran = G4UniformRand();
03471         i4 = G4int( vecLen*ran );
03472       }
03473     }
03474     //
03475     // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
03476     //
03477     const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
03478                                0.0975, 0.123, 0.28,  0.398,  0.495,  0.573 };
03479     const G4double avky[] = { 0.005, 0.03,  0.064, 0.095, 0.115, 0.13,
03480                               0.145, 0.155, 0.20,  0.205, 0.210, 0.212 };
03481     const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
03482                                0.04,    0.05,   0.12,   0.15,   0.18, 0.20 };
03483     
03484     avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03485       /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
03486     avk = std::exp(avk);
03487     
03488     avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03489       /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
03490     avy = std::exp(avy);
03491     
03492     avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03493       /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
03494     avn = std::exp(avn);
03495     
03496     if( avk+avy+avn <= 0.0 )return;
03497     
03498     if( currentMass < protonMass )avy /= 2.0;
03499     if( targetMass < protonMass )avy = 0.0;
03500     avy += avk+avn;
03501     avk += avn;
03502     ran = G4UniformRand();
03503     if(  ran < avn )
03504     {
03505       if( availableEnergy < 2.0 )return;
03506       if( vecLen == 1 )                              // add a new secondary
03507       {
03508         G4ReactionProduct *p1 = new G4ReactionProduct;
03509         if( G4UniformRand() < 0.5 )
03510         {
03511           vec[0]->SetDefinition( aNeutron );
03512           p1->SetDefinition( anAntiNeutron );
03513           (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03514           vec[0]->SetMayBeKilled(false);
03515           p1->SetMayBeKilled(false);
03516         }
03517         else
03518         {
03519           vec[0]->SetDefinition( aProton );
03520           p1->SetDefinition( anAntiProton );
03521           (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03522           vec[0]->SetMayBeKilled(false);
03523           p1->SetMayBeKilled(false);
03524         }
03525         vec.SetElement( vecLen++, p1 );
03526       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03527       }
03528       else
03529       {                                             // replace two secondaries
03530         if( G4UniformRand() < 0.5 )
03531         {
03532           vec[i3]->SetDefinition( aNeutron );
03533           vec[i4]->SetDefinition( anAntiNeutron );
03534           vec[i3]->SetMayBeKilled(false);
03535           vec[i4]->SetMayBeKilled(false);
03536         }
03537         else
03538         {
03539           vec[i3]->SetDefinition( aProton );
03540           vec[i4]->SetDefinition( anAntiProton );
03541           vec[i3]->SetMayBeKilled(false);
03542           vec[i4]->SetMayBeKilled(false);
03543         }
03544       }
03545     }
03546     else if( ran < avk )
03547     {
03548       if( availableEnergy < 1.0 )return;
03549       
03550       const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
03551                                0.6875, 0.7500, 0.8750, 1.000 };
03552       const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
03553       const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
03554       ran = G4UniformRand();
03555       i = 0;
03556       while( (i<9) && (ran>=kkb[i]) )++i;
03557       if( i == 9 )return;
03558       //
03559       // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
03560       // charge       +  -   +  0   +  0   0  0   0  0   0  0   0  0   0  -   0  -
03561       //
03562       switch( ipakkb1[i] )
03563       {
03564        case 10:
03565          vec[i3]->SetDefinition( aKaonPlus );
03566          vec[i3]->SetMayBeKilled(false);
03567          break;
03568        case 11:
03569          vec[i3]->SetDefinition( aKaonZS );
03570          vec[i3]->SetMayBeKilled(false);
03571          break;
03572        case 12:
03573          vec[i3]->SetDefinition( aKaonZL );
03574          vec[i3]->SetMayBeKilled(false);
03575          break;
03576       }
03577       if( vecLen == 1 )                          // add a secondary
03578       {
03579         G4ReactionProduct *p1 = new G4ReactionProduct;
03580         switch( ipakkb2[i] )
03581         {
03582          case 11:
03583            p1->SetDefinition( aKaonZS );
03584            p1->SetMayBeKilled(false);
03585            break;
03586          case 12:
03587            p1->SetDefinition( aKaonZL );
03588            p1->SetMayBeKilled(false);
03589            break;
03590          case 13:
03591            p1->SetDefinition( aKaonMinus );
03592            p1->SetMayBeKilled(false);
03593            break;
03594         }
03595         (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03596         vec.SetElement( vecLen++, p1 );
03597       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03598       }
03599       else                                        // replace
03600       {
03601         switch( ipakkb2[i] )
03602         {
03603          case 11:
03604            vec[i4]->SetDefinition( aKaonZS );
03605            vec[i4]->SetMayBeKilled(false);
03606            break;
03607          case 12:
03608            vec[i4]->SetDefinition( aKaonZL );
03609            vec[i4]->SetMayBeKilled(false);
03610            break;
03611          case 13:
03612            vec[i4]->SetDefinition( aKaonMinus );
03613            vec[i4]->SetMayBeKilled(false);
03614            break;
03615         }
03616       }
03617     }
03618     else if( ran < avy )
03619     {
03620       if( availableEnergy < 1.6 )return;
03621       
03622       const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
03623                               0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
03624       const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
03625       const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
03626       const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
03627       const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
03628       ran = G4UniformRand();
03629       i = 0;
03630       while( (i<12) && (ran>ky[i]) )++i;
03631       if( i == 12 )return;
03632       if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
03633       {
03634         // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
03635         //             0  +   0  0   0  0   +  +   +  0   +  0
03636         //
03637         //             21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
03638         //             0  +   0  0   0  0   -  +   -  0   -  0
03639         switch( ipaky1[i] )
03640         {
03641          case 18:
03642            targetParticle.SetDefinition( aLambda );
03643            break;
03644          case 20:
03645            targetParticle.SetDefinition( aSigmaPlus );
03646            break;
03647          case 21:
03648            targetParticle.SetDefinition( aSigmaZero );
03649            break;
03650          case 22:
03651            targetParticle.SetDefinition( aSigmaMinus );
03652            break;
03653         }
03654         targetHasChanged = true;
03655         switch( ipaky2[i] )
03656         {
03657          case 10:
03658            vec[i3]->SetDefinition( aKaonPlus ); 
03659            vec[i3]->SetMayBeKilled(false);
03660            break;
03661          case 11:
03662            vec[i3]->SetDefinition( aKaonZS );
03663            vec[i3]->SetMayBeKilled(false);
03664            break;
03665          case 12:
03666            vec[i3]->SetDefinition( aKaonZL );
03667            vec[i3]->SetMayBeKilled(false);
03668            break;
03669         }
03670       }
03671       else  // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
03672       {
03673         // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
03674         //              24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
03675         if( (currentParticle.GetDefinition() == anAntiProton) ||
03676             (currentParticle.GetDefinition() == anAntiNeutron) ||
03677             (currentParticle.GetDefinition() == anAntiLambda) ||
03678             (currentMass > sigmaMinusMass) )
03679         {
03680           switch( ipakyb1[i] )
03681           {
03682            case 19:
03683              currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
03684              break;
03685            case 23:
03686              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
03687              break;
03688            case 24:
03689              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
03690              break;
03691            case 25:
03692              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
03693              break;
03694           }
03695           incidentHasChanged = true;
03696           switch( ipakyb2[i] )
03697           {
03698            case 11:
03699              vec[i3]->SetDefinition( aKaonZS ); 
03700              vec[i3]->SetMayBeKilled(false);
03701              break;
03702            case 12:
03703              vec[i3]->SetDefinition( aKaonZL );
03704              vec[i3]->SetMayBeKilled(false);
03705              break;
03706            case 13:
03707              vec[i3]->SetDefinition( aKaonMinus );
03708              vec[i3]->SetMayBeKilled(false);
03709              break;
03710           }
03711         }
03712         else
03713         {
03714           switch( ipaky1[i] )
03715           {
03716            case 18:
03717              currentParticle.SetDefinitionAndUpdateE( aLambda );
03718              break;
03719            case 20:
03720              currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
03721              break;
03722            case 21:
03723              currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
03724              break;
03725            case 22:
03726              currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
03727              break;
03728           }
03729           incidentHasChanged = true;
03730           switch( ipaky2[i] )
03731           {
03732            case 10:
03733              vec[i3]->SetDefinition( aKaonPlus ); 
03734              vec[i3]->SetMayBeKilled(false);
03735              break;
03736            case 11:
03737              vec[i3]->SetDefinition( aKaonZS );
03738              vec[i3]->SetMayBeKilled(false);
03739              break;
03740            case 12:
03741              vec[i3]->SetDefinition( aKaonZL );
03742              vec[i3]->SetMayBeKilled(false);
03743              break;
03744           }
03745         }
03746       }
03747     }
03748     else return;
03749     //
03750     //  check the available energy
03751     //   if there is not enough energy for kkb/ky pair production
03752     //   then reduce the number of secondary particles 
03753     //  NOTE:
03754     //        the number of secondaries may have been changed
03755     //        the incident and/or target particles may have changed
03756     //        charge conservation is ignored (as well as strangness conservation)
03757     //
03758     currentMass = currentParticle.GetMass()/GeV;
03759     targetMass = targetParticle.GetMass()/GeV;
03760     
03761     G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
03762     for( i=0; i<vecLen; ++i )
03763     {
03764       energyCheck -= vec[i]->GetMass()/GeV;
03765       if( energyCheck < 0.0 )      // chop off the secondary List
03766       {
03767         vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
03768         G4int j;
03769         for(j=i; j<vecLen; j++) delete vec[j];
03770         break;
03771       }
03772     }
03773     return;
03774   }

void G4ReactionDynamics::SuppressChargedPions ( G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen,
const G4ReactionProduct modifiedOriginal,
G4ReactionProduct currentParticle,
G4ReactionProduct targetParticle,
const G4Nucleus targetNucleus,
G4bool incidentHasChanged,
G4bool targetHasChanged 
)

Definition at line 1339 of file G4ReactionDynamics.cc.

References G4AntiLambda::AntiLambda(), G4AntiNeutron::AntiNeutron(), G4AntiOmegaMinus::AntiOmegaMinus(), G4AntiProton::AntiProton(), G4AntiSigmaMinus::AntiSigmaMinus(), G4AntiSigmaPlus::AntiSigmaPlus(), G4AntiXiMinus::AntiXiMinus(), G4AntiXiZero::AntiXiZero(), G4UniformRand, G4Nucleus::GetA_asInt(), G4ReactionProduct::GetDefinition(), G4ReactionProduct::GetMass(), G4ParticleDefinition::GetPDGMass(), G4ReactionProduct::GetTotalEnergy(), G4ReactionProduct::GetTotalMomentum(), G4Nucleus::GetZ_asInt(), G4Neutron::Neutron(), G4PionMinus::PionMinus(), G4PionPlus::PionPlus(), G4PionZero::PionZero(), G4Proton::Proton(), and G4ReactionProduct::SetDefinitionAndUpdateE().

Referenced by G4InelasticInteraction::CalculateMomenta().

01348   {
01349     // this code was originally in the fortran code TWOCLU
01350     //
01351     // suppress charged pions, for various reasons
01352     //
01353     G4double mOriginal = modifiedOriginal.GetMass()/GeV;
01354     G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
01355     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
01356     G4double cmEnergy = std::sqrt( mOriginal*mOriginal + targetMass*targetMass +
01357                                    2.0*targetMass*etOriginal ); 
01358     G4double eAvailable = cmEnergy - mOriginal - targetMass;
01359     for (G4int i = 0; i < vecLen; i++) eAvailable -= vec[i]->GetMass()/GeV;
01360 
01361     const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
01362     const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
01363     const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
01364     
01365     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
01366     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
01367     G4ParticleDefinition* aPiZero = G4PionZero::PionZero();
01368     G4ParticleDefinition *aProton = G4Proton::Proton();
01369     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
01370     G4double piMass = aPiPlus->GetPDGMass()/GeV;
01371     G4double nucleonMass = aNeutron->GetPDGMass()/GeV;
01372     
01373     const G4bool antiTest =
01374       modifiedOriginal.GetDefinition() != G4AntiProton::AntiProton() &&
01375       modifiedOriginal.GetDefinition() != G4AntiNeutron::AntiNeutron() &&
01376       modifiedOriginal.GetDefinition() != G4AntiLambda::AntiLambda() &&
01377       modifiedOriginal.GetDefinition() != G4AntiSigmaPlus::AntiSigmaPlus() &&
01378       modifiedOriginal.GetDefinition() != G4AntiSigmaMinus::AntiSigmaMinus() &&
01379       modifiedOriginal.GetDefinition() != G4AntiXiZero::AntiXiZero() &&
01380       modifiedOriginal.GetDefinition() != G4AntiXiMinus::AntiXiMinus() &&
01381       modifiedOriginal.GetDefinition() != G4AntiOmegaMinus::AntiOmegaMinus();
01382 
01383     if( antiTest && (
01384           currentParticle.GetDefinition() == aPiPlus ||
01385           currentParticle.GetDefinition() == aPiZero ||
01386           currentParticle.GetDefinition() == aPiMinus ) &&
01387         ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01388         ( G4UniformRand() <= atomicWeight/300.0 ) )
01389     {
01390       if (eAvailable > nucleonMass - piMass) {
01391         if( G4UniformRand() > atomicNumber/atomicWeight )
01392           currentParticle.SetDefinitionAndUpdateE( aNeutron );
01393         else
01394           currentParticle.SetDefinitionAndUpdateE( aProton );
01395         incidentHasChanged = true;
01396       }
01397     }
01398     if( antiTest && (
01399           targetParticle.GetDefinition() == aPiPlus ||
01400           targetParticle.GetDefinition() == aPiZero ||
01401           targetParticle.GetDefinition() == aPiMinus ) &&
01402         ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01403         ( G4UniformRand() <= atomicWeight/300.0 ) )
01404     {
01405       if (eAvailable > nucleonMass - piMass) {
01406         if( G4UniformRand() > atomicNumber/atomicWeight )
01407           targetParticle.SetDefinitionAndUpdateE( aNeutron );
01408         else
01409           targetParticle.SetDefinitionAndUpdateE( aProton );
01410         targetHasChanged = true;
01411       }
01412     }
01413       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01414     for( G4int i=0; i<vecLen; ++i )
01415     {
01416       if( antiTest && (
01417             vec[i]->GetDefinition() == aPiPlus ||
01418             vec[i]->GetDefinition() == aPiZero ||
01419             vec[i]->GetDefinition() == aPiMinus ) &&
01420           ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01421           ( G4UniformRand() <= atomicWeight/300.0 ) )
01422       {
01423         if (eAvailable > nucleonMass - piMass) {
01424           if( G4UniformRand() > atomicNumber/atomicWeight )
01425             vec[i]->SetDefinitionAndUpdateE( aNeutron );
01426           else
01427             vec[i]->SetDefinitionAndUpdateE( aProton );
01428         }
01429       }
01430     }
01431       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01432   }

void G4ReactionDynamics::TwoBody ( G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen,
G4ReactionProduct modifiedOriginal,
const G4DynamicParticle originalTarget,
G4ReactionProduct currentParticle,
G4ReactionProduct targetParticle,
const G4Nucleus targetNucleus,
G4bool targetHasChanged 
)

Definition at line 2243 of file G4ReactionDynamics.cc.

References G4UniformRand, G4Nucleus::GetA_asInt(), G4ReactionProduct::GetDefinition(), G4Nucleus::GetDTABlackTrackEnergy(), G4ReactionProduct::GetKineticEnergy(), G4ReactionProduct::GetMass(), G4ReactionProduct::GetMomentum(), G4Nucleus::GetN_asInt(), G4ParticleDefinition::GetParticleSubType(), G4ParticleDefinition::GetPDGMass(), G4Nucleus::GetPNBlackTrackEnergy(), G4ReactionProduct::GetTotalEnergy(), G4ReactionProduct::GetTotalMomentum(), G4Nucleus::GetZ_asInt(), G4ReactionProduct::Lorentz(), G4InuclParticleNames::pp, G4ReactionProduct::SetKineticEnergy(), G4ReactionProduct::SetMass(), G4ReactionProduct::SetMomentum(), G4ReactionProduct::SetTOF(), and G4ReactionProduct::SetTotalEnergy().

Referenced by G4InelasticInteraction::CalculateMomenta().

02252   {
02253     // 
02254     // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
02255     //
02256     // Generation of momenta for elastic and quasi-elastic 2 body reactions
02257     //
02258     // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
02259     // The b values are parametrizations from experimental data.
02260     // Not available values are taken from those of similar reactions.
02261     //
02262     
02263       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);    
02264     static const G4double expxu =  82.;           // upper bound for arg. of exp
02265     static const G4double expxl = -expxu;         // lower bound for arg. of exp
02266     
02267     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
02268     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
02269     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
02270     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
02271     G4double currentMass = currentParticle.GetMass()/GeV;
02272     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
02273 
02274     targetMass = targetParticle.GetMass()/GeV;
02275     const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
02276     
02277     G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
02278     G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
02279 
02280     G4double cmEnergy = std::sqrt( currentMass*currentMass +
02281                               targetMass*targetMass +
02282                               2.0*targetMass*etCurrent );  // in GeV
02283 
02284     //if( (pOriginal < 0.1) ||
02285     //    (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
02286     // Continue with original particle, but spend the nuclear evaporation energy
02287     //  targetParticle.SetMass( 0.0 );  // flag that the target doesn't exist
02288     //else                           // Two-body scattering is possible
02289 
02290     if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
02291     {
02292       targetParticle.SetMass( 0.0 );  // flag that the target particle doesn't exist
02293     }
02294     else
02295     {
02296 // moved this if-block to a later stage, i.e. to the assignment of the scattering angle
02297 // @@@@@ double-check.
02298 //      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" || 
02299 //          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
02300 //        if( G4UniformRand() < 0.5 )
02301 //          targetParticle.SetDefinitionAndUpdateE( aNeutron );
02302 //        else
02303 //          targetParticle.SetDefinitionAndUpdateE( aProton );
02304 //        targetHasChanged = true;
02305 //        targetMass = targetParticle.GetMass()/GeV;
02306 //      }
02307       //
02308       // Set masses and momenta for final state particles
02309       //
02310       G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
02311       pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
02312       
02313       if( pf < 0.001 )
02314       {
02315         for(G4int i=0; i<vecLen; i++) delete vec[i];
02316         vecLen = 0;
02317         throw G4HadronicException(__FILE__, __LINE__, "G4ReactionDynamics::TwoBody: pf is too small ");
02318       }
02319       
02320       pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
02321       //
02322       // Set beam and target in centre of mass system
02323       //
02324       G4ReactionProduct pseudoParticle[3];
02325       
02326       if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
02327           targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
02328         pseudoParticle[0].SetMass( targetMass*GeV );
02329         pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
02330         pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
02331       
02332         pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
02333         pseudoParticle[1].SetMass( mOriginal*GeV );
02334         pseudoParticle[1].SetKineticEnergy( 0.0 );
02335 
02336       } else {
02337         pseudoParticle[0].SetMass( currentMass*GeV );
02338         pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
02339         pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
02340       
02341         pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
02342         pseudoParticle[1].SetMass( targetMass*GeV );
02343         pseudoParticle[1].SetKineticEnergy( 0.0 );
02344       }
02345       //
02346       // Transform into centre of mass system
02347       //
02348       pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
02349       pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
02350       pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
02351       //
02352       // Set final state masses and energies in centre of mass system
02353       //
02354       currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
02355       targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
02356       //
02357       // Set |t| and |tmin|
02358       //
02359       const G4double cb = 0.01;
02360       const G4double b1 = 4.225;
02361       const G4double b2 = 1.795;
02362       //
02363       // Calculate slope b for elastic scattering on proton/neutron
02364       //
02365       G4double b = std::max( cb, b1+b2*std::log(pOriginal) );     
02366       G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
02367       
02368       G4double exindt = -1.0;
02369       exindt += std::exp(std::max(-btrang,expxl));
02370       //
02371       // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
02372       //
02373       G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
02374       if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
02375       G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
02376       G4double phi = twopi * G4UniformRand();
02377       //
02378       // Calculate final state momenta in centre of mass system
02379       //
02380       if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
02381           targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
02382 
02383         currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
02384                                      -pf*stet*std::cos(phi)*GeV,
02385                                      -pf*ctet*GeV );
02386       } else {
02387 
02388         currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
02389                                      pf*stet*std::cos(phi)*GeV,
02390                                      pf*ctet*GeV );
02391       }
02392       targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
02393       //
02394       // Transform into lab system
02395       //
02396       currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
02397       targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
02398       
02399       Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
02400       
02401       G4double pp, pp1, ekin;
02402       if( atomicWeight >= 1.5 )
02403       {
02404         const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
02405         pp1 = currentParticle.GetMomentum().mag()/MeV;
02406         if( pp1 >= 1.0 )
02407         {
02408           ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
02409           ekin = std::max( 0.0001*GeV, ekin );
02410           currentParticle.SetKineticEnergy( ekin*MeV );
02411           pp = currentParticle.GetTotalMomentum()/MeV;
02412           currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02413         }
02414         pp1 = targetParticle.GetMomentum().mag()/MeV;
02415         if( pp1 >= 1.0 )
02416         {
02417           ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
02418           ekin = std::max( 0.0001*GeV, ekin );
02419           targetParticle.SetKineticEnergy( ekin*MeV );
02420           pp = targetParticle.GetTotalMomentum()/MeV;
02421           targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
02422         }
02423       }
02424     }
02425 
02426     // Get number of final state nucleons and nucleons remaining in
02427     // target nucleus
02428     
02429     std::pair<G4int, G4int> finalStateNucleons = 
02430       GetFinalStateNucleons(originalTarget, vec, vecLen);
02431     G4int protonsInFinalState = finalStateNucleons.first;
02432     G4int neutronsInFinalState = finalStateNucleons.second;
02433 
02434     G4int PinNucleus = std::max(0, 
02435       targetNucleus.GetZ_asInt() - protonsInFinalState);
02436     G4int NinNucleus = std::max(0,
02437       targetNucleus.GetN_asInt() - neutronsInFinalState);
02438 
02439       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02440     if( atomicWeight >= 1.5 )
02441     {
02442       // Add black track particles
02443       // npnb is number of proton/neutron black track particles
02444       // ndta is the number of deuterons, tritons, and alphas produced
02445       // epnb is the kinetic energy available for proton/neutron black track particles
02446       // edta is the kinetic energy available for deuteron/triton/alpha particles
02447       //
02448       G4double epnb, edta;
02449       G4int npnb=0, ndta=0;
02450       
02451       epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
02452       edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
02453       const G4double pnCutOff = 0.0001;       // GeV
02454       const G4double dtaCutOff = 0.0001;      // GeV
02455       const G4double kineticMinimum = 0.0001;
02456       const G4double kineticFactor = -0.010;
02457       G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
02458       if( epnb >= pnCutOff )
02459       {
02460         npnb = Poisson( epnb/0.02 );
02461         if( npnb > atomicWeight )npnb = G4int(atomicWeight);
02462         if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
02463         npnb = std::min( npnb, 127-vecLen );
02464       }
02465       if( edta >= dtaCutOff )
02466       {
02467         ndta = G4int(2.0 * std::log(atomicWeight));
02468         ndta = std::min( ndta, 127-vecLen );
02469       }
02470 
02471       if (npnb == 0 && ndta == 0) npnb = 1;
02472 
02473       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02474 
02475       AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
02476                              kineticFactor, modifiedOriginal, 
02477                              PinNucleus, NinNucleus, targetNucleus,
02478                              vec, vecLen);
02479       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02480     }
02481     //
02482     //  calculate time delay for nuclear reactions
02483     //
02484     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
02485       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
02486     else
02487       currentParticle.SetTOF( 1.0 );
02488     return;
02489   }

G4bool G4ReactionDynamics::TwoCluster ( G4FastVector< G4ReactionProduct, GHADLISTSIZE > &  vec,
G4int vecLen,
G4ReactionProduct modifiedOriginal,
const G4HadProjectile originalIncident,
G4ReactionProduct currentParticle,
G4ReactionProduct targetParticle,
const G4DynamicParticle originalTarget,
const G4Nucleus targetNucleus,
G4bool incidentHasChanged,
G4bool targetHasChanged,
G4bool  leadFlag,
G4ReactionProduct leadingStrangeParticle 
)

Definition at line 1434 of file G4ReactionDynamics.cc.

References G4UniformRand, GenerateNBodyEvent(), G4Nucleus::GetA_asInt(), G4Nucleus::GetAnnihilationDTABlackTrackEnergy(), G4Nucleus::GetAnnihilationPNBlackTrackEnergy(), G4ParticleDefinition::GetBaryonNumber(), G4HadProjectile::GetDefinition(), G4ReactionProduct::GetDefinition(), G4Nucleus::GetDTABlackTrackEnergy(), G4HadProjectile::GetKineticEnergy(), G4ReactionProduct::GetKineticEnergy(), G4ReactionProduct::GetMass(), G4ReactionProduct::GetMomentum(), G4Nucleus::GetN_asInt(), G4ParticleDefinition::GetPDGMass(), G4Nucleus::GetPNBlackTrackEnergy(), G4ReactionProduct::GetSide(), G4ReactionProduct::GetTotalEnergy(), G4ReactionProduct::GetTotalMomentum(), G4Nucleus::GetZ_asInt(), G4FastVector< Type, N >::Initialize(), G4Lambda::Lambda(), G4ReactionProduct::Lorentz(), G4Neutron::Neutron(), G4PionMinus::PionMinus(), G4PionPlus::PionPlus(), G4PionZero::PionZero(), G4InuclParticleNames::pp, G4Proton::Proton(), G4ReactionProduct::SetDefinition(), G4FastVector< Type, N >::SetElement(), G4ReactionProduct::SetKineticEnergy(), G4ReactionProduct::SetMass(), G4ReactionProduct::SetMomentum(), G4ReactionProduct::SetSide(), and G4ReactionProduct::SetTotalEnergy().

Referenced by G4InelasticInteraction::CalculateMomenta().

01447   {
01448       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01449     // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
01450     //
01451     //  Generation of X- and PT- values for incident, target, and all secondary particles 
01452     //  
01453     //  A simple two cluster model is used.
01454     //  This should be sufficient for low energy interactions.
01455     //
01456 
01457     // + debugging
01458     // raise(SIGSEGV);
01459     // - debugging
01460 
01461     G4int i;
01462     G4ParticleDefinition *aProton = G4Proton::Proton();
01463     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
01464     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
01465     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
01466     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
01467     G4bool veryForward = false;
01468 
01469     const G4double protonMass = aProton->GetPDGMass()/MeV;
01470     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
01471     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
01472     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
01473     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
01474     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
01475     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
01476                                         targetMass*targetMass +
01477                                         2.0*targetMass*etOriginal );  // GeV
01478     G4double currentMass = currentParticle.GetMass()/GeV;
01479     targetMass = targetParticle.GetMass()/GeV;
01480 
01481     if( currentMass == 0.0 && targetMass == 0.0 )
01482     {
01483       G4double ek = currentParticle.GetKineticEnergy();
01484       G4ThreeVector mom = currentParticle.GetMomentum();
01485       currentParticle = *vec[0];
01486       targetParticle = *vec[1];
01487       for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
01488       if(vecLen<2) 
01489       {
01490         for(G4int j=0; j<vecLen; j++) delete vec[j];
01491         vecLen = 0;
01492         throw G4HadReentrentException(__FILE__, __LINE__,
01493         "G4ReactionDynamics::TwoCluster: Negative number of particles");
01494       }
01495       delete vec[vecLen-1];
01496       delete vec[vecLen-2];
01497       vecLen -= 2;
01498       currentMass = currentParticle.GetMass()/GeV;
01499       targetMass = targetParticle.GetMass()/GeV;
01500       incidentHasChanged = true;
01501       targetHasChanged = true;
01502       currentParticle.SetKineticEnergy( ek );
01503       currentParticle.SetMomentum( mom );
01504       veryForward = true;
01505     }
01506 
01507     const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
01508     const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
01509     //
01510     // particles have been distributed in forward and backward hemispheres
01511     // in center of mass system of the hadron nucleon interaction
01512     //
01513     // incident is always in forward hemisphere
01514     G4int forwardCount = 1;            // number of particles in forward hemisphere
01515     currentParticle.SetSide( 1 );
01516     G4double forwardMass = currentParticle.GetMass()/GeV;
01517     G4double cMass = forwardMass;
01518     
01519     // target is always in backward hemisphere
01520     G4int backwardCount = 1;           // number of particles in backward hemisphere
01521     G4int backwardNucleonCount = 1;    // number of nucleons in backward hemisphere
01522     targetParticle.SetSide( -1 );
01523     G4double backwardMass = targetParticle.GetMass()/GeV;
01524     G4double bMass = backwardMass;
01525     
01526     for( i=0; i<vecLen; ++i )
01527     {
01528       if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
01529       // to take care of the case where vec has been preprocessed by GenerateXandPt
01530       // and some of them have been set to -2 or -3
01531       if( vec[i]->GetSide() == -1 )
01532       {
01533         ++backwardCount;
01534         backwardMass += vec[i]->GetMass()/GeV;
01535       }
01536       else
01537       {
01538         ++forwardCount;
01539         forwardMass += vec[i]->GetMass()/GeV;
01540       }
01541     }
01542     //
01543     // nucleons and some pions from intranuclear cascade
01544     //
01545     G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
01546     if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
01547     const G4double afc = 0.312 + 0.2 * std::log(term1);
01548     G4double xtarg;
01549     if( centerofmassEnergy < 2.0+G4UniformRand() )        // added +2 below, JLC 4Jul97
01550       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
01551     else
01552       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
01553     if( xtarg <= 0.0 )xtarg = 0.01;
01554     G4int nuclearExcitationCount = Poisson( xtarg );
01555     if(atomicWeight<1.0001) nuclearExcitationCount = 0;
01556     G4int extraNucleonCount = 0;
01557     G4double extraMass = 0.0;
01558     G4double extraNucleonMass = 0.0;
01559     if( nuclearExcitationCount > 0 )
01560     {
01561       G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );     
01562       const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
01563       //
01564       //  NOTE: in TWOCLU, these new particles were given negative codes
01565       //        here we use  NewlyAdded = true  instead
01566       //
01567 //      G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
01568       for( i=0; i<nuclearExcitationCount; ++i )
01569       {
01570         G4ReactionProduct* pVec = new G4ReactionProduct();
01571         if( G4UniformRand() < nucsup[momentumBin] )  // add proton or neutron
01572         {
01573           if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
01574             pVec->SetDefinition( aProton );
01575           else
01576             pVec->SetDefinition( aNeutron );
01577           ++backwardNucleonCount;
01578           ++extraNucleonCount;
01579           extraNucleonMass += pVec->GetMass()/GeV;
01580         }
01581         else
01582         {                                       // add a pion
01583           G4double ran = G4UniformRand();
01584           if( ran < 0.3181 )
01585             pVec->SetDefinition( aPiPlus );
01586           else if( ran < 0.6819 )
01587             pVec->SetDefinition( aPiZero );
01588           else
01589             pVec->SetDefinition( aPiMinus );
01590         }
01591         pVec->SetSide( -2 );    // backside particle
01592         extraMass += pVec->GetMass()/GeV;
01593         pVec->SetNewlyAdded( true );
01594         vec.SetElement( vecLen++, pVec );
01595         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01596       }
01597     }
01598       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01599     G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
01600     G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
01601     G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
01602     G4bool secondaryDeleted;
01603     G4double pMass;
01604 
01605     while( eAvailable <= 0.0 )   // must eliminate a particle
01606     {
01607       secondaryDeleted = false;
01608       for( i=(vecLen-1); i>=0; --i )
01609       {
01610         if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
01611         {
01612           pMass = vec[i]->GetMass()/GeV;
01613           for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];     // shift up
01614           --forwardCount;
01615           forwardEnergy += pMass;
01616           forwardMass -= pMass;
01617           secondaryDeleted = true;
01618           break;
01619         }
01620         else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
01621         {
01622           pMass = vec[i]->GetMass()/GeV;
01623           for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01624           --backwardCount;
01625           backwardEnergy += pMass;
01626           backwardMass -= pMass;
01627           secondaryDeleted = true;
01628           break;
01629         }
01630       }           // breaks go down to here
01631       if( secondaryDeleted )
01632       {      
01633         delete vec[vecLen-1];
01634         --vecLen;
01635         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01636       }
01637       else
01638       {
01639         if( vecLen == 0 )
01640         {
01641           return false;  // all secondaries have been eliminated
01642         }
01643         if( targetParticle.GetSide() == -1 )
01644         {
01645           pMass = targetParticle.GetMass()/GeV;
01646           targetParticle = *vec[0];
01647           for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01648           --backwardCount;
01649           backwardEnergy += pMass;
01650           backwardMass -= pMass;
01651           secondaryDeleted = true;
01652         }
01653         else if( targetParticle.GetSide() == 1 )
01654         {
01655           pMass = targetParticle.GetMass()/GeV;
01656           targetParticle = *vec[0];
01657           for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01658           --forwardCount;
01659           forwardEnergy += pMass;
01660           forwardMass -= pMass;
01661           secondaryDeleted = true;
01662         }
01663         if( secondaryDeleted )
01664         {
01665           delete vec[vecLen-1];
01666           --vecLen;
01667           // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01668         }
01669         else
01670         {
01671           if( currentParticle.GetSide() == -1 )
01672           {
01673             pMass = currentParticle.GetMass()/GeV;
01674             currentParticle = *vec[0];
01675             for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01676             --backwardCount;
01677             backwardEnergy += pMass;
01678             backwardMass -= pMass;
01679             secondaryDeleted = true;
01680           }
01681           else if( currentParticle.GetSide() == 1 )
01682           {
01683             pMass = currentParticle.GetMass()/GeV;
01684             currentParticle = *vec[0];
01685             for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01686             --forwardCount;
01687             forwardEnergy += pMass;
01688             forwardMass -= pMass;
01689             secondaryDeleted = true;
01690           }
01691           if( secondaryDeleted )
01692           {
01693             delete vec[vecLen-1];
01694             --vecLen;
01695             // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01696           }
01697           else break;
01698         }
01699       }
01700       eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
01701     }
01702     //
01703     // This is the start of the TwoCluster function
01704     //  Choose masses for the 3 clusters:
01705     //   forward cluster
01706     //   backward meson cluster
01707     //   backward nucleon cluster
01708     //
01709     G4double rmc = 0.0, rmd = 0.0;
01710     const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
01711     const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
01712     
01713     if (forwardCount <= 0 || backwardCount <= 0) return false;  // array bounds protection
01714 
01715     if (forwardCount == 1) rmc = forwardMass;
01716     else 
01717     {
01718       G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
01719       rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
01720     }
01721 
01722     if (backwardCount == 1) rmd = backwardMass;
01723     else
01724     {
01725       G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
01726       rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
01727     }
01728 
01729     while( rmc+rmd > centerofmassEnergy )
01730     {
01731       if( (rmc <= forwardMass) && (rmd <= backwardMass) )
01732       {
01733         G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
01734         rmc *= temp;
01735         rmd *= temp;
01736       }
01737       else
01738       {
01739         rmc = 0.1*forwardMass + 0.9*rmc;
01740         rmd = 0.1*backwardMass + 0.9*rmd;
01741       }
01742     }
01743 
01744     G4ReactionProduct pseudoParticle[8];
01745     for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
01746     
01747     pseudoParticle[1].SetMass( mOriginal*GeV );
01748     pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
01749     pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
01750     
01751     pseudoParticle[2].SetMass( protonMass*MeV );
01752     pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
01753     pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
01754     //
01755     //  transform into centre of mass system
01756     //
01757     pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
01758     pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
01759     pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
01760     
01761     const G4double pfMin = 0.0001;
01762     G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
01763     pf *= pf;
01764     pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
01765     pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
01766     //
01767     //  set final state masses and energies in centre of mass system
01768     //
01769     pseudoParticle[3].SetMass( rmc*GeV );
01770     pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
01771     
01772     pseudoParticle[4].SetMass( rmd*GeV );
01773     pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
01774     //
01775     // set |T| and |TMIN|
01776     //
01777     const G4double bMin = 0.01;
01778     const G4double b1 = 4.0;
01779     const G4double b2 = 1.6;
01780 
01781     G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
01782     G4double dtb = 4.0*pin*pf*std::max( bMin, b1+b2*std::log(pOriginal) );
01783     G4double factor = 1.0 - std::exp(-dtb);
01784     G4double costheta = 1.0 + 2.0*std::log(1.0 - G4UniformRand()*factor) / dtb;
01785     costheta = std::max(-1.0, std::min(1.0, costheta));
01786     G4double sintheta = std::sqrt(1.0-costheta*costheta);
01787     G4double phi = G4UniformRand() * twopi;
01788 
01789     //
01790     // calculate final state momenta in centre of mass system
01791     //
01792     pseudoParticle[3].SetMomentum( pf*sintheta*std::cos(phi)*GeV,
01793                                    pf*sintheta*std::sin(phi)*GeV,
01794                                    pf*costheta*GeV );
01795 
01796     pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
01797     //
01798     // simulate backward nucleon cluster in lab. system and transform in cms
01799     //
01800     G4double pp, pp1;
01801     if( nuclearExcitationCount > 0 )
01802     {
01803       const G4double ga = 1.2;
01804       G4double ekit1 = 0.04;
01805       G4double ekit2 = 0.6;
01806       if( ekOriginal <= 5.0 )
01807       {
01808         ekit1 *= ekOriginal*ekOriginal/25.0;
01809         ekit2 *= ekOriginal*ekOriginal/25.0;
01810       }
01811       const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
01812       for( i=0; i<vecLen; ++i )
01813       {
01814         if( vec[i]->GetSide() == -2 )
01815         {
01816           G4double kineticE =
01817             std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
01818           vec[i]->SetKineticEnergy( kineticE*GeV );
01819           G4double vMass = vec[i]->GetMass()/MeV;
01820           G4double totalE = kineticE*GeV + vMass;
01821           pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
01822           G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
01823           G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
01824           phi = twopi*G4UniformRand();
01825           vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
01826                                pp*sint*std::cos(phi)*MeV,
01827                                pp*cost*MeV );
01828           vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
01829         }
01830       }
01831       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01832     }
01833     //
01834     // fragmentation of forward cluster and backward meson cluster
01835     //
01836     currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
01837     currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
01838     
01839     targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
01840     targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
01841     
01842     pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
01843     pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
01844     pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
01845     
01846     pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
01847     pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
01848     pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
01849     
01850     G4double wgt;
01851       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01852     if( forwardCount > 1 )     // tempV will contain the forward particles
01853     {
01854       G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
01855       tempV.Initialize( forwardCount );
01856       G4bool constantCrossSection = true;
01857       G4int tempLen = 0;
01858       if( currentParticle.GetSide() == 1 )
01859         tempV.SetElement( tempLen++, &currentParticle );
01860       if( targetParticle.GetSide() == 1 )
01861         tempV.SetElement( tempLen++, &targetParticle );
01862       for( i=0; i<vecLen; ++i )
01863       {
01864         if( vec[i]->GetSide() == 1 )
01865         {
01866           if( tempLen < 18 )
01867             tempV.SetElement( tempLen++, vec[i] );
01868           else
01869           {
01870             vec[i]->SetSide( -1 );
01871             continue;
01872           }
01873         }
01874       }
01875       if( tempLen >= 2 )
01876       {
01877         wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
01878                                   constantCrossSection, tempV, tempLen );
01879         if( currentParticle.GetSide() == 1 )
01880           currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
01881         if( targetParticle.GetSide() == 1 )
01882           targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
01883         for( i=0; i<vecLen; ++i )
01884         {
01885           if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
01886         }
01887       }
01888     }
01889       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01890     if( backwardCount > 1 )   //  tempV will contain the backward particles,
01891     {                         //  but not those created from the intranuclear cascade
01892       G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
01893       tempV.Initialize( backwardCount );
01894       G4bool constantCrossSection = true;
01895       G4int tempLen = 0;
01896       if( currentParticle.GetSide() == -1 )
01897         tempV.SetElement( tempLen++, &currentParticle );
01898       if( targetParticle.GetSide() == -1 )
01899         tempV.SetElement( tempLen++, &targetParticle );
01900       for( i=0; i<vecLen; ++i )
01901       {
01902         if( vec[i]->GetSide() == -1 )
01903         {
01904           if( tempLen < 18 )
01905             tempV.SetElement( tempLen++, vec[i] );
01906           else
01907           {
01908             vec[i]->SetSide( -2 );
01909             vec[i]->SetKineticEnergy( 0.0 );
01910             vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
01911             continue;
01912           }
01913         }
01914       }
01915       if( tempLen >= 2 )
01916       {
01917         wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
01918                                   constantCrossSection, tempV, tempLen );
01919         if( currentParticle.GetSide() == -1 )
01920           currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
01921         if( targetParticle.GetSide() == -1 )
01922           targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
01923         for( i=0; i<vecLen; ++i )
01924         {
01925           if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
01926         }
01927       }
01928     }
01929       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01930     //
01931     // Lorentz transformation in lab system
01932     //
01933     currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
01934     targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
01935     for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
01936 
01937       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01938     //
01939     // sometimes the leading strange particle is lost, set it back
01940     //
01941     G4bool dum = true;
01942     if( leadFlag )
01943     {
01944       // leadFlag will be true
01945       //  iff original particle is at least as heavy as K+ and not a proton or 
01946       //  neutron AND if incident particle is at least as heavy as K+ and it is
01947       //  not a proton or neutron leadFlag is set to the incident particle
01948       //  or
01949       //  target particle is at least as heavy as K+ and it is not a proton or 
01950       //  neutron leadFlag is set to the target particle
01951       //
01952       if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
01953         dum = false;
01954       else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
01955         dum = false;
01956       else
01957       {
01958         for( i=0; i<vecLen; ++i )
01959         {
01960           if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
01961           {
01962             dum = false;
01963             break;
01964           }
01965         }
01966       }
01967       if( dum )
01968       {
01969         G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
01970         G4double ekin;
01971         if( ((leadMass <  protonMass) && (targetParticle.GetMass()/MeV <  protonMass)) ||
01972             ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
01973         {
01974           ekin = targetParticle.GetKineticEnergy()/GeV;
01975           pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
01976           targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
01977           targetParticle.SetKineticEnergy( ekin*GeV );
01978           pp = targetParticle.GetTotalMomentum()/MeV;   // new momentum
01979           if( pp1 < 1.0e-3 )
01980           {
01981             G4double costheta2 = 2.*G4UniformRand() - 1.;
01982             G4double sintheta2 = std::sqrt(1. - costheta2*costheta2);
01983             G4double phi2 = twopi*G4UniformRand();
01984             targetParticle.SetMomentum( pp*sintheta2*std::cos(phi2)*MeV,
01985                                         pp*sintheta2*std::sin(phi2)*MeV,
01986                                         pp*costheta2*MeV ) ;
01987           }
01988           else
01989             targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
01990           
01991           targetHasChanged = true;
01992         }
01993         else
01994         {
01995           ekin = currentParticle.GetKineticEnergy()/GeV;
01996           pp1 = currentParticle.GetMomentum().mag()/MeV;
01997           currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
01998           currentParticle.SetKineticEnergy( ekin*GeV );
01999           pp = currentParticle.GetTotalMomentum()/MeV;
02000           if( pp1 < 1.0e-3 )
02001           {
02002             G4double costheta2 = 2.*G4UniformRand() - 1.;
02003             G4double sintheta2 = std::sqrt(1. - costheta2*costheta2);
02004             G4double phi2 = twopi*G4UniformRand();
02005             currentParticle.SetMomentum( pp*sintheta2*std::cos(phi2)*MeV,
02006                                          pp*sintheta2*std::sin(phi2)*MeV,
02007                                          pp*costheta2*MeV ) ;
02008           }
02009           else
02010             currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02011           
02012           incidentHasChanged = true;
02013         }
02014       }
02015     }    // end of if( leadFlag )
02016 
02017     // Get number of final state nucleons and nucleons remaining in
02018     // target nucleus
02019     
02020     std::pair<G4int, G4int> finalStateNucleons = 
02021       GetFinalStateNucleons(originalTarget, vec, vecLen);
02022 
02023     G4int protonsInFinalState = finalStateNucleons.first;
02024     G4int neutronsInFinalState = finalStateNucleons.second;
02025 
02026     G4int numberofFinalStateNucleons = 
02027       protonsInFinalState + neutronsInFinalState;
02028 
02029     if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
02030         targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
02031         originalIncident->GetDefinition()->GetPDGMass() < 
02032                                    G4Lambda::Lambda()->GetPDGMass())
02033       numberofFinalStateNucleons++;
02034 
02035     numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
02036 
02037     G4int PinNucleus = std::max(0, 
02038       targetNucleus.GetZ_asInt() - protonsInFinalState);
02039     G4int NinNucleus = std::max(0,
02040       targetNucleus.GetN_asInt() - neutronsInFinalState);
02041     //
02042     //  for various reasons, the energy balance is not sufficient,
02043     //  check that,  energy balance, angle of final system, etc.
02044     //
02045     pseudoParticle[4].SetMass( mOriginal*GeV );
02046     pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
02047     pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
02048     
02049     G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
02050     G4int diff = 0;
02051     if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
02052     if(numberofFinalStateNucleons == 1) diff = 0;
02053     pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
02054     pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV);
02055     pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV);
02056     
02057     G4double theoreticalKinetic =
02058       pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
02059     
02060     pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
02061     pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
02062     pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
02063      
02064     if( vecLen < 16 )
02065     {
02066       G4ReactionProduct tempR[130];
02067       tempR[0] = currentParticle;
02068       tempR[1] = targetParticle;
02069       for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
02070 
02071       G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
02072       tempV.Initialize( vecLen+2 );
02073       G4bool constantCrossSection = true;
02074       G4int tempLen = 0;
02075       for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
02076 
02077       if( tempLen >= 2 )
02078       {
02079       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02080         wgt = GenerateNBodyEvent( pseudoParticle[4].GetTotalEnergy()/MeV +
02081                                   pseudoParticle[5].GetTotalEnergy()/MeV,
02082                                   constantCrossSection, tempV, tempLen );
02083         if (wgt == -1) {
02084           G4double Qvalue = 0;
02085           for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
02086           wgt = GenerateNBodyEvent( Qvalue/MeV,
02087                                     constantCrossSection, tempV, tempLen );
02088         }
02089         theoreticalKinetic = 0.0;
02090         for( i=0; i<vecLen+2; ++i )
02091         {
02092           pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
02093           pseudoParticle[7].SetMass( tempV[i]->GetMass() );
02094           pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
02095           pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
02096           theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
02097         }
02098       }
02099       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02100     }
02101     else
02102     {
02103       theoreticalKinetic -=
02104         ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
02105       for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
02106     }
02107     G4double simulatedKinetic =
02108       currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
02109     for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
02110     //
02111     // make sure that kinetic energies are correct
02112     // the backward nucleon cluster is not produced within proper kinematics!!!
02113     //
02114     
02115     if( simulatedKinetic != 0.0 )
02116     {
02117       wgt = (theoreticalKinetic)/simulatedKinetic;
02118       currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
02119       pp = currentParticle.GetTotalMomentum()/MeV;
02120       pp1 = currentParticle.GetMomentum().mag()/MeV;
02121       if( pp1 < 0.001*MeV )
02122       {
02123         G4double costheta2 = 2.*G4UniformRand() - 1.;
02124         G4double sintheta2 = std::sqrt(1. - costheta2*costheta2);
02125         G4double phi2 = twopi*G4UniformRand();
02126         currentParticle.SetMomentum( pp*sintheta2*std::cos(phi2)*MeV,
02127                                      pp*sintheta2*std::sin(phi2)*MeV,
02128                                      pp*costheta2*MeV ) ;
02129       }
02130       else
02131         currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02132       
02133       targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
02134       pp = targetParticle.GetTotalMomentum()/MeV;
02135       pp1 = targetParticle.GetMomentum().mag()/MeV;
02136       if( pp1 < 0.001*MeV )
02137       {
02138         G4double costheta2 = 2.*G4UniformRand() - 1.;
02139         G4double sintheta2 = std::sqrt(1. - costheta2*costheta2);
02140         G4double phi2 = twopi*G4UniformRand();
02141         targetParticle.SetMomentum( pp*sintheta2*std::cos(phi2)*MeV,
02142                                     pp*sintheta2*std::sin(phi2)*MeV,
02143                                     pp*costheta2*MeV ) ;
02144       }
02145       else
02146         targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
02147       
02148       for( i=0; i<vecLen; ++i )
02149       {
02150         vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
02151         pp = vec[i]->GetTotalMomentum()/MeV;
02152         pp1 = vec[i]->GetMomentum().mag()/MeV;
02153         if( pp1 < 0.001 )
02154         {
02155           G4double costheta2 = 2.*G4UniformRand() - 1.;
02156           G4double sintheta2 = std::sqrt(1. - costheta2*costheta2);
02157           G4double phi2 = twopi*G4UniformRand();
02158           vec[i]->SetMomentum( pp*sintheta2*std::cos(phi2)*MeV,
02159                                pp*sintheta2*std::sin(phi2)*MeV,
02160                                pp*costheta2*MeV ) ;
02161         }
02162         else
02163           vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
02164       }
02165     }
02166       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02167 
02168     Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
02169             modifiedOriginal, originalIncident, targetNucleus,
02170             currentParticle, targetParticle, vec, vecLen );
02171     //
02172     //  add black track particles
02173     //  the total number of particles produced is restricted to 198
02174     //  this may have influence on very high energies
02175     //
02176     if( atomicWeight >= 1.5 )
02177     {
02178       // npnb is number of proton/neutron black track particles
02179       // ndta is the number of deuterons, tritons, and alphas produced
02180       // epnb is the kinetic energy available for proton/neutron black track 
02181       //   particles
02182       // edta is the kinetic energy available for deuteron/triton/alpha 
02183       //   particles
02184 
02185       G4int npnb = 0;
02186       G4int ndta = 0;
02187 
02188       G4double epnb, edta;
02189       if (veryForward) {
02190         epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
02191         edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
02192       } else {
02193         epnb = targetNucleus.GetPNBlackTrackEnergy();
02194         edta = targetNucleus.GetDTABlackTrackEnergy();
02195       }
02196 
02197       const G4double pnCutOff = 0.001;     // GeV
02198       const G4double dtaCutOff = 0.001;    // GeV
02199       const G4double kineticMinimum = 1.e-6;
02200       const G4double kineticFactor = -0.005;
02201       
02202       G4double sprob = 0.0;   // sprob = probability of self-absorption in 
02203                               // heavy molecules
02204       const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
02205       if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
02206       
02207       if( epnb >= pnCutOff )
02208       {
02209         npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
02210         if( numberofFinalStateNucleons + npnb > atomicWeight )
02211           npnb = G4int(atomicWeight - numberofFinalStateNucleons);
02212         npnb = std::min( npnb, 127-vecLen );
02213       }
02214       if( edta >= dtaCutOff )
02215       {
02216         ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
02217         ndta = std::min( ndta, 127-vecLen );
02218       }
02219       if (npnb == 0 && ndta == 0) npnb = 1;
02220 
02221       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02222 
02223       AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
02224                              kineticFactor, modifiedOriginal, 
02225                              PinNucleus, NinNucleus, targetNucleus,
02226                              vec, vecLen );
02227       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02228     }
02229     //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
02230     //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
02231     //
02232     //  calculate time delay for nuclear reactions
02233     //
02234     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
02235       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
02236     else
02237       currentParticle.SetTOF( 1.0 );
02238     
02239       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02240     return true;
02241   }


The documentation for this class was generated from the following files:
Generated on Mon May 27 17:53:16 2013 for Geant4 by  doxygen 1.4.7