CMS 3D CMS Logo

FullModelReactionDynamics.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * DISCLAIMER                                                       *
00004 // *                                                                  *
00005 // * The following disclaimer summarizes all the specific disclaimers *
00006 // * of contributors to this software. The specific disclaimers,which *
00007 // * govern, are listed with their locations in:                      *
00008 // *   https://cern.ch/geant4/license                                  *
00009 // *                                                                  *
00010 // * Neither the authors of this software system, nor their employing *
00011 // * institutes,nor the agencies providing financial support for this *
00012 // * work  make  any representation or  warranty, express or implied, *
00013 // * regarding  this  software system or assume any liability for its *
00014 // * use.                                                             *
00015 // *                                                                  *
00016 // * This  code  implementation is the  intellectual property  of the *
00017 // * GEANT4 collaboration.                                            *
00018 // * By copying,  distributing  or modifying the Program (or any work *
00019 // * based  on  the Program)  you indicate  your  acceptance of  this *
00020 // * statement, and all its terms.                                    *
00021 // ********************************************************************
00022 //
00023 //
00024 //
00025  // Hadronic Process: Reaction Dynamics
00026  // original by H.P. Wellisch
00027  // modified by J.L. Chuma, TRIUMF, 19-Nov-1996
00028  // Last modified: 27-Mar-1997
00029  // modified by H.P. Wellisch, 24-Apr-97
00030  // H.P. Wellisch, 25.Apr-97: Side of current and target particle taken into account
00031  // H.P. Wellisch, 29.Apr-97: Bug fix in NuclearReaction. (pseudo1 was without energy)
00032  // J.L. Chuma, 30-Apr-97:  Changed return value for GenerateXandPt.  It seems possible
00033  //                         that GenerateXandPt could eliminate some secondaries, but
00034  //                         still finish its calculations, thus we would not want to
00035  //                         then use TwoCluster to again calculate the momenta if vecLen
00036  //                         was less than 6.
00037  // J.L. Chuma, 10-Jun-97:  Modified NuclearReaction.  Was not creating ReactionProduct's
00038  //                         with the new operator, thus they would be meaningless when
00039  //                         going out of scope.
00040  // J.L. Chuma, 20-Jun-97:  Modified GenerateXandPt and TwoCluster to fix units problems
00041  // J.L. Chuma, 23-Jun-97:  Modified ProduceStrangeParticlePairs to fix units problems
00042  // J.L. Chuma, 26-Jun-97:  Modified ProduceStrangeParticlePairs to fix array indices
00043  //                         which were sometimes going out of bounds
00044  // J.L. Chuma, 04-Jul-97:  Many minor modifications to GenerateXandPt and TwoCluster
00045  // J.L. Chuma, 06-Aug-97:  Added original incident particle, before Fermi motion and
00046  //                         evaporation effects are included, needed for self absorption
00047  //                         and corrections for single particle spectra (shower particles)
00048  // logging stopped 1997
00049  // J. Allison, 17-Jun-99:  Replaced a min function to get correct behaviour on DEC.
00050  
00051 #include "SimG4Core/CustomPhysics/interface/FullModelReactionDynamics.hh"
00052 #include "G4AntiProton.hh"
00053 #include "G4AntiNeutron.hh"
00054 #include "Randomize.hh"
00055 #include <iostream>
00056 #include "G4HadReentrentException.hh"
00057 #include <signal.h>
00058 #include "G4ParticleTable.hh"
00059 
00060 // #include "DumpFrame.hh"
00061 
00062 /*         G4double GetQValue(G4ReactionProduct * aSec)
00063            {
00064              double QValue=0;
00065              if(aSec->GetDefinition()->GetParticleType() == "baryon")
00066              { 
00067                if(aSec->GetDefinition()->GetBaryonNumber() < 0)
00068                {
00069                  QValue = aSec->GetTotalEnergy();
00070                  QValue += G4Neutron::Neutron()->GetPDGMass();
00071                }
00072                else
00073                {
00074                  G4double ss = 0;
00075                  ss +=aSec->GetDefinition()->GetPDGMass();
00076                  if(aSec->GetDefinition() == G4Proton::Proton())
00077                  {
00078                    ss -=G4Proton::Proton()->GetPDGMass();
00079                  }
00080                  else
00081                  {
00082                    ss -=G4Neutron::Neutron()->GetPDGMass();
00083                  }
00084                  ss += aSec->GetKineticEnergy();
00085                  QValue = ss;
00086                }
00087              }
00088              else if(aSec->GetDefinition()->GetPDGEncoding() == 0)
00089              {
00090                QValue = aSec->GetKineticEnergy();
00091              }
00092              else
00093              {
00094                QValue = aSec->GetTotalEnergy();
00095              }
00096              return QValue;
00097            }
00098 */
00099  
00100  G4bool FullModelReactionDynamics::GenerateXandPt(
00101    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
00102    G4int &vecLen,
00103    G4ReactionProduct &modifiedOriginal,   // Fermi motion & evap. effects included
00104    const G4HadProjectile *originalIncident,   // the original incident particle
00105    G4ReactionProduct &currentParticle,
00106    G4ReactionProduct &targetParticle,
00107    const G4Nucleus &targetNucleus,
00108    G4bool &incidentHasChanged,
00109    G4bool &targetHasChanged,
00110    G4bool leadFlag,
00111    G4ReactionProduct &leadingStrangeParticle )
00112   {
00113     // 
00114     // derived from original FORTRAN code GENXPT by H. Fesefeldt (11-Oct-1987)
00115     //
00116     //  Generation of X- and PT- values for incident, target, and all secondary particles 
00117     //  A simple single variable description E D3S/DP3= F(Q) with
00118     //  Q^2 = (M*X)^2 + PT^2 is used. Final state kinematic is produced
00119     //  by an FF-type iterative cascade method
00120     //
00121     //  internal units are GeV
00122     //
00123     // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00124     
00125     // Protection in case no secondary has been created; cascades down to two-body.
00126     if(vecLen == 0) return false;
00127 
00128     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
00129     // G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
00130     // G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
00131     G4ParticleDefinition *aProton = G4Proton::Proton();
00132     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
00133     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
00134     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
00135     G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
00136     G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
00137     G4ParticleDefinition *aKaonZeroS = G4KaonZeroShort::KaonZeroShort();
00138     G4ParticleDefinition *aKaonZeroL = G4KaonZeroLong::KaonZeroLong();
00139 
00140     G4int i, l;
00141     G4double forVeryForward = 0.;
00142     G4bool veryForward = false;
00143     
00144     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
00145     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
00146     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
00147     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
00148     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
00149     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
00150                                         targetMass*targetMass +
00151                                         2.0*targetMass*etOriginal );  // GeV
00152     G4double currentMass = currentParticle.GetMass()/GeV;
00153     targetMass = targetParticle.GetMass()/GeV;
00154     //
00155     //  randomize the order of the secondary particles
00156     //  note that the current and target particles are not affected
00157     //
00158     for( i=0; i<vecLen; ++i )
00159     {
00160       G4int itemp = G4int( G4UniformRand()*vecLen );
00161       G4ReactionProduct pTemp = *vec[itemp];
00162       *vec[itemp] = *vec[i];
00163       *vec[i] = pTemp;
00164       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00165     }
00166 
00167     if( currentMass == 0.0 && targetMass == 0.0 )       // annihilation
00168     {
00169       // no kinetic energy in target .....
00170       G4double ek = currentParticle.GetKineticEnergy();
00171       G4ThreeVector m = currentParticle.GetMomentum();
00172       currentParticle = *vec[0];
00173       targetParticle = *vec[1];
00174       for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
00175       G4ReactionProduct *temp = vec[vecLen-1];
00176       delete temp;
00177       temp = vec[vecLen-2];
00178       delete temp;
00179       vecLen -= 2;
00180       currentMass = currentParticle.GetMass()/GeV;
00181       targetMass = targetParticle.GetMass()/GeV;
00182       incidentHasChanged = true;
00183       targetHasChanged = true;
00184       currentParticle.SetKineticEnergy( ek );
00185       currentParticle.SetMomentum( m );
00186       forVeryForward = aProton->GetPDGMass();
00187       veryForward = true;
00188     }
00189     const G4double atomicWeight = targetNucleus.GetN();
00190     //    G4cout <<"Atomic weight is: "<<atomicWeight<<G4endl;
00191     const G4double atomicNumber = targetNucleus.GetZ();
00192     const G4double protonMass = aProton->GetPDGMass()/MeV;
00193     if( (originalIncident->GetDefinition() == aKaonMinus ||
00194          originalIncident->GetDefinition() == aKaonZeroL ||
00195          originalIncident->GetDefinition() == aKaonZeroS ||
00196          originalIncident->GetDefinition() == aKaonPlus) &&
00197         G4UniformRand() >= 0.7 )
00198     {
00199       G4ReactionProduct temp = currentParticle;
00200       currentParticle = targetParticle;
00201       targetParticle = temp;
00202       incidentHasChanged = true;
00203       targetHasChanged = true;
00204       currentMass = currentParticle.GetMass()/GeV;
00205       targetMass = targetParticle.GetMass()/GeV;
00206     }
00207     const G4double afc = std::min( 0.75,
00208                               0.312+0.200*std::log(std::log(centerofmassEnergy*centerofmassEnergy))+
00209                               std::pow(centerofmassEnergy*centerofmassEnergy,1.5)/6000.0 );
00210 
00211     // PROBLEMET ER HER!!!
00212     
00213     G4double freeEnergy = centerofmassEnergy-currentMass-targetMass;
00214 
00215     if(freeEnergy<0) 
00216       {
00217         G4cout<<"Free energy < 0!"<<G4endl;
00218         G4cout<<"E_CMS = "<<centerofmassEnergy<<" GeV"<<G4endl;
00219         G4cout<<"m_curr = "<<currentMass<<" GeV"<<G4endl;
00220         G4cout<<"m_orig = "<<mOriginal<<" GeV"<<G4endl;
00221         G4cout<<"m_targ = "<<targetMass<<" GeV"<<G4endl;
00222         G4cout<<"E_free = "<<freeEnergy<<" GeV"<<G4endl;
00223       }
00224 
00225     G4double forwardEnergy = freeEnergy/2.;
00226     G4int forwardCount = 1;            // number of particles in forward hemisphere
00227     
00228     G4double backwardEnergy = freeEnergy/2.;
00229     G4int backwardCount = 1;           // number of particles in backward hemisphere
00230     if(veryForward)
00231     {
00232       if(currentParticle.GetSide()==-1)
00233       {
00234         forwardEnergy += currentMass;
00235         forwardCount --;
00236         backwardEnergy -= currentMass;
00237         backwardCount ++;
00238       }
00239       if(targetParticle.GetSide()!=-1)
00240       {
00241         backwardEnergy += targetMass;
00242         backwardCount --;
00243         forwardEnergy -= targetMass;
00244         forwardCount ++;
00245       }
00246     }
00247     for( i=0; i<vecLen; ++i )
00248     {
00249       if( vec[i]->GetSide() == -1 )
00250       {
00251         ++backwardCount;
00252         backwardEnergy -= vec[i]->GetMass()/GeV;
00253       } else {
00254         ++forwardCount;
00255         forwardEnergy -= vec[i]->GetMass()/GeV;
00256       }
00257     }
00258     //
00259     //  add particles from intranuclear cascade
00260     //  nuclearExcitationCount = number of new secondaries produced by nuclear excitation
00261     //  extraCount = number of nucleons within these new secondaries
00262     //
00263     G4double xtarg;
00264     if( centerofmassEnergy < (2.0+G4UniformRand()) )
00265       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount+vecLen+2)/2.0;
00266     else
00267       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount);
00268     if( xtarg <= 0.0 )xtarg = 0.01;
00269     G4int nuclearExcitationCount = Poisson( xtarg );
00270     if(atomicWeight<1.0001) nuclearExcitationCount = 0;
00271     G4int extraNucleonCount = 0;
00272     G4double extraNucleonMass = 0.0;
00273     if( nuclearExcitationCount > 0 )
00274     {
00275       const G4double nucsup[] = { 1.00, 0.7, 0.5, 0.4, 0.35, 0.3 };
00276       const G4double psup[] = { 3., 6., 20., 50., 100., 1000. };
00277       G4int momentumBin = 0;
00278       while( (momentumBin < 6) &&
00279              (modifiedOriginal.GetTotalMomentum()/GeV > psup[momentumBin]) )
00280         ++momentumBin;
00281       momentumBin = std::min( 5, momentumBin );
00282       //
00283       //  NOTE: in GENXPT, these new particles were given negative codes
00284       //        here I use  NewlyAdded = true  instead
00285       //
00286 //      G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
00287       for( i=0; i<nuclearExcitationCount; ++i )
00288       {
00289         G4ReactionProduct * pVec = new G4ReactionProduct();
00290         if( G4UniformRand() < nucsup[momentumBin] )
00291         {
00292           if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
00293             pVec->SetDefinition( aProton );
00294           else
00295             pVec->SetDefinition( aNeutron );
00296           pVec->SetSide( -2 );                // -2 means backside nucleon
00297           ++extraNucleonCount;
00298           backwardEnergy += pVec->GetMass()/GeV;
00299           extraNucleonMass += pVec->GetMass()/GeV;
00300         }
00301         else
00302         {
00303           G4double ran = G4UniformRand();
00304           if( ran < 0.3181 )
00305             pVec->SetDefinition( aPiPlus );
00306           else if( ran < 0.6819 )
00307             pVec->SetDefinition( aPiZero );
00308           else
00309             pVec->SetDefinition( aPiMinus );
00310           pVec->SetSide( -1 );                // backside particle, but not a nucleon
00311         }
00312         pVec->SetNewlyAdded( true );                // true is the same as IPA(i)<0
00313         vec.SetElement( vecLen++, pVec );    
00314         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00315         backwardEnergy -= pVec->GetMass()/GeV;
00316         ++backwardCount;
00317       }
00318     }
00319     //
00320     //  assume conservation of kinetic energy in forward & backward hemispheres
00321     //
00322     G4int is, iskip;
00323     while( forwardEnergy <= 0.0 )  // must eliminate a particle from the forward side
00324     {
00325       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00326       iskip = G4int(G4UniformRand()*forwardCount) + 1; // 1 <= iskip <= forwardCount
00327       is = 0;
00328       G4int forwardParticlesLeft = 0;
00329       for( i=(vecLen-1); i>=0; --i )
00330       {
00331         if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
00332         {
00333           forwardParticlesLeft = 1;  
00334           if( ++is == iskip )
00335           { 
00336             forwardEnergy += vec[i]->GetMass()/GeV;
00337             for( G4int j=i; j<(vecLen-1); j++ )*vec[j] = *vec[j+1];    // shift up
00338             --forwardCount;
00339             G4ReactionProduct *temp = vec[vecLen-1];
00340             delete temp;
00341             if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00342             break;  // --+
00343           }         //   |
00344         }           //   |
00345       }             // break goes down to here
00346       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00347       if( forwardParticlesLeft == 0 )
00348       {
00349         forwardEnergy += currentParticle.GetMass()/GeV;
00350         currentParticle.SetDefinitionAndUpdateE( targetParticle.GetDefinition() );
00351         targetParticle.SetDefinitionAndUpdateE( vec[0]->GetDefinition() );
00352         // above two lines modified 20-oct-97: were just simple equalities
00353         --forwardCount;
00354         for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];
00355         G4ReactionProduct *temp = vec[vecLen-1];
00356         delete temp;
00357         if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00358         break;
00359       }
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             G4ReactionProduct *temp = vec[vecLen-1];
00385             delete temp;
00386             if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00387             break;
00388           }
00389         }
00390       }
00391       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00392       if( backwardParticlesLeft == 0 )
00393       {
00394         backwardEnergy += targetParticle.GetMass()/GeV;
00395         targetParticle = *vec[0];
00396         --backwardCount;
00397         for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];
00398         G4ReactionProduct *temp = vec[vecLen-1];
00399         delete temp;
00400         if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00401         break;
00402       }
00403     }
00404       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00405     //
00406     //  define initial state vectors for Lorentz transformations
00407     //  the pseudoParticles have non-standard masses, hence the "pseudo"
00408     //
00409     G4ReactionProduct pseudoParticle[10];
00410     for( i=0; i<10; ++i )pseudoParticle[i].SetZero();
00411     
00412     pseudoParticle[0].SetMass( mOriginal*GeV );
00413     pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
00414     pseudoParticle[0].SetTotalEnergy(
00415      std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
00416     
00417     pseudoParticle[1].SetMass( protonMass*MeV );        // this could be targetMass
00418     pseudoParticle[1].SetTotalEnergy( protonMass*MeV );
00419     
00420     pseudoParticle[3].SetMass( protonMass*(1+extraNucleonCount)*MeV );
00421     pseudoParticle[3].SetTotalEnergy( protonMass*(1+extraNucleonCount)*MeV );
00422     
00423     pseudoParticle[8].SetMomentum( 1.0*GeV, 0.0, 0.0 );
00424     
00425     pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
00426     pseudoParticle[3] = pseudoParticle[3] + pseudoParticle[0];
00427     
00428     pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
00429     pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
00430     
00431     G4double dndl[20];
00432     //
00433     //  main loop for 4-momentum generation
00434     //  see Pitha-report (Aachen) for a detailed description of the method
00435     //
00436     G4double aspar, pt, et, x, pp, pp1, rthnve, phinve, rmb, wgt;
00437     G4int    innerCounter, outerCounter;
00438     G4bool   eliminateThisParticle, resetEnergies, constantCrossSection;
00439     
00440     G4double forwardKinetic = 0.0, backwardKinetic = 0.0;
00441     //
00442     // process the secondary particles in reverse order
00443     // the incident particle is Done after the secondaries
00444     // nucleons, including the target, in the backward hemisphere are also Done later
00445     //
00446     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,
00447                          1.43,1.67,2.0,2.5,3.33,5.00,10.00};
00448     G4int backwardNucleonCount = 0;       // number of nucleons in backward hemisphere
00449     G4double totalEnergy, kineticEnergy, vecMass;
00450 
00451     for( i=(vecLen-1); i>=0; --i )
00452     {
00453       G4double phi = G4UniformRand()*twopi;
00454       if( vec[i]->GetNewlyAdded() )           // added from intranuclear cascade
00455       {
00456         if( vec[i]->GetSide() == -2 )         //  is a nucleon
00457         {
00458           if( backwardNucleonCount < 18 )
00459           {
00460             if( vec[i]->GetDefinition() == G4PionMinus::PionMinus() ||
00461                 vec[i]->GetDefinition() == G4PionPlus::PionPlus() ||
00462                 vec[i]->GetDefinition() == G4PionZero::PionZero() )
00463             {
00464               for(G4int i=0; i<vecLen; i++) delete vec[i];
00465               vecLen = 0;
00466               throw G4HadReentrentException(__FILE__, __LINE__,
00467               "FullModelReactionDynamics::GenerateXandPt : a pion has been counted as a backward nucleon");
00468             }
00469             vec[i]->SetSide( -3 );
00470             ++backwardNucleonCount;
00471             continue;
00472           }
00473         }
00474       }
00475       //
00476       //  set pt and phi values, they are changed somewhat in the iteration loop
00477       //  set mass parameter for lambda fragmentation model
00478       //
00479       vecMass = vec[i]->GetMass()/GeV;
00480       G4double ran = -std::log(1.0-G4UniformRand())/3.5;
00481       if( vec[i]->GetSide() == -2 )   // backward nucleon
00482       {
00483         if( vec[i]->GetDefinition() == aKaonMinus ||
00484             vec[i]->GetDefinition() == aKaonZeroL ||
00485             vec[i]->GetDefinition() == aKaonZeroS ||
00486             vec[i]->GetDefinition() == aKaonPlus ||
00487             vec[i]->GetDefinition() == aPiMinus ||
00488             vec[i]->GetDefinition() == aPiZero ||
00489             vec[i]->GetDefinition() == aPiPlus )
00490         {
00491           aspar = 0.75;
00492           pt = std::sqrt( std::pow( ran, 1.7 ) );
00493         } else {                          // vec[i] must be a proton, neutron,
00494           aspar = 0.20;                   //  lambda, sigma, xsi, or ion
00495           pt = std::sqrt( std::pow( ran, 1.2 ) );
00496         }
00497       } else {                          // not a backward nucleon
00498         if( vec[i]->GetDefinition() == aPiMinus ||
00499             vec[i]->GetDefinition() == aPiZero ||
00500             vec[i]->GetDefinition() == aPiPlus )
00501         {
00502           aspar = 0.75;
00503           pt = std::sqrt( std::pow( ran, 1.7 ) );
00504         } else if( vec[i]->GetDefinition() == aKaonMinus ||
00505                    vec[i]->GetDefinition() == aKaonZeroL ||
00506                    vec[i]->GetDefinition() == aKaonZeroS ||
00507                    vec[i]->GetDefinition() == aKaonPlus )
00508         {
00509           aspar = 0.70;
00510           pt = std::sqrt( std::pow( ran, 1.7 ) );
00511         } else {                        // vec[i] must be a proton, neutron, 
00512           aspar = 0.65;                 //  lambda, sigma, xsi, or ion
00513           pt = std::sqrt( std::pow( ran, 1.5 ) );
00514         }
00515       }
00516       pt = std::max( 0.001, pt );
00517       vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00518       for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
00519       if( vec[i]->GetSide() > 0 )
00520         et = pseudoParticle[0].GetTotalEnergy()/GeV;
00521       else
00522         et = pseudoParticle[1].GetTotalEnergy()/GeV;
00523       dndl[0] = 0.0;
00524       //
00525       //   start of outer iteration loop
00526       //
00527       outerCounter = 0;
00528       eliminateThisParticle = true;
00529       resetEnergies = true;
00530       while( ++outerCounter < 3 )
00531       {
00532         for( l=1; l<20; ++l )
00533         {
00534           x = (binl[l]+binl[l-1])/2.;
00535           pt = std::max( 0.001, pt );
00536           if( x > 1.0/pt )
00537             dndl[l] += dndl[l-1];   //  changed from just  =  on 02 April 98
00538           else
00539             dndl[l] = et * aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) )
00540               * (binl[l]-binl[l-1]) / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass )
00541               + dndl[l-1];
00542         }
00543         innerCounter = 0;
00544         vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00545         //
00546         //   start of inner iteration loop
00547         //
00548         while( ++innerCounter < 7 )
00549         {
00550           ran = G4UniformRand()*dndl[19];
00551           l = 1;
00552           while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
00553           l = std::min( 19, l );
00554           x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
00555           if( vec[i]->GetSide() < 0 )x *= -1.;
00556           vec[i]->SetMomentum( x*et*GeV );              // set the z-momentum
00557           totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
00558           vec[i]->SetTotalEnergy( totalEnergy*GeV );
00559           kineticEnergy = vec[i]->GetKineticEnergy()/GeV;
00560           if( vec[i]->GetSide() > 0 )                            // forward side
00561           {
00562             if( (forwardKinetic+kineticEnergy) < 0.95*forwardEnergy )
00563             {
00564               pseudoParticle[4] = pseudoParticle[4] + (*vec[i]);
00565               forwardKinetic += kineticEnergy;
00566               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00567               pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
00568               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00569               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00570               phi += pi + normal()*pi/12.0;
00571               if( phi > twopi )phi -= twopi;
00572               if( phi < 0.0 )phi = twopi - phi;
00573               outerCounter = 2;                     // leave outer loop
00574               eliminateThisParticle = false;        // don't eliminate this particle
00575               resetEnergies = false;
00576               break;                                // leave inner loop
00577             }
00578             if( innerCounter > 5 )break;           // leave inner loop
00579             if( backwardEnergy >= vecMass )  // switch sides
00580             {
00581               vec[i]->SetSide( -1 );
00582               forwardEnergy += vecMass;
00583               backwardEnergy -= vecMass;
00584               ++backwardCount;
00585             }
00586           } else {                                                 // backward side
00587            if( extraNucleonCount > 19 )   // commented out to duplicate ?bug? in GENXPT
00588              x = 0.999;
00589            G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
00590            if( (backwardKinetic+kineticEnergy) < xxx*backwardEnergy )
00591             {
00592               pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
00593               backwardKinetic += kineticEnergy;
00594               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00595               pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
00596               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00597               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00598               phi += pi + normal() * pi / 12.0;
00599               if( phi > twopi )phi -= twopi;
00600               if( phi < 0.0 )phi = twopi - phi;
00601               outerCounter = 2;                    // leave outer loop
00602               eliminateThisParticle = false;       // don't eliminate this particle
00603               resetEnergies = false;
00604               break;                               // leave inner loop
00605             }
00606             if( innerCounter > 5 )break;           // leave inner loop
00607             if( forwardEnergy >= vecMass )  // switch sides
00608             {
00609               vec[i]->SetSide( 1 );
00610               forwardEnergy -= vecMass;
00611               backwardEnergy += vecMass;
00612               backwardCount--;
00613             }
00614           }
00615           G4ThreeVector momentum = vec[i]->GetMomentum();
00616           vec[i]->SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
00617           pt *= 0.9;
00618           dndl[19] *= 0.9;
00619         }                       // closes inner loop
00620         if( resetEnergies )
00621         {
00622           //   if we get to here, the inner loop has been Done 6 Times
00623           //   reset the kinetic energies of previously Done particles, if they are lighter
00624           //    than protons and in the forward hemisphere
00625           //   then continue with outer loop
00626           //
00627           forwardKinetic = 0.0;
00628           backwardKinetic = 0.0;
00629           pseudoParticle[4].SetZero();
00630           pseudoParticle[5].SetZero();
00631           for( l=i+1; l<vecLen; ++l )
00632           {
00633             if( vec[l]->GetSide() > 0 ||
00634                 vec[l]->GetDefinition() == aKaonMinus ||
00635                 vec[l]->GetDefinition() == aKaonZeroL ||
00636                 vec[l]->GetDefinition() == aKaonZeroS ||
00637                 vec[l]->GetDefinition() == aKaonPlus ||
00638                 vec[l]->GetDefinition() == aPiMinus ||
00639                 vec[l]->GetDefinition() == aPiZero ||
00640                 vec[l]->GetDefinition() == aPiPlus )
00641             {
00642               G4double tempMass = vec[l]->GetMass()/MeV;
00643               totalEnergy = 0.95*vec[l]->GetTotalEnergy()/MeV + 0.05*tempMass;
00644               totalEnergy = std::max( tempMass, totalEnergy );
00645               vec[l]->SetTotalEnergy( totalEnergy*MeV );
00646               pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) );
00647               pp1 = vec[l]->GetMomentum().mag()/MeV;
00648               if( pp1 < 1.0e-6*GeV )
00649               {
00650                 G4double rthnve = pi*G4UniformRand();
00651                 G4double phinve = twopi*G4UniformRand();
00652                 G4double srth = std::sin(rthnve);
00653                 vec[l]->SetMomentum( pp*srth*std::cos(phinve)*MeV,
00654                                      pp*srth*std::sin(phinve)*MeV,
00655                                      pp*std::cos(rthnve)*MeV ) ;
00656               } else {
00657                 vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
00658               }
00659               G4double px = vec[l]->GetMomentum().x()/MeV;
00660               G4double py = vec[l]->GetMomentum().y()/MeV;
00661               pt = std::max( 1.0, std::sqrt( px*px + py*py ) )/GeV;
00662               if( vec[l]->GetSide() > 0 )
00663               {
00664                 forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00665                 pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
00666               } else {
00667                 backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00668                 pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
00669               }
00670             }
00671           }
00672         }
00673       }    // closes outer loop
00674               
00675       if( eliminateThisParticle && vec[i]->GetMayBeKilled())  // not enough energy, eliminate this particle
00676       {
00677         if( vec[i]->GetSide() > 0 )
00678         {
00679           --forwardCount;
00680           forwardEnergy += vecMass;
00681         } else {
00682           if( vec[i]->GetSide() == -2 )
00683           {
00684             --extraNucleonCount;
00685             extraNucleonMass -= vecMass;
00686             backwardEnergy -= vecMass;
00687           }
00688           --backwardCount;
00689           backwardEnergy += vecMass;
00690         }
00691         for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
00692         G4ReactionProduct *temp = vec[vecLen-1];
00693         delete temp;
00694         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
00695         if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
00696         pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00697         pseudoParticle[6].SetMomentum( 0.0 );                 // set z-momentum
00698         phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00699         if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00700         phi += pi + normal() * pi / 12.0;
00701         if( phi > twopi )phi -= twopi;
00702         if( phi < 0.0 )phi = twopi - phi;
00703       }
00704     }   // closes main for loop
00705 
00706     //
00707     //  for the incident particle:  it was placed in the forward hemisphere
00708     //   set pt and phi values, they are changed somewhat in the iteration loop
00709     //   set mass parameter for lambda fragmentation model
00710     //
00711     G4double phi = G4UniformRand()*twopi;
00712     G4double ran = -std::log(1.0-G4UniformRand());
00713     if( currentParticle.GetDefinition() == aPiMinus ||
00714         currentParticle.GetDefinition() == aPiZero ||
00715         currentParticle.GetDefinition() == aPiPlus )
00716     {
00717       aspar = 0.60;
00718       pt = std::sqrt( std::pow( ran/6.0, 1.7 ) );
00719     } else if( currentParticle.GetDefinition() == aKaonMinus ||
00720                currentParticle.GetDefinition() == aKaonZeroL ||
00721                currentParticle.GetDefinition() == aKaonZeroS ||
00722                currentParticle.GetDefinition() == aKaonPlus )
00723     {
00724       aspar = 0.50;
00725       pt = std::sqrt( std::pow( ran/5.0, 1.4 ) );
00726     } else {
00727       aspar = 0.40;
00728       pt = std::sqrt( std::pow( ran/4.0, 1.2 ) );
00729     }
00730     for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
00731     currentParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00732     et = pseudoParticle[0].GetTotalEnergy()/GeV;
00733     dndl[0] = 0.0;
00734     vecMass = currentParticle.GetMass()/GeV;
00735     for( l=1; l<20; ++l )
00736     {
00737       x = (binl[l]+binl[l-1])/2.;
00738       if( x > 1.0/pt )
00739         dndl[l] += dndl[l-1];   //  changed from just  =   on 02 April 98
00740       else
00741         dndl[l] = aspar/std::sqrt( std::pow((1.+sqr(aspar*x)),3) ) *
00742           (binl[l]-binl[l-1]) * et / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass ) +
00743           dndl[l-1];
00744     }
00745     ran = G4UniformRand()*dndl[19];
00746     l = 1;
00747     while( (ran>dndl[l]) && (l<20) )l++;
00748     l = std::min( 19, l );
00749     x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );   
00750     currentParticle.SetMomentum( x*et*GeV );                 // set the z-momentum
00751     if( forwardEnergy < forwardKinetic )
00752       totalEnergy = vecMass + 0.04*std::fabs(normal());
00753     else
00754       totalEnergy = vecMass + forwardEnergy - forwardKinetic;
00755     currentParticle.SetTotalEnergy( totalEnergy*GeV );
00756     pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00757     pp1 = currentParticle.GetMomentum().mag()/MeV;
00758     if( pp1 < 1.0e-6*GeV )
00759     {
00760       G4double rthnve = pi*G4UniformRand();
00761       G4double phinve = twopi*G4UniformRand();
00762       G4double srth = std::sin(rthnve);
00763       currentParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
00764                                    pp*srth*std::sin(phinve)*MeV,
00765                                    pp*std::cos(rthnve)*MeV );
00766     } else {
00767       currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
00768     }
00769     pseudoParticle[4] = pseudoParticle[4] + currentParticle;
00770     //
00771     // this finishes the current particle
00772     // now for the target particle
00773     //
00774     if( backwardNucleonCount < 18 )
00775     {
00776       targetParticle.SetSide( -3 );
00777       ++backwardNucleonCount;
00778     }
00779     else
00780     {
00781       //  set pt and phi values, they are changed somewhat in the iteration loop
00782       //  set mass parameter for lambda fragmentation model
00783       //
00784       vecMass = targetParticle.GetMass()/GeV;
00785       ran = -std::log(1.0-G4UniformRand());
00786       aspar = 0.40;
00787       pt = std::max( 0.001, std::sqrt( std::pow( ran/4.0, 1.2 ) ) );
00788       targetParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
00789       for( G4int j=0; j<20; ++j )binl[j] = (j-1.)/(19.*pt);
00790       et = pseudoParticle[1].GetTotalEnergy()/GeV;
00791       dndl[0] = 0.0;
00792       outerCounter = 0;
00793       eliminateThisParticle = true;     // should never eliminate the target particle
00794       resetEnergies = true;
00795       while( ++outerCounter < 3 )     // start of outer iteration loop
00796       {
00797         for( l=1; l<20; ++l )
00798         {
00799           x = (binl[l]+binl[l-1])/2.;
00800           if( x > 1.0/pt )
00801             dndl[l] += dndl[l-1];   // changed from just  =  on 02 April 98
00802           else
00803             dndl[l] = aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) ) *
00804               (binl[l]-binl[l-1])*et / std::sqrt( pt*x*et*pt*x*et+pt*pt+vecMass*vecMass ) +
00805               dndl[l-1];
00806         }
00807         innerCounter = 0;
00808         while( ++innerCounter < 7 )    // start of inner iteration loop
00809         {
00810           l = 1;
00811           ran = G4UniformRand()*dndl[19];
00812           while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
00813           l = std::min( 19, l );
00814           x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
00815           if( targetParticle.GetSide() < 0 )x *= -1.;
00816           targetParticle.SetMomentum( x*et*GeV );                // set the z-momentum
00817           totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
00818           targetParticle.SetTotalEnergy( totalEnergy*GeV );
00819           if( targetParticle.GetSide() < 0 )
00820           {
00821             if( extraNucleonCount > 19 )x=0.999;
00822             G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
00823             if( (backwardKinetic+totalEnergy-vecMass) < xxx*backwardEnergy )
00824             {
00825               pseudoParticle[5] = pseudoParticle[5] + targetParticle;
00826               backwardKinetic += totalEnergy - vecMass;
00827               pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
00828               pseudoParticle[6].SetMomentum( 0.0 );                      // set z-momentum
00829               phi = pseudoParticle[6].Angle( pseudoParticle[8] );
00830               if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
00831               phi += pi + normal() * pi / 12.0;
00832               if( phi > twopi )phi -= twopi;
00833               if( phi < 0.0 )phi = twopi - phi;
00834               outerCounter = 2;                    // leave outer loop
00835               eliminateThisParticle = false;       // don't eliminate this particle
00836               resetEnergies = false;
00837               break;                               // leave inner loop
00838             }
00839             if( innerCounter > 5 )break;           // leave inner loop
00840             if( forwardEnergy >= vecMass )  // switch sides
00841             {
00842               targetParticle.SetSide( 1 );
00843               forwardEnergy -= vecMass;
00844               backwardEnergy += vecMass;
00845               --backwardCount;
00846             }
00847             G4ThreeVector momentum = targetParticle.GetMomentum();
00848             targetParticle.SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
00849             pt *= 0.9;
00850             dndl[19] *= 0.9;
00851           }
00852           else                    // target has gone to forward side
00853           {
00854             if( forwardEnergy < forwardKinetic )
00855               totalEnergy = vecMass + 0.04*std::fabs(normal());
00856             else
00857               totalEnergy = vecMass + forwardEnergy - forwardKinetic;
00858             targetParticle.SetTotalEnergy( totalEnergy*GeV );
00859             pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00860             pp1 = targetParticle.GetMomentum().mag()/MeV;
00861             if( pp1 < 1.0e-6*GeV )
00862             {
00863               G4double rthnve = pi*G4UniformRand();
00864               G4double phinve = twopi*G4UniformRand();
00865               G4double srth = std::sin(rthnve);
00866               targetParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
00867                                           pp*srth*std::sin(phinve)*MeV,
00868                                           pp*std::cos(rthnve)*MeV );
00869             }
00870             else
00871               targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
00872 
00873             pseudoParticle[4] = pseudoParticle[4] + targetParticle;
00874             outerCounter = 2;                    // leave outer loop
00875             eliminateThisParticle = false;       // don't eliminate this particle
00876             resetEnergies = false;
00877             break;                               // leave inner loop
00878           }
00879         }    // closes inner loop
00880         if( resetEnergies )
00881         {
00882           //   if we get to here, the inner loop has been Done 6 Times
00883           //   reset the kinetic energies of previously Done particles, if they are lighter
00884           //    than protons and in the forward hemisphere
00885           //   then continue with outer loop
00886           
00887           forwardKinetic = backwardKinetic = 0.0;
00888           pseudoParticle[4].SetZero();
00889           pseudoParticle[5].SetZero();
00890           for( l=0; l<vecLen; ++l ) // changed from l=1  on 02 April 98
00891           {
00892             if( vec[l]->GetSide() > 0 ||
00893                 vec[l]->GetDefinition() == aKaonMinus ||
00894                 vec[l]->GetDefinition() == aKaonZeroL ||
00895                 vec[l]->GetDefinition() == aKaonZeroS ||
00896                 vec[l]->GetDefinition() == aKaonPlus ||
00897                 vec[l]->GetDefinition() == aPiMinus ||
00898                 vec[l]->GetDefinition() == aPiZero ||
00899                 vec[l]->GetDefinition() == aPiPlus )
00900             {
00901               G4double tempMass = vec[l]->GetMass()/GeV;
00902               totalEnergy =
00903                 std::max( tempMass, 0.95*vec[l]->GetTotalEnergy()/GeV + 0.05*tempMass );
00904               vec[l]->SetTotalEnergy( totalEnergy*GeV );
00905               pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) )*GeV;
00906               pp1 = vec[l]->GetMomentum().mag()/MeV;
00907               if( pp1 < 1.0e-6*GeV )
00908               {
00909                 G4double rthnve = pi*G4UniformRand();
00910                 G4double phinve = twopi*G4UniformRand();
00911                 G4double srth = std::sin(rthnve);
00912                 vec[l]->SetMomentum( pp*srth*std::cos(phinve)*MeV,
00913                                      pp*srth*std::sin(phinve)*MeV,
00914                                      pp*std::cos(rthnve)*MeV );
00915               }
00916               else
00917                 vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
00918 
00919               pt = std::max( 0.001*GeV, std::sqrt( sqr(vec[l]->GetMomentum().x()/MeV) +
00920                                          sqr(vec[l]->GetMomentum().y()/MeV) ) )/GeV;
00921               if( vec[l]->GetSide() > 0)
00922               {
00923                 forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00924                 pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
00925               } else {
00926                 backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
00927                 pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
00928               }
00929             }
00930           }
00931         }
00932       }    // closes outer loop
00933 //      if( eliminateThisParticle )  // not enough energy, eliminate target
00934 //      {
00935 //        G4cerr << "Warning: eliminating target particle" << G4endl;
00936 //        exit( EXIT_FAILURE );
00937 //      }
00938     }
00939     //
00940     //  this finishes the target particle
00941     // backward nucleons produced with a cluster model
00942     //
00943     pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
00944     pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
00945     pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
00946     if( backwardNucleonCount == 1 )  // target particle is the only backward nucleon
00947     {
00948       G4double ekin =
00949         std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
00950       if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
00951       vecMass = targetParticle.GetMass()/GeV;
00952       totalEnergy = ekin+vecMass;
00953       targetParticle.SetTotalEnergy( totalEnergy*GeV );
00954       pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00955       pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
00956       if( pp1 < 1.0e-6*GeV )
00957       { 
00958         rthnve = pi*G4UniformRand();
00959         phinve = twopi*G4UniformRand();
00960         G4double srth = std::sin(rthnve);
00961         targetParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
00962                                     pp*srth*std::sin(phinve)*MeV,
00963                                     pp*std::cos(rthnve)*MeV );
00964       } else {
00965         targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
00966       }
00967       pseudoParticle[5] = pseudoParticle[5] + targetParticle;
00968     }
00969     else  // more than one backward nucleon
00970     {
00971       const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
00972       const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
00973       // Replaced the following min function to get correct behaviour on DEC.
00974       // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
00975       G4int tempCount;
00976       if (backwardNucleonCount < 5)
00977         {
00978           tempCount = backwardNucleonCount;
00979         }
00980       else
00981         {
00982           tempCount = 5;
00983         }
00984       tempCount--;
00985       //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
00986       //cout << "tempCount " << tempCount << G4endl;
00987       G4double rmb0 = 0.0;
00988       if( targetParticle.GetSide() == -3 )
00989         rmb0 += targetParticle.GetMass()/GeV;
00990       for( i=0; i<vecLen; ++i )
00991       {
00992         if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
00993       }
00994       rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
00995       totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
00996       vecMass = std::min( rmb, totalEnergy );
00997       pseudoParticle[6].SetMass( vecMass*GeV );
00998       pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
00999       pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
01000       if( pp1 < 1.0e-6*GeV )
01001       {
01002         rthnve = pi * G4UniformRand();
01003         phinve = twopi * G4UniformRand();
01004         G4double srth = std::sin(rthnve);
01005         pseudoParticle[6].SetMomentum( -pp*srth*std::cos(phinve)*MeV,
01006                                        -pp*srth*std::sin(phinve)*MeV,
01007                                        -pp*std::cos(rthnve)*MeV );
01008       }
01009       else
01010         pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
01011       
01012       G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;  // tempV contains the backward nucleons
01013       tempV.Initialize( backwardNucleonCount );
01014       G4int tempLen = 0;
01015       if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
01016       for( i=0; i<vecLen; ++i )
01017       {
01018         if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
01019       }
01020       if( tempLen != backwardNucleonCount )
01021       {
01022         G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
01023         G4cerr << "tempLen = " << tempLen;
01024         G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
01025         G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
01026         G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
01027         for( i=0; i<vecLen; ++i )
01028           G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
01029         exit( EXIT_FAILURE );
01030       }
01031       constantCrossSection = true;
01032       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01033       if( tempLen >= 2 )
01034       {
01035         wgt = GenerateNBodyEvent(
01036          pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
01037          // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01038         if( targetParticle.GetSide() == -3 )
01039         {
01040           targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
01041           // tempV contains the real stuff
01042           pseudoParticle[5] = pseudoParticle[5] + targetParticle;
01043         }
01044         for( i=0; i<vecLen; ++i )
01045         {
01046           if( vec[i]->GetSide() == -3 )
01047           {
01048             vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
01049             pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
01050           }
01051         }
01052       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01053       }
01054     }
01055     //
01056     //  Lorentz transformation in lab system
01057     //
01058     if( vecLen == 0 )return false;  // all the secondaries have been eliminated
01059       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01060     
01061     G4int numberofFinalStateNucleons = 0;
01062     if( currentParticle.GetDefinition() ==aProton ||
01063         currentParticle.GetDefinition() == aNeutron ||
01064         currentParticle.GetDefinition() == G4SigmaMinus::SigmaMinus()||
01065         currentParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
01066         currentParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
01067         currentParticle.GetDefinition() == G4XiZero::XiZero()||
01068         currentParticle.GetDefinition() == G4XiMinus::XiMinus()||
01069         currentParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
01070         currentParticle.GetDefinition() == G4Lambda::Lambda()) ++numberofFinalStateNucleons;
01071     currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
01072     
01073     if( targetParticle.GetDefinition() ==aProton ||
01074         targetParticle.GetDefinition() == aNeutron ||
01075         targetParticle.GetDefinition() == G4Lambda::Lambda() ||
01076         targetParticle.GetDefinition() == G4XiZero::XiZero()||
01077         targetParticle.GetDefinition() == G4XiMinus::XiMinus()||
01078         targetParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
01079         targetParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
01080         targetParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
01081         targetParticle.GetDefinition() == G4SigmaMinus::SigmaMinus()) ++numberofFinalStateNucleons;
01082     if( targetParticle.GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
01083     if( targetParticle.GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
01084     if( targetParticle.GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
01085     if( targetParticle.GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
01086     if( targetParticle.GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
01087     if( targetParticle.GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
01088     if( targetParticle.GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
01089     if( targetParticle.GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
01090     if( targetParticle.GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
01091     targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
01092     
01093     for( i=0; i<vecLen; ++i )
01094     {
01095       if( vec[i]->GetDefinition() ==aProton ||
01096           vec[i]->GetDefinition() == aNeutron ||
01097           vec[i]->GetDefinition() == G4Lambda::Lambda() ||
01098           vec[i]->GetDefinition() == G4XiZero::XiZero() ||
01099           vec[i]->GetDefinition() == G4XiMinus::XiMinus() ||
01100           vec[i]->GetDefinition() == G4OmegaMinus::OmegaMinus() ||
01101           vec[i]->GetDefinition() == G4SigmaPlus::SigmaPlus()||
01102           vec[i]->GetDefinition() == G4SigmaZero::SigmaZero()||
01103           vec[i]->GetDefinition() == G4SigmaMinus::SigmaMinus()) ++numberofFinalStateNucleons;
01104       if( vec[i]->GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
01105       if( vec[i]->GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
01106       if( vec[i]->GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
01107       if( vec[i]->GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
01108       if( vec[i]->GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
01109       if( vec[i]->GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
01110       if( vec[i]->GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
01111       if( vec[i]->GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
01112       if( vec[i]->GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
01113      vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
01114     }
01115       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01116     if(veryForward) numberofFinalStateNucleons++;
01117     numberofFinalStateNucleons = std::max( 1, numberofFinalStateNucleons );
01118     //
01119     // leadFlag will be true
01120     //  iff original particle is at least as heavy as K+ and not a proton or neutron AND
01121     //   if
01122     //    incident particle is at least as heavy as K+ and it is not a proton or neutron
01123     //     leadFlag is set to the incident particle
01124     //   or
01125     //    target particle is at least as heavy as K+ and it is not a proton or neutron
01126     //     leadFlag is set to the target particle
01127     //
01128     G4bool leadingStrangeParticleHasChanged = true;
01129     if( leadFlag )
01130     {
01131       if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
01132         leadingStrangeParticleHasChanged = false;
01133       if( leadingStrangeParticleHasChanged &&
01134           ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
01135         leadingStrangeParticleHasChanged = false;
01136       if( leadingStrangeParticleHasChanged )
01137       {
01138         for( i=0; i<vecLen; i++ )
01139         {
01140           if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
01141           {
01142             leadingStrangeParticleHasChanged = false;
01143             break;
01144           }
01145         }
01146       }
01147       if( leadingStrangeParticleHasChanged )
01148       {
01149         G4bool leadTest = 
01150           (leadingStrangeParticle.GetDefinition() == aKaonMinus ||
01151            leadingStrangeParticle.GetDefinition() == aKaonZeroL ||
01152            leadingStrangeParticle.GetDefinition() == aKaonZeroS ||
01153            leadingStrangeParticle.GetDefinition() == aKaonPlus ||
01154            leadingStrangeParticle.GetDefinition() == aPiMinus ||
01155            leadingStrangeParticle.GetDefinition() == aPiZero ||
01156            leadingStrangeParticle.GetDefinition() == aPiPlus);
01157         G4bool targetTest = false;
01158         /*          (targetParticle.GetDefinition() == aKaonMinus ||
01159            targetParticle.GetDefinition() == aKaonZeroL ||
01160            targetParticle.GetDefinition() == aKaonZeroS ||
01161            targetParticle.GetDefinition() == aKaonPlus ||
01162            targetParticle.GetDefinition() == aPiMinus ||
01163            targetParticle.GetDefinition() == aPiZero ||
01164            targetParticle.GetDefinition() == aPiPlus);
01165         */
01166         // following modified by JLC 22-Oct-97
01167           
01168         if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
01169         {
01170           targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
01171           targetHasChanged = true;
01172       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01173         }
01174         else
01175         {
01176           currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
01177           incidentHasChanged = false;
01178       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01179         }
01180       }
01181     }   // end of if( leadFlag )
01182     
01183     pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
01184     pseudoParticle[3].SetMass( mOriginal*GeV );
01185     pseudoParticle[3].SetTotalEnergy(
01186      std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
01187     
01188 //    G4double ekin0 = pseudoParticle[3].GetKineticEnergy()/GeV;
01189     
01190     G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
01191     G4int diff = 0;
01192     if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
01193     if(numberofFinalStateNucleons == 1) diff = 0;
01194     pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
01195     pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
01196     pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
01197     
01198     G4double theoreticalKinetic =
01199       pseudoParticle[3].GetTotalEnergy()/MeV +
01200       pseudoParticle[4].GetTotalEnergy()/MeV -
01201       currentParticle.GetMass()/MeV -
01202       targetParticle.GetMass()/MeV;
01203     
01204     G4double simulatedKinetic =
01205       currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
01206     
01207     pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
01208     pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
01209     pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
01210     
01211     pseudoParticle[7].SetZero();
01212     pseudoParticle[7] = pseudoParticle[7] + currentParticle;
01213     pseudoParticle[7] = pseudoParticle[7] + targetParticle;
01214 
01215     for( i=0; i<vecLen; ++i )
01216     {
01217       pseudoParticle[7] = pseudoParticle[7] + *vec[i];
01218       simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
01219       theoreticalKinetic -= vec[i]->GetMass()/MeV;
01220     }
01221     if( vecLen <= 16 && vecLen > 0 )
01222     {
01223       // must create a new set of ReactionProducts here because GenerateNBody will
01224       // modify the momenta for the particles, and we don't want to do this
01225       //
01226       G4ReactionProduct tempR[130];
01227       //G4ReactionProduct *tempR = new G4ReactionProduct [vecLen+2];
01228       tempR[0] = currentParticle;
01229       tempR[1] = targetParticle;
01230       for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
01231       G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
01232       tempV.Initialize( vecLen+2 );
01233       G4int tempLen = 0;
01234       for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
01235       constantCrossSection = true;
01236 
01237       wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
01238                                 pseudoParticle[4].GetTotalEnergy()/MeV,
01239        constantCrossSection, tempV, tempLen );
01240       if(wgt>-.5)
01241       {
01242         theoreticalKinetic = 0.0;
01243         for( i=0; i<tempLen; ++i )
01244         {
01245           pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
01246           theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
01247         }
01248       }
01249       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01250       //delete [] tempR;
01251     }
01252     //
01253     //  Make sure, that the kinetic energies are correct
01254     //
01255     if( simulatedKinetic != 0.0 )
01256     {
01257       wgt = (theoreticalKinetic)/simulatedKinetic;
01258       theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
01259       simulatedKinetic = theoreticalKinetic;
01260       currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
01261       pp = currentParticle.GetTotalMomentum()/MeV;
01262       pp1 = currentParticle.GetMomentum().mag()/MeV;
01263       if( pp1 < 1.0e-6*GeV )
01264       {
01265         rthnve = pi*G4UniformRand();
01266         phinve = twopi*G4UniformRand();
01267         currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
01268                                      pp*std::sin(rthnve)*std::sin(phinve)*MeV,
01269                                      pp*std::cos(rthnve)*MeV );
01270       }
01271       else
01272       {
01273         currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
01274       }
01275       theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
01276       targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
01277       simulatedKinetic += theoreticalKinetic;
01278       pp = targetParticle.GetTotalMomentum()/MeV;
01279       pp1 = targetParticle.GetMomentum().mag()/MeV;
01280       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01281       if( pp1 < 1.0e-6*GeV )
01282       {
01283         rthnve = pi*G4UniformRand();
01284         phinve = twopi*G4UniformRand();
01285         targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
01286                                     pp*std::sin(rthnve)*std::sin(phinve)*MeV,
01287                                     pp*std::cos(rthnve)*MeV );
01288       } else {
01289         targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
01290       }
01291       for( i=0; i<vecLen; ++i )
01292       {
01293         theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
01294         simulatedKinetic += theoreticalKinetic;
01295         vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
01296         pp = vec[i]->GetTotalMomentum()/MeV;
01297         pp1 = vec[i]->GetMomentum().mag()/MeV;
01298         if( pp1 < 1.0e-6*GeV )
01299         {
01300           rthnve = pi*G4UniformRand();
01301           phinve = twopi*G4UniformRand();
01302           vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
01303                                pp*std::sin(rthnve)*std::sin(phinve)*MeV,
01304                                pp*std::cos(rthnve)*MeV );
01305         }
01306         else
01307           vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
01308       }
01309     }
01310       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01311     Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
01312             modifiedOriginal, originalIncident, targetNucleus,
01313             currentParticle, targetParticle, vec, vecLen );
01314       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01315     //
01316     // add black track particles
01317     // the total number of particles produced is restricted to 198
01318     // this may have influence on very high energies
01319     //
01320     if( atomicWeight >= 1.5 )
01321     {
01322       // npnb is number of proton/neutron black track particles
01323       // ndta is the number of deuterons, tritons, and alphas produced
01324       // epnb is the kinetic energy available for proton/neutron black track particles
01325       // edta is the kinetic energy available for deuteron/triton/alpha particles
01326       //
01327       G4double epnb, edta;
01328       G4int npnb = 0;
01329       G4int ndta = 0;
01330       
01331       epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
01332       edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
01333       const G4double pnCutOff = 0.001;
01334       const G4double dtaCutOff = 0.001;
01335       const G4double kineticMinimum = 1.e-6;
01336       const G4double kineticFactor = -0.010;
01337       G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
01338       const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
01339       if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
01340       if( epnb >= pnCutOff )
01341       {
01342         npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
01343         if( numberofFinalStateNucleons + npnb > atomicWeight )
01344           npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
01345         npnb = std::min( npnb, 127-vecLen );
01346       }
01347       if( edta >= dtaCutOff )
01348       {
01349         ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
01350         ndta = std::min( ndta, 127-vecLen );
01351       }
01352       G4double spall = numberofFinalStateNucleons;
01353       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01354 
01355       AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
01356                              modifiedOriginal, spall, targetNucleus,
01357                               vec, vecLen );
01358 
01359 //       G4double jpw=0; 
01360 //       jpw+=GetQValue(&currentParticle);
01361 //       jpw+=GetQValue(&targetParticle);
01362 //       for( i=0; i<vecLen; ++i )jpw += GetQValue(vec[i]);
01363 //       G4cout << "JPW ### "<<jpw<<G4endl;
01364       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01365     }
01366     //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
01367     //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
01368     //
01369     //  calculate time delay for nuclear reactions
01370     //
01371     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
01372       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
01373     else
01374       currentParticle.SetTOF( 1.0 );
01375     return true;
01376       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01377   }
01378  
01379  void FullModelReactionDynamics::SuppressChargedPions(
01380    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
01381    G4int &vecLen,
01382    const G4ReactionProduct &modifiedOriginal,
01383    G4ReactionProduct &currentParticle,
01384    G4ReactionProduct &targetParticle,
01385    const G4Nucleus &targetNucleus,
01386    G4bool &incidentHasChanged,
01387    G4bool &targetHasChanged )
01388   {
01389     // this code was originally in the fortran code TWOCLU
01390     //
01391     // suppress charged pions, for various reasons
01392     //
01393     const G4double atomicWeight = targetNucleus.GetN();
01394     const G4double atomicNumber = targetNucleus.GetZ();
01395     const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
01396     
01397     // G4ParticleDefinition *aGamma = G4Gamma::Gamma();
01398     G4ParticleDefinition *aProton = G4Proton::Proton();
01399     G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
01400     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
01401     G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
01402     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
01403     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
01404     
01405     const G4bool antiTest =
01406       modifiedOriginal.GetDefinition() != anAntiProton &&
01407       modifiedOriginal.GetDefinition() != anAntiNeutron;
01408     if( antiTest && (
01409        // currentParticle.GetDefinition() == aGamma ||
01410           currentParticle.GetDefinition() == aPiPlus ||
01411           currentParticle.GetDefinition() == aPiMinus ) &&
01412         ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01413         ( G4UniformRand() <= atomicWeight/300.0 ) )
01414     {
01415       if( G4UniformRand() > atomicNumber/atomicWeight )
01416         currentParticle.SetDefinitionAndUpdateE( aNeutron );
01417       else
01418         currentParticle.SetDefinitionAndUpdateE( aProton );
01419       incidentHasChanged = true;
01420     }
01421     /*    if( antiTest && (
01422        // targetParticle.GetDefinition() == aGamma ||
01423           targetParticle.GetDefinition() == aPiPlus ||
01424           targetParticle.GetDefinition() == aPiMinus ) &&
01425         ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01426         ( G4UniformRand() <= atomicWeight/300.0 ) )
01427     {
01428       if( G4UniformRand() > atomicNumber/atomicWeight )
01429         targetParticle.SetDefinitionAndUpdateE( aNeutron );
01430       else
01431         targetParticle.SetDefinitionAndUpdateE( aProton );
01432       targetHasChanged = true;
01433       }*/
01434       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01435     for( G4int i=0; i<vecLen; ++i )
01436     {
01437       if( antiTest && (
01438          // vec[i]->GetDefinition() == aGamma ||
01439             vec[i]->GetDefinition() == aPiPlus ||
01440             vec[i]->GetDefinition() == aPiMinus ) &&
01441           ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
01442           ( G4UniformRand() <= atomicWeight/300.0 ) )
01443       {
01444         if( G4UniformRand() > atomicNumber/atomicWeight )
01445           vec[i]->SetDefinitionAndUpdateE( aNeutron );
01446         else
01447           vec[i]->SetDefinitionAndUpdateE( aProton );
01448       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01449       }
01450     }
01451       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01452   }
01453  
01454  G4bool FullModelReactionDynamics::TwoCluster(
01455    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
01456    G4int &vecLen,
01457    G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
01458    const G4HadProjectile *originalIncident, // the original incident particle
01459    G4ReactionProduct &currentParticle,
01460    G4ReactionProduct &targetParticle,
01461    const G4Nucleus &targetNucleus,
01462    G4bool &incidentHasChanged,
01463    G4bool &targetHasChanged,
01464    G4bool leadFlag,
01465    G4ReactionProduct &leadingStrangeParticle )
01466   {
01467       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01468     // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
01469     //
01470     //  Generation of X- and PT- values for incident, target, and all secondary particles 
01471     //  
01472     //  A simple two cluster model is used.
01473     //  This should be sufficient for low energy interactions.
01474     //
01475 
01476     // + debugging
01477     // raise(SIGSEGV);
01478     // - debugging
01479 
01480     G4int i;
01481     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
01482     G4ParticleDefinition *aProton = G4Proton::Proton();
01483     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
01484     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
01485     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
01486     G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
01487     const G4double protonMass = aProton->GetPDGMass()/MeV;
01488     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
01489     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
01490     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
01491     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
01492     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
01493     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
01494                                         targetMass*targetMass +
01495                                         2.0*targetMass*etOriginal );  // GeV
01496     G4double currentMass = currentParticle.GetMass()/GeV;
01497     targetMass = targetParticle.GetMass()/GeV;
01498 
01499     if( currentMass == 0.0 && targetMass == 0.0 )
01500     {
01501       G4double ek = currentParticle.GetKineticEnergy();
01502       G4ThreeVector m = currentParticle.GetMomentum();
01503       currentParticle = *vec[0];
01504       targetParticle = *vec[1];
01505       for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
01506       if(vecLen<2) 
01507       {
01508         for(G4int i=0; i<vecLen; i++) delete vec[i];
01509         vecLen = 0;
01510         throw G4HadReentrentException(__FILE__, __LINE__,
01511         "FullModelReactionDynamics::TwoCluster: Negative number of particles");
01512       }
01513       delete vec[vecLen-1];
01514       delete vec[vecLen-2];
01515       vecLen -= 2;
01516       currentMass = currentParticle.GetMass()/GeV;
01517       targetMass = targetParticle.GetMass()/GeV;
01518       incidentHasChanged = true;
01519       targetHasChanged = true;
01520       currentParticle.SetKineticEnergy( ek );
01521       currentParticle.SetMomentum( m );
01522     }
01523     const G4double atomicWeight = targetNucleus.GetN();
01524     const G4double atomicNumber = targetNucleus.GetZ();
01525     //
01526     // particles have been distributed in forward and backward hemispheres
01527     // in center of mass system of the hadron nucleon interaction
01528     //
01529     // incident is always in forward hemisphere
01530     G4int forwardCount = 1;            // number of particles in forward hemisphere
01531     currentParticle.SetSide( 1 );
01532     G4double forwardMass = currentParticle.GetMass()/GeV;
01533     G4double cMass = forwardMass;
01534     
01535     // target is always in backward hemisphere
01536     G4int backwardCount = 1;           // number of particles in backward hemisphere
01537     G4int backwardNucleonCount = 1;    // number of nucleons in backward hemisphere
01538     targetParticle.SetSide( -1 );
01539     G4double backwardMass = targetParticle.GetMass()/GeV;
01540     G4double bMass = backwardMass;
01541     
01542     for( i=0; i<vecLen; ++i )
01543     {
01544       if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
01545       // to take care of the case where vec has been preprocessed by GenerateXandPt
01546       // and some of them have been set to -2 or -3
01547       if( vec[i]->GetSide() == -1 )
01548       {
01549         ++backwardCount;
01550         backwardMass += vec[i]->GetMass()/GeV;
01551       }
01552       else
01553       {
01554         ++forwardCount;
01555         forwardMass += vec[i]->GetMass()/GeV;
01556       }
01557     }
01558     //
01559     // nucleons and some pions from intranuclear cascade
01560     //
01561     G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
01562     if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
01563     const G4double afc = 0.312 + 0.2 * std::log(term1);
01564     G4double xtarg;
01565     if( centerofmassEnergy < 2.0+G4UniformRand() )        // added +2 below, JLC 4Jul97
01566       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
01567     else
01568       xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
01569     if( xtarg <= 0.0 )xtarg = 0.01;
01570     G4int nuclearExcitationCount = Poisson( xtarg );
01571     if(atomicWeight<1.0001) nuclearExcitationCount = 0;
01572     G4int extraNucleonCount = 0;
01573     G4double extraMass = 0.0;
01574     G4double extraNucleonMass = 0.0;
01575     if( nuclearExcitationCount > 0 )
01576     {
01577       G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );     
01578       const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
01579       //
01580       //  NOTE: in TWOCLU, these new particles were given negative codes
01581       //        here we use  NewlyAdded = true  instead
01582       //
01583 //      G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
01584       for( i=0; i<nuclearExcitationCount; ++i )
01585       {
01586         G4ReactionProduct* pVec = new G4ReactionProduct();
01587         if( G4UniformRand() < nucsup[momentumBin] )  // add proton or neutron
01588         {
01589           if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
01590             // HPW: looks like a gheisha bug 
01591             pVec->SetDefinition( aProton );
01592           else
01593             pVec->SetDefinition( aNeutron );
01594           ++backwardNucleonCount;
01595           ++extraNucleonCount;
01596           extraNucleonMass += pVec->GetMass()/GeV;
01597         }
01598         else
01599         {                                       // add a pion
01600           G4double ran = G4UniformRand();
01601           if( ran < 0.3181 )
01602             pVec->SetDefinition( aPiPlus );
01603           else if( ran < 0.6819 )
01604             pVec->SetDefinition( aPiZero );
01605           else
01606             pVec->SetDefinition( aPiMinus );
01607         }
01608         pVec->SetSide( -2 );    // backside particle
01609         extraMass += pVec->GetMass()/GeV;
01610         pVec->SetNewlyAdded( true );
01611         vec.SetElement( vecLen++, pVec );
01612         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01613       }
01614     }
01615       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01616     G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
01617     G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
01618     G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
01619     G4bool secondaryDeleted;
01620     G4double pMass;
01621     while( eAvailable <= 0.0 )   // must eliminate a particle
01622     {
01623       secondaryDeleted = false;
01624       for( i=(vecLen-1); i>=0; --i )
01625       {
01626         if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
01627         {
01628           pMass = vec[i]->GetMass()/GeV;
01629           for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];     // shift up
01630           --forwardCount;
01631           forwardEnergy += pMass;
01632           forwardMass -= pMass;
01633           secondaryDeleted = true;
01634           break;
01635         }
01636         else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
01637         {
01638           pMass = vec[i]->GetMass()/GeV;
01639           for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01640           --backwardCount;
01641           backwardEnergy += pMass;
01642           backwardMass -= pMass;
01643           secondaryDeleted = true;
01644           break;
01645         }
01646       }           // breaks go down to here
01647       if( secondaryDeleted )
01648       {      
01649         G4ReactionProduct *temp = vec[vecLen-1];
01650         delete temp;
01651         --vecLen;
01652         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01653       }
01654       else
01655       {
01656         if( vecLen == 0 )
01657         {
01658           return false;  // all secondaries have been eliminated
01659         }
01660         if( targetParticle.GetSide() == -1 )
01661         {
01662           pMass = targetParticle.GetMass()/GeV;
01663           targetParticle = *vec[0];
01664           for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01665           --backwardCount;
01666           backwardEnergy += pMass;
01667           backwardMass -= pMass;
01668           secondaryDeleted = true;
01669         }
01670         else if( targetParticle.GetSide() == 1 )
01671         {
01672           pMass = targetParticle.GetMass()/GeV;
01673           targetParticle = *vec[0];
01674           for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01675           --forwardCount;
01676           forwardEnergy += pMass;
01677           forwardMass -= pMass;
01678           secondaryDeleted = true;
01679         }
01680         if( secondaryDeleted )
01681         {
01682           G4ReactionProduct *temp = vec[vecLen-1];
01683           delete temp;
01684           --vecLen;
01685           // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01686         }
01687         else
01688         {
01689           if( currentParticle.GetSide() == -1 )
01690           {
01691             pMass = currentParticle.GetMass()/GeV;
01692             currentParticle = *vec[0];
01693             for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01694             --backwardCount;
01695             backwardEnergy += pMass;
01696             backwardMass -= pMass;
01697             secondaryDeleted = true;
01698           }
01699           else if( currentParticle.GetSide() == 1 )
01700           {
01701             pMass = currentParticle.GetMass()/GeV;
01702             currentParticle = *vec[0];
01703             for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
01704             --forwardCount;//This line can cause infinite loop
01705             forwardEnergy += pMass;
01706             forwardMass -= pMass;
01707             secondaryDeleted = true;
01708           }
01709           if( secondaryDeleted )
01710           {
01711             G4ReactionProduct *temp = vec[vecLen-1];
01712             delete temp;
01713             --vecLen;
01714             // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01715           }
01716           else break;
01717         }
01718       }
01719       eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
01720     }
01721     //
01722     // This is the start of the TwoCluster function
01723     //  Choose masses for the 3 clusters:
01724     //   forward cluster
01725     //   backward meson cluster
01726     //   backward nucleon cluster
01727     //
01728     G4double rmc = 0.0, rmd = 0.0; // rme = 0.0;
01729     const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
01730     const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
01731     
01732     if( forwardCount == 0) return false;
01733 
01734     if( forwardCount == 1 )rmc = forwardMass;
01735     else
01736     {
01737 //      G4int ntc = std::min(5,forwardCount); // check if offset by 1 @@
01738       G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
01739       rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
01740     }
01741     if( backwardCount == 1 )rmd = backwardMass;
01742     else
01743     {
01744 //      G4int ntc = std::min(5,backwardCount); // check, if offfset by 1 @@
01745       G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
01746       rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
01747     }
01748     while( rmc+rmd > centerofmassEnergy )
01749     {
01750       if( (rmc <= forwardMass) && (rmd <= backwardMass) )
01751       {
01752         G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
01753         rmc *= temp;
01754         rmd *= temp;
01755       }
01756       else
01757       {
01758         rmc = 0.1*forwardMass + 0.9*rmc;
01759         rmd = 0.1*backwardMass + 0.9*rmd;
01760       }
01761     }
01762     // note that rme is never used below this section
01763     //
01764     //if( nuclearExcitationCount == 0 )rme = 0.0;
01765     //else if( nuclearExcitationCount == 1 )rme = extraMass;
01766     //else
01767     //{
01768     //  G4int ntc = std::min(5,nuclearExcitationCount)-1;
01769     //  rme = extraMass + std::pow(-std::log(1.-G4UniformRand()),cpar[ntc])/gpar[ntc];
01770     //}
01771     //
01772     //  Set beam, target of first interaction in centre of mass system
01773     //
01774     G4ReactionProduct pseudoParticle[8];
01775     for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
01776     
01777     pseudoParticle[1].SetMass( mOriginal*GeV );
01778     pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
01779     pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
01780     
01781     pseudoParticle[2].SetMass( protonMass*MeV );
01782     pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
01783     pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
01784     //
01785     //  transform into centre of mass system
01786     //
01787     pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
01788     pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
01789     pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
01790     
01791     const G4double pfMin = 0.0001;
01792     G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
01793     pf *= pf;
01794     pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
01795     pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
01796     //
01797     //  set final state masses and energies in centre of mass system
01798     //
01799     pseudoParticle[3].SetMass( rmc*GeV );
01800     pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
01801     
01802     pseudoParticle[4].SetMass( rmd*GeV );
01803     pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
01804     //
01805     // set |T| and |TMIN|
01806     //
01807     const G4double bMin = 0.01;
01808     const G4double b1 = 4.0;
01809     const G4double b2 = 1.6;
01810     G4double t = std::log( 1.0-G4UniformRand() ) / std::max( bMin, b1+b2*std::log(pOriginal) );
01811     G4double t1 =
01812       pseudoParticle[1].GetTotalEnergy()/GeV - pseudoParticle[3].GetTotalEnergy()/GeV;
01813     G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
01814     G4double tacmin = t1*t1 - (pin-pf)*(pin-pf);
01815     //
01816     // calculate (std::sin(teta/2.)^2 and std::cos(teta), set azimuth angle phi
01817     //
01818     const G4double smallValue = 1.0e-10;
01819     G4double dumnve = 4.0*pin*pf;
01820     if( dumnve == 0.0 )dumnve = smallValue;
01821     G4double ctet = std::max( -1.0, std::min( 1.0, 1.0+2.0*(t-tacmin)/dumnve ) );
01822     dumnve = std::max( 0.0, 1.0-ctet*ctet );
01823     G4double stet = std::sqrt(dumnve);
01824     G4double phi = G4UniformRand() * twopi;
01825     //
01826     // calculate final state momenta in centre of mass system
01827     //
01828     pseudoParticle[3].SetMomentum( pf*stet*std::sin(phi)*GeV,
01829                                    pf*stet*std::cos(phi)*GeV,
01830                                    pf*ctet*GeV );
01831     pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
01832     //
01833     // simulate backward nucleon cluster in lab. system and transform in cms
01834     //
01835     G4double pp, pp1, rthnve, phinve;
01836     if( nuclearExcitationCount > 0 )
01837     {
01838       const G4double ga = 1.2;
01839       G4double ekit1 = 0.04;
01840       G4double ekit2 = 0.6;
01841       if( ekOriginal <= 5.0 )
01842       {
01843         ekit1 *= ekOriginal*ekOriginal/25.0;
01844         ekit2 *= ekOriginal*ekOriginal/25.0;
01845       }
01846       const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
01847       for( i=0; i<vecLen; ++i )
01848       {
01849         if( vec[i]->GetSide() == -2 )
01850         {
01851           G4double kineticE =
01852             std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
01853           vec[i]->SetKineticEnergy( kineticE*GeV );
01854           G4double vMass = vec[i]->GetMass()/MeV;
01855           G4double totalE = kineticE + vMass;
01856           pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
01857           G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
01858           G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
01859           phi = twopi*G4UniformRand();
01860           vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
01861                                pp*sint*std::cos(phi)*MeV,
01862                                pp*cost*MeV );
01863           vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
01864         }
01865       }
01866       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01867     }
01868     //
01869     // fragmentation of forward cluster and backward meson cluster
01870     //
01871     currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
01872     currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
01873     
01874     targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
01875     targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
01876     
01877     pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
01878     pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
01879     pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
01880     
01881     pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
01882     pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
01883     pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
01884     
01885     G4double wgt;
01886       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01887     if( forwardCount > 1 )     // tempV will contain the forward particles
01888     {
01889       G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
01890       tempV.Initialize( forwardCount );
01891       G4bool constantCrossSection = true;
01892       G4int tempLen = 0;
01893       if( currentParticle.GetSide() == 1 )
01894         tempV.SetElement( tempLen++, &currentParticle );
01895       if( targetParticle.GetSide() == 1 )
01896         tempV.SetElement( tempLen++, &targetParticle );
01897       for( i=0; i<vecLen; ++i )
01898       {
01899         if( vec[i]->GetSide() == 1 )
01900         {
01901           if( tempLen < 18 )
01902             tempV.SetElement( tempLen++, vec[i] );
01903           else
01904           {
01905             vec[i]->SetSide( -1 );
01906             continue;
01907           }
01908         }
01909       }
01910       if( tempLen >= 2 )
01911       {
01912         wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
01913                                   constantCrossSection, tempV, tempLen );
01914         if( currentParticle.GetSide() == 1 )
01915           currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
01916         if( targetParticle.GetSide() == 1 )
01917           targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
01918         for( i=0; i<vecLen; ++i )
01919         {
01920           if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
01921         }
01922       }
01923     }
01924       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01925     if( backwardCount > 1 )   //  tempV will contain the backward particles,
01926     {                         //  but not those created from the intranuclear cascade
01927       G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
01928       tempV.Initialize( backwardCount );
01929       G4bool constantCrossSection = true;
01930       G4int tempLen = 0;
01931       if( currentParticle.GetSide() == -1 )
01932         tempV.SetElement( tempLen++, &currentParticle );
01933       if( targetParticle.GetSide() == -1 )
01934         tempV.SetElement( tempLen++, &targetParticle );
01935       for( i=0; i<vecLen; ++i )
01936       {
01937         if( vec[i]->GetSide() == -1 )
01938         {
01939           if( tempLen < 18 )
01940             tempV.SetElement( tempLen++, vec[i] );
01941           else
01942           {
01943             vec[i]->SetSide( -2 );
01944             vec[i]->SetKineticEnergy( 0.0 );
01945             vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
01946             continue;
01947           }
01948         }
01949       }
01950       if( tempLen >= 2 )
01951       {
01952         wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
01953                                   constantCrossSection, tempV, tempLen );
01954         if( currentParticle.GetSide() == -1 )
01955           currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
01956         if( targetParticle.GetSide() == -1 )
01957           targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
01958         for( i=0; i<vecLen; ++i )
01959         {
01960           if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
01961         }
01962       }
01963     }
01964       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
01965     //
01966     // Lorentz transformation in lab system
01967     //
01968     G4int numberofFinalStateNucleons = 0;
01969     if( currentParticle.GetDefinition() ==aProton ||
01970         currentParticle.GetDefinition() == aNeutron ||
01971         currentParticle.GetDefinition() == aSigmaMinus||
01972         currentParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
01973         currentParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
01974         currentParticle.GetDefinition() == G4XiZero::XiZero()||
01975         currentParticle.GetDefinition() == G4XiMinus::XiMinus()||
01976         currentParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
01977         currentParticle.GetDefinition() == G4Lambda::Lambda()) ++numberofFinalStateNucleons;
01978     currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
01979     if( targetParticle.GetDefinition() ==aProton ||
01980         targetParticle.GetDefinition() == aNeutron ||
01981         targetParticle.GetDefinition() == G4Lambda::Lambda() ||
01982         targetParticle.GetDefinition() == G4XiZero::XiZero()||
01983         targetParticle.GetDefinition() == G4XiMinus::XiMinus()||
01984         targetParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
01985         targetParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
01986         targetParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
01987         targetParticle.GetDefinition() == aSigmaMinus) ++numberofFinalStateNucleons;
01988     if( targetParticle.GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
01989     if( targetParticle.GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
01990     if( targetParticle.GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
01991     if( targetParticle.GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
01992     if( targetParticle.GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
01993     if( targetParticle.GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
01994     if( targetParticle.GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
01995     if( targetParticle.GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
01996     if( targetParticle.GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
01997     targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
01998     for( i=0; i<vecLen; ++i )
01999     {
02000       if( vec[i]->GetDefinition() ==aProton ||
02001           vec[i]->GetDefinition() == aNeutron ||
02002           vec[i]->GetDefinition() == G4Lambda::Lambda() ||
02003           vec[i]->GetDefinition() == G4XiZero::XiZero() ||
02004           vec[i]->GetDefinition() == G4XiMinus::XiMinus() ||
02005           vec[i]->GetDefinition() == G4OmegaMinus::OmegaMinus() ||
02006           vec[i]->GetDefinition() == G4SigmaPlus::SigmaPlus()||
02007           vec[i]->GetDefinition() == G4SigmaZero::SigmaZero()||
02008           vec[i]->GetDefinition() == aSigmaMinus) ++numberofFinalStateNucleons;
02009       if( vec[i]->GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
02010       if( vec[i]->GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
02011       if( vec[i]->GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
02012       if( vec[i]->GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
02013       if( vec[i]->GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
02014       if( vec[i]->GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
02015       if( vec[i]->GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
02016       if( vec[i]->GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
02017       if( vec[i]->GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
02018       vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
02019     }
02020       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02021     numberofFinalStateNucleons = std::max( 1, numberofFinalStateNucleons );
02022     //
02023     // sometimes the leading strange particle is lost, set it back
02024     //
02025     G4bool dum = true;
02026     if( leadFlag )
02027     {
02028       // leadFlag will be true
02029       //  iff original particle is at least as heavy as K+ and not a proton or neutron AND
02030       //   if
02031       //    incident particle is at least as heavy as K+ and it is not a proton or neutron
02032       //     leadFlag is set to the incident particle
02033       //   or
02034       //    target particle is at least as heavy as K+ and it is not a proton or neutron
02035       //     leadFlag is set to the target particle
02036       //
02037       if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
02038         dum = false;
02039       else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
02040         dum = false;
02041       else
02042       {
02043         for( i=0; i<vecLen; ++i )
02044         {
02045           if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
02046           {
02047             dum = false;
02048             break;
02049           }
02050         }
02051       }
02052       if( dum )
02053       {
02054         G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
02055         G4double ekin;
02056         if( ((leadMass <  protonMass) && (targetParticle.GetMass()/MeV <  protonMass)) ||
02057             ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
02058         {
02059           ekin = targetParticle.GetKineticEnergy()/GeV;
02060           pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
02061           targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
02062           targetParticle.SetKineticEnergy( ekin*GeV );
02063           pp = targetParticle.GetTotalMomentum()/MeV;   // new momentum
02064           if( pp1 < 1.0e-3 )
02065           {
02066             rthnve = pi*G4UniformRand();
02067             phinve = twopi*G4UniformRand();
02068             targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(rthnve)*MeV,
02069                                         pp*std::sin(rthnve)*std::sin(rthnve)*MeV,
02070                                         pp*std::cos(rthnve)*MeV );
02071           }
02072           else
02073             targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
02074           
02075           targetHasChanged = true;
02076         }
02077         else
02078         {
02079           ekin = currentParticle.GetKineticEnergy()/GeV;
02080           pp1 = currentParticle.GetMomentum().mag()/MeV;
02081           currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
02082           currentParticle.SetKineticEnergy( ekin*GeV );
02083           pp = currentParticle.GetTotalMomentum()/MeV;
02084           if( pp1 < 1.0e-3 )
02085           {
02086             rthnve = pi*G4UniformRand();
02087             phinve = twopi*G4UniformRand();
02088             currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(rthnve)*MeV,
02089                                          pp*std::sin(rthnve)*std::sin(rthnve)*MeV,
02090                                          pp*std::cos(rthnve)*MeV );
02091           }
02092           else
02093             currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02094           
02095           incidentHasChanged = true;
02096         }
02097       }
02098     }    // end of if( leadFlag )
02099     //
02100     //  for various reasons, the energy balance is not sufficient,
02101     //  check that,  energy balance, angle of final system, etc.
02102     //
02103     pseudoParticle[4].SetMass( mOriginal*GeV );
02104     pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
02105     pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
02106     
02107     G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
02108     G4int diff = 0;
02109     if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
02110     if(numberofFinalStateNucleons == 1) diff = 0;
02111     pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
02112     pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
02113     pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
02114     
02115 //    G4double ekin0 = pseudoParticle[4].GetKineticEnergy()/GeV;
02116     G4double theoreticalKinetic =
02117       pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
02118     
02119     pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
02120     pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
02121     pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
02122      
02123     if( vecLen < 16 )
02124     {
02125       G4ReactionProduct tempR[130];
02126       //G4ReactionProduct *tempR = new G4ReactionProduct [vecLen+2];
02127       tempR[0] = currentParticle;
02128       tempR[1] = targetParticle;
02129       for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
02130 
02131       G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
02132       tempV.Initialize( vecLen+2 );
02133       G4bool constantCrossSection = true;
02134       G4int tempLen = 0;
02135       for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
02136 
02137       if( tempLen >= 2 )
02138       {
02139       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02140         wgt = GenerateNBodyEvent(
02141          pseudoParticle[4].GetTotalEnergy()/MeV+pseudoParticle[5].GetTotalEnergy()/MeV,
02142          constantCrossSection, tempV, tempLen );
02143         theoreticalKinetic = 0.0;
02144         for( i=0; i<vecLen+2; ++i )
02145         {
02146           pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
02147           pseudoParticle[7].SetMass( tempV[i]->GetMass() );
02148           pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
02149           pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
02150           theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
02151         }
02152       }
02153       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02154       //delete [] tempR;
02155     }
02156     else
02157     {
02158       theoreticalKinetic -=
02159         ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
02160       for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
02161     }
02162     G4double simulatedKinetic =
02163       currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
02164     for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
02165     //
02166     // make sure that kinetic energies are correct
02167     // the backward nucleon cluster is not produced within proper kinematics!!!
02168     //
02169     
02170     if( simulatedKinetic != 0.0 )
02171     {
02172       wgt = (theoreticalKinetic)/simulatedKinetic;
02173       currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
02174       pp = currentParticle.GetTotalMomentum()/MeV;
02175       pp1 = currentParticle.GetMomentum().mag()/MeV;
02176       if( pp1 < 0.001*MeV )
02177       {
02178         rthnve = pi * G4UniformRand();
02179         phinve = twopi * G4UniformRand();
02180         currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
02181                                      pp*std::sin(rthnve)*std::sin(phinve)*MeV,
02182                                      pp*std::cos(rthnve)*MeV );
02183       }
02184       else
02185         currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02186       
02187       targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
02188       pp = targetParticle.GetTotalMomentum()/MeV;
02189       pp1 = targetParticle.GetMomentum().mag()/MeV;
02190       if( pp1 < 0.001*MeV )
02191       {
02192         rthnve = pi * G4UniformRand();
02193         phinve = twopi * G4UniformRand();
02194         targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
02195                                     pp*std::sin(rthnve)*std::sin(phinve)*MeV,
02196                                     pp*std::cos(rthnve)*MeV );
02197       }
02198       else
02199         targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
02200       
02201       for( i=0; i<vecLen; ++i )
02202       {
02203         vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
02204         pp = vec[i]->GetTotalMomentum()/MeV;
02205         pp1 = vec[i]->GetMomentum().mag()/MeV;
02206         if( pp1 < 0.001 )
02207         {
02208           rthnve = pi * G4UniformRand();
02209           phinve = twopi * G4UniformRand();
02210           vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
02211                                pp*std::sin(rthnve)*std::sin(phinve)*MeV,
02212                                pp*std::cos(rthnve)*MeV );
02213         }
02214         else
02215           vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
02216       }
02217     }
02218       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02219     Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
02220             modifiedOriginal, originalIncident, targetNucleus,
02221             currentParticle, targetParticle, vec, vecLen );
02222     //
02223     //  add black track particles
02224     //  the total number of particles produced is restricted to 198
02225     //  this may have influence on very high energies
02226     //
02227     if( atomicWeight >= 1.5 )
02228     {
02229       // npnb is number of proton/neutron black track particles
02230       // ndta is the number of deuterons, tritons, and alphas produced
02231       // epnb is the kinetic energy available for proton/neutron black track particles
02232       // edta is the kinetic energy available for deuteron/triton/alpha particles
02233       //
02234       G4double epnb, edta;
02235       G4int npnb = 0;
02236       G4int ndta = 0;
02237       
02238       epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
02239       edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
02240       const G4double pnCutOff = 0.001;     // GeV
02241       const G4double dtaCutOff = 0.001;    // GeV
02242       const G4double kineticMinimum = 1.e-6;
02243       const G4double kineticFactor = -0.005;
02244       
02245       G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
02246       const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
02247       if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
02248       
02249       if( epnb >= pnCutOff )
02250       {
02251         npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
02252         if( numberofFinalStateNucleons + npnb > atomicWeight )
02253           npnb = G4int(atomicWeight - numberofFinalStateNucleons);
02254         npnb = std::min( npnb, 127-vecLen );
02255       }
02256       if( edta >= dtaCutOff )
02257       {
02258         ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
02259         ndta = std::min( ndta, 127-vecLen );
02260       }
02261       G4double spall = numberofFinalStateNucleons;
02262       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02263 
02264       AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
02265                               modifiedOriginal, spall, targetNucleus,
02266                               vec, vecLen );
02267 
02268       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02269     }
02270     //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
02271     //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
02272     //
02273     //  calculate time delay for nuclear reactions
02274     //
02275     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
02276       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
02277     else
02278       currentParticle.SetTOF( 1.0 );
02279     
02280       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02281     return true;
02282   }
02283  
02284  void FullModelReactionDynamics::TwoBody(
02285   G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
02286   G4int &vecLen,
02287   G4ReactionProduct &modifiedOriginal,
02288   const G4DynamicParticle */*originalTarget*/,
02289   G4ReactionProduct &currentParticle,
02290   G4ReactionProduct &targetParticle,
02291   const G4Nucleus &targetNucleus,
02292   G4bool &/* targetHasChanged*/ )
02293   {
02294     //    G4cout<<"TwoBody called"<<G4endl;
02295     // 
02296     // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
02297     //
02298     // Generation of momenta for elastic and quasi-elastic 2 body reactions
02299     //
02300     // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
02301     // The b values are parametrizations from experimental data.
02302     // Not available values are taken from those of similar reactions.
02303     //
02304     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
02305     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
02306     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
02307     G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
02308     G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
02309     G4ParticleDefinition *aKaonZeroS = G4KaonZeroShort::KaonZeroShort();
02310     G4ParticleDefinition *aKaonZeroL = G4KaonZeroLong::KaonZeroLong();
02311     
02312       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);    
02313     static const G4double expxu =  82.;           // upper bound for arg. of exp
02314     static const G4double expxl = -expxu;         // lower bound for arg. of exp
02315     
02316     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
02317     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
02318     const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
02319     const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
02320     G4double currentMass = currentParticle.GetMass()/GeV;
02321     G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
02322 
02323     targetMass = targetParticle.GetMass()/GeV;
02324     const G4double atomicWeight = targetNucleus.GetN();
02325     //    G4cout<<"Atomic weight is found to be: "<<atomicWeight<<G4endl;
02326     G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
02327     G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
02328 
02329     G4double cmEnergy = std::sqrt( currentMass*currentMass +
02330                               targetMass*targetMass +
02331                               2.0*targetMass*etCurrent );  // in GeV
02332 
02333     //if( (pOriginal < 0.1) ||
02334     //    (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
02335     // Continue with original particle, but spend the nuclear evaporation energy
02336     //  targetParticle.SetMass( 0.0 );  // flag that the target doesn't exist
02337     //else                           // Two-body scattering is possible
02338 
02339     if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
02340     {
02341       targetParticle.SetMass( 0.0 );  // flag that the target particle doesn't exist
02342     }
02343     else
02344     {
02345 // moved this if-block to a later stage, i.e. to the assignment of the scattering angle
02346 // @@@@@ double-check.
02347 //      if( targetParticle.GetDefinition() == aKaonMinus ||
02348 //          targetParticle.GetDefinition() == aKaonZeroL ||
02349 //          targetParticle.GetDefinition() == aKaonZeroS ||
02350 //          targetParticle.GetDefinition() == aKaonPlus ||
02351 //          targetParticle.GetDefinition() == aPiMinus ||
02352 //          targetParticle.GetDefinition() == aPiZero ||
02353 //          targetParticle.GetDefinition() == aPiPlus )
02354 //      {
02355 //        if( G4UniformRand() < 0.5 )
02356 //          targetParticle.SetDefinitionAndUpdateE( aNeutron );
02357 //        else
02358 //          targetParticle.SetDefinitionAndUpdateE( aProton );
02359 //        targetHasChanged = true;
02360 //        targetMass = targetParticle.GetMass()/GeV;
02361 //      }
02362       //
02363       // Set masses and momenta for final state particles
02364       //
02365       /*
02366       G4cout<<"Check 0"<<G4endl;
02367       G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()/GeV<<G4endl;
02368       G4cout<<"target mass: "<<targetParticle.GetMass()/GeV<<G4endl;
02369       G4cout<<targetParticle.GetDefinition()->GetParticleName()<<G4endl;
02370       G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()/GeV<<G4endl;
02371       G4cout<<"current mass: "<<currentParticle.GetMass()/GeV<<G4endl;
02372       G4cout<<currentParticle.GetDefinition()->GetParticleName()<<G4endl;
02373       */
02374       G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
02375       pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
02376       //      G4cout << "pf: " << pf<< G4endl;
02377       
02378       if( pf <= 0.)// 0.001 )
02379       {
02380         for(G4int i=0; i<vecLen; i++) delete vec[i];
02381         vecLen = 0;
02382         throw G4HadronicException(__FILE__, __LINE__, "FullModelReactionDynamics::TwoBody: pf is too small ");
02383       }
02384       
02385       pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
02386       //
02387       // Set beam and target in centre of mass system
02388       //
02389       G4ReactionProduct pseudoParticle[3];
02390       /* //Marker      
02391       if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron") 
02392          targetParticle.GetDefinition() == aKaonMinus ||
02393          targetParticle.GetDefinition() == aKaonZeroL ||
02394          targetParticle.GetDefinition() == aKaonZeroS ||
02395          targetParticle.GetDefinition() == aKaonPlus ||
02396          targetParticle.GetDefinition() == aPiMinus ||
02397          targetParticle.GetDefinition() == aPiZero ||
02398          targetParticle.GetDefinition() == aPiPlus )
02399         {
02400         G4cout<<"Particlecheck"<<G4endl;
02401         pseudoParticle[0].SetMass( targetMass*GeV );
02402         G4cout<<pseudoParticle[0].GetMass()<<G4endl;
02403         pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
02404         G4cout<<pseudoParticle[0].GetTotalEnergy()<<G4endl;
02405         pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
02406       
02407         pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
02408         pseudoParticle[1].SetMass( mOriginal*GeV );
02409         G4cout<<pseudoParticle[1].GetMass()<<G4endl;
02410         pseudoParticle[1].SetKineticEnergy( 0.0 );
02411         G4cout<<pseudoParticle[1].GetTotalEnergy()<<G4endl;
02412         }
02413       else
02414       {*/
02415         pseudoParticle[0].SetMass( currentMass*GeV );
02416         pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
02417         pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
02418       
02419         pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
02420         pseudoParticle[1].SetMass( targetMass*GeV );
02421         pseudoParticle[1].SetKineticEnergy( 0.0 );
02422         //      }
02423       //
02424       // Transform into centre of mass system
02425       //
02426       pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
02427       pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
02428       pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
02429       //
02430       // Set final state masses and energies in centre of mass system
02431       //
02432       currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
02433       targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
02434       //
02435       // Set |t| and |tmin|
02436       //
02437       const G4double cb = 0.01;
02438       const G4double b1 = 4.225;
02439       const G4double b2 = 1.795;
02440       //
02441       // Calculate slope b for elastic scattering on proton/neutron
02442       //
02443       G4ParticleTable* theParticleTable = G4ParticleTable::GetParticleTable();
02444       G4double ptemp=0;
02445       /*
02446       if(modifiedOriginal.GetDefinition()->GetParticleType()=="rhadron"){
02447         //      G4cout<<"Rescaling energy by gluino mass"<<G4endl;
02448         //Getting the mass of the bare gluino:
02449         G4double Mg = theParticleTable->FindParticle("~g")->GetPDGMass();
02450         //Mass of active system:
02451         G4double sysmass = mOriginal-Mg;
02452         ptemp = sqrt(etOriginal*etOriginal/(mOriginal*mOriginal)-1)*sysmass;
02453 
02454       }
02455       */
02456 
02457       G4double b = std::max( cb, b1+b2*std::log(pOriginal) );     
02458       //      G4double b = std::max( cb, b1+b2*std::log(ptemp) );     
02459       G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
02460       
02461       G4double exindt = -1.0;
02462       exindt += std::exp(std::max(-btrang,expxl));
02463       //
02464       // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
02465       //
02466       G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
02467       if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
02468       G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
02469       G4double phi = twopi * G4UniformRand();
02470       //
02471       // Calculate final state momenta in centre of mass system
02472       //
02473       if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron") 
02474         targetParticle.GetDefinition() == aKaonMinus ||
02475           targetParticle.GetDefinition() == aKaonZeroL ||
02476           targetParticle.GetDefinition() == aKaonZeroS ||
02477           targetParticle.GetDefinition() == aKaonPlus ||
02478           targetParticle.GetDefinition() == aPiMinus ||
02479           targetParticle.GetDefinition() == aPiZero ||
02480           targetParticle.GetDefinition() == aPiPlus )
02481       {
02482         currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
02483                                      -pf*stet*std::cos(phi)*GeV,
02484                                      -pf*ctet*GeV );
02485       }
02486       else
02487       {
02488         currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
02489                                      pf*stet*std::cos(phi)*GeV,
02490                                      pf*ctet*GeV );
02491       }
02492       targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
02493       //
02494       // Transform into lab system
02495       //
02496       currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
02497       targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
02498 
02499       /*
02500       G4cout<<"Check 1"<<G4endl;
02501       G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
02502       G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
02503       G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
02504       G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
02505       */
02506 
02507       Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
02508       
02509       G4double pp, pp1, ekin;
02510       if( atomicWeight >= 1.5 )
02511       {
02512         const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
02513         pp1 = currentParticle.GetMomentum().mag()/MeV;
02514         if( pp1 >= 1.0 )
02515         {
02516           ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
02517           ekin = std::max( 0.0001*GeV, ekin );
02518           currentParticle.SetKineticEnergy( ekin*MeV );
02519           pp = currentParticle.GetTotalMomentum()/MeV;
02520           currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
02521         }
02522         pp1 = targetParticle.GetMomentum().mag()/MeV;
02523         if( pp1 >= 1.0 )
02524         {
02525           ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
02526           ekin = std::max( 0.0001*GeV, ekin );
02527           targetParticle.SetKineticEnergy( ekin*MeV );
02528           pp = targetParticle.GetTotalMomentum()/MeV;
02529           targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
02530         }
02531       }
02532     }
02533       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02534     if( atomicWeight >= 1.5 )
02535     {
02536       // Add black track particles
02537       //  the procedure is somewhat different than in TwoCluster and GenerateXandPt.
02538       //  The reason is that we have to also simulate the nuclear reactions
02539       //  at low energies like a(h,p)b, a(h,p p)b, a(h,n)b etc.
02540       //
02541       // npnb is number of proton/neutron black track particles
02542       // ndta is the number of deuterons, tritons, and alphas produced
02543       // epnb is the kinetic energy available for proton/neutron black track particles
02544       // edta is the kinetic energy available for deuteron/triton/alpha particles
02545       //
02546       G4double epnb, edta;
02547       G4int npnb=0, ndta=0;
02548       
02549       epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
02550       edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
02551       const G4double pnCutOff = 0.0001;       // GeV
02552       const G4double dtaCutOff = 0.0001;      // GeV
02553       const G4double kineticMinimum = 0.0001;
02554       const G4double kineticFactor = -0.010;
02555       G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
02556       if( epnb >= pnCutOff )
02557       {
02558         npnb = Poisson( epnb/0.02 );
02559         /*
02560         G4cout<<"A couple of Poisson numbers:"<<G4endl;
02561         for (int n=0;n!=10;n++) G4cout<<Poisson(epnb/0.02)<<", ";
02562         G4cout<<G4endl;
02563         */
02564         if( npnb > atomicWeight )npnb = G4int(atomicWeight);
02565         if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
02566         npnb = std::min( npnb, 127-vecLen );
02567       }
02568       if( edta >= dtaCutOff )
02569       {
02570         ndta = G4int(2.0 * std::log(atomicWeight));
02571         ndta = std::min( ndta, 127-vecLen );
02572       }
02573       G4double spall = 0.0;
02574       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02575 
02576       /*
02577       G4cout<<"Check 2"<<G4endl;
02578       G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
02579       G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
02580       G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
02581       G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
02582 
02583       G4cout<<"------------------------------------------------------------------------"<<G4endl;
02584       G4cout<<"Atomic weight: "<<atomicWeight<<G4endl;
02585       G4cout<<"number of proton/neutron black track particles: "<<npnb<<G4endl;
02586       G4cout<<"number of deuterons, tritons, and alphas produced: "<<ndta <<G4endl;
02587       G4cout<<"kinetic energy available for proton/neutron black track particles: "<<epnb/GeV<<" GeV" <<G4endl;
02588       G4cout<<"kinetic energy available for deuteron/triton/alpha particles: "<<edta/GeV <<" GeV"<<G4endl;
02589       G4cout<<"------------------------------------------------------------------------"<<G4endl;
02590       */
02591 
02592       AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
02593                               modifiedOriginal, spall, targetNucleus,
02594                               vec, vecLen );
02595 
02596       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02597     }
02598     //
02599     //  calculate time delay for nuclear reactions
02600     //
02601     if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
02602       currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
02603     else
02604       currentParticle.SetTOF( 1.0 );
02605     return;
02606   }
02607  
02608  G4double FullModelReactionDynamics::GenerateNBodyEvent(
02609   const G4double totalEnergy,                // MeV
02610   const G4bool constantCrossSection,
02611   G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
02612   G4int &vecLen )
02613   {
02614 //      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02615     // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
02616     // Returns the weight of the event
02617     //
02618     G4int i;
02619     const G4double expxu =  82.;           // upper bound for arg. of exp
02620     const G4double expxl = -expxu;         // lower bound for arg. of exp
02621     if( vecLen < 2 )
02622     {
02623       G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
02624       G4cerr << "    number of particles < 2" << G4endl;
02625       G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
02626       return -1.0;
02627     }
02628     G4double mass[18];    // mass of each particle
02629     G4double energy[18];  // total energy of each particle
02630     G4double pcm[3][18];           // pcm is an array with 3 rows and vecLen columns
02631     //G4double *mass = new G4double [vecLen];    // mass of each particle
02632     //G4double *energy = new G4double [vecLen];  // total energy of each particle
02633     //G4double **pcm;           // pcm is an array with 3 rows and vecLen columns
02634     //pcm = new G4double * [3];
02635     //for( i=0; i<3; ++i )pcm[i] = new G4double [vecLen];
02636     
02637     G4double totalMass = 0.0;
02638     G4double extraMass = 0;
02639     G4double sm[18];
02640     //G4double *sm = new G4double [vecLen];
02641     
02642     for( i=0; i<vecLen; ++i )
02643     {
02644       mass[i] = vec[i]->GetMass()/GeV;
02645       if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
02646       vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
02647       pcm[0][i] = 0.0;      // x-momentum of i-th particle
02648       pcm[1][i] = 0.0;      // y-momentum of i-th particle
02649       pcm[2][i] = 0.0;      // z-momentum of i-th particle
02650       energy[i] = mass[i];  // total energy of i-th particle
02651       totalMass += mass[i];
02652       sm[i] = totalMass;
02653     }
02654     G4double totalE = totalEnergy/GeV;
02655     if( totalMass > totalE )
02656     {
02657       //G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
02658       //G4cerr << "    total mass (" << totalMass*GeV << "MeV) > total energy ("
02659       //     << totalEnergy << "MeV)" << G4endl;
02660       totalE = totalMass;
02661       //delete [] mass;
02662       //delete [] energy;
02663       //for( i=0; i<3; ++i )delete [] pcm[i];
02664       //delete [] pcm;
02665       //delete [] sm;
02666       return -1.0;
02667     }
02668     G4double kineticEnergy = totalE - totalMass;
02669     G4double emm[18];
02670     //G4double *emm = new G4double [vecLen];
02671     emm[0] = mass[0];
02672     emm[vecLen-1] = totalE;
02673     if( vecLen > 2 )          // the random numbers are sorted
02674     {
02675       G4double ran[18];
02676       for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
02677       for( i=0; i<vecLen-2; ++i )
02678       {
02679         for( G4int j=vecLen-2; j>i; --j )
02680         {
02681           if( ran[i] > ran[j] )
02682           {
02683             G4double temp = ran[i];
02684             ran[i] = ran[j];
02685             ran[j] = temp;
02686           }
02687         }
02688       }
02689       for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
02690     }
02691     //   Weight is the sum of logarithms of terms instead of the product of terms
02692     G4bool lzero = true;    
02693     G4double wtmax = 0.0;
02694     if( constantCrossSection )     // this is KGENEV=1 in PHASP
02695     {
02696       G4double emmax = kineticEnergy + mass[0];
02697       G4double emmin = 0.0;
02698       for( i=1; i<vecLen; ++i )
02699       {
02700         emmin += mass[i-1];
02701         emmax += mass[i];
02702         G4double wtfc = 0.0;
02703         if( emmax*emmax > 0.0 )
02704         {
02705           G4double arg = emmax*emmax
02706             + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
02707             - 2.0*(emmin*emmin+mass[i]*mass[i]);
02708           if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
02709         }
02710         if( wtfc == 0.0 )
02711         {
02712           lzero = false;
02713           break;
02714         }
02715         wtmax += std::log( wtfc );
02716       }
02717       if( lzero )
02718         wtmax = -wtmax;
02719       else
02720         wtmax = expxu;
02721     }
02722     else
02723     {
02724       //   ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
02725       const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
02726                                  256.3704, 268.4705, 240.9780, 189.2637,
02727                                  132.1308,  83.0202,  47.4210,  24.8295,
02728                                  12.0006,   5.3858,   2.2560,   0.8859 };
02729       wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
02730     }
02731     lzero = true;
02732     G4double pd[50];
02733     //G4double *pd = new G4double [vecLen-1];
02734     for( i=0; i<vecLen-1; ++i )
02735     {
02736       pd[i] = 0.0;
02737       if( emm[i+1]*emm[i+1] > 0.0 )
02738       {
02739         G4double arg = emm[i+1]*emm[i+1]
02740           + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
02741             /(emm[i+1]*emm[i+1])
02742           - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
02743         if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
02744       }
02745       if( pd[i] <= 0.0 )    //  changed from  ==  on 02 April 98
02746         lzero = false;
02747       else
02748         wtmax += std::log( pd[i] );
02749     }
02750     G4double weight = 0.0;           // weight is returned by GenerateNBodyEvent
02751     if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
02752     
02753     G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
02754     pcm[0][0] = 0.0;
02755     pcm[1][0] = pd[0];
02756     pcm[2][0] = 0.0;
02757     for( i=1; i<vecLen; ++i )
02758     {
02759       pcm[0][i] = 0.0;
02760       pcm[1][i] = -pd[i-1];
02761       pcm[2][i] = 0.0;
02762       bang = twopi*G4UniformRand();
02763       cb = std::cos(bang);
02764       sb = std::sin(bang);
02765       c = 2.0*G4UniformRand() - 1.0;
02766       s = std::sqrt( std::fabs( 1.0-c*c ) );
02767       if( i < vecLen-1 )
02768       {
02769         esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
02770         beta = pd[i]/esys;
02771         gama = esys/emm[i];
02772         for( G4int j=0; j<=i; ++j )
02773         {
02774           s0 = pcm[0][j];
02775           s1 = pcm[1][j];
02776           s2 = pcm[2][j];
02777           energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
02778           a = s0*c - s1*s;                           //  rotation
02779           pcm[1][j] = s0*s + s1*c;
02780           b = pcm[2][j];
02781           pcm[0][j] = a*cb - b*sb;
02782           pcm[2][j] = a*sb + b*cb;
02783           pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
02784         }
02785       }
02786       else
02787       {
02788         for( G4int j=0; j<=i; ++j )
02789         {
02790           s0 = pcm[0][j];
02791           s1 = pcm[1][j];
02792           s2 = pcm[2][j];
02793           energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
02794           a = s0*c - s1*s;                           //  rotation
02795           pcm[1][j] = s0*s + s1*c;
02796           b = pcm[2][j];
02797           pcm[0][j] = a*cb - b*sb;
02798           pcm[2][j] = a*sb + b*cb;
02799         }
02800       }
02801     }
02802     for( i=0; i<vecLen; ++i )
02803     {
02804       vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
02805       vec[i]->SetTotalEnergy( energy[i]*GeV );
02806     }
02807     //delete [] mass;
02808     //delete [] energy;
02809     //for( i=0; i<3; ++i )delete [] pcm[i];
02810     //delete [] pcm;
02811     //delete [] emm;
02812     //delete [] sm;
02813     //delete [] pd;
02814       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
02815     return weight;
02816   }
02817  
02818  G4double
02819    FullModelReactionDynamics::normal()
02820    {
02821      G4double ran = -6.0;
02822      for( G4int i=0; i<12; ++i )ran += G4UniformRand();
02823      return ran;
02824    }
02825  
02826  G4int
02827    FullModelReactionDynamics::Poisson( G4double x )  // generation of poisson distribution
02828    {
02829      G4int iran;
02830      G4double ran;
02831      
02832      if( x > 9.9 )    // use normal distribution with sigma^2 = <x>
02833        iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
02834      else {
02835       G4int mm = G4int(5.0*x);
02836       if( mm <= 0 )   // for very small x try iran=1,2,3
02837       {
02838         G4double p1 = x*std::exp(-x);
02839         G4double p2 = x*p1/2.0;
02840         G4double p3 = x*p2/3.0;
02841         ran = G4UniformRand();
02842         if( ran < p3 )
02843           iran = 3;
02844         else if( ran < p2 )   // this is original Geisha, it should be ran < p2+p3
02845           iran = 2;
02846         else if( ran < p1 )   // should be ran < p1+p2+p3
02847           iran = 1;
02848         else
02849           iran = 0;
02850       }
02851       else
02852       {
02853         iran = 0;
02854         G4double r = std::exp(-x);
02855         ran = G4UniformRand();
02856         if( ran > r )
02857         {
02858           G4double rrr;
02859           G4double rr = r;
02860           for( G4int i=1; i<=mm; ++i )
02861           {
02862             iran++;
02863             if( i > 5 )   // Stirling's formula for large numbers
02864               rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
02865             else
02866               rrr = std::pow(x,i)/Factorial(i);
02867             rr += r*rrr;
02868             if( ran <= rr )break;
02869           }
02870         }
02871       }
02872     }
02873     return iran;
02874   }
02875  
02876  G4int
02877    FullModelReactionDynamics::Factorial( G4int n )
02878    {   // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
02879      G4int m = std::min(n,10);
02880      G4int result = 1;
02881      if( m <= 1 )return result;
02882      for( G4int i=2; i<=m; ++i )result *= i;
02883      return result;
02884    }
02885  
02886  void FullModelReactionDynamics::Defs1(
02887    const G4ReactionProduct &modifiedOriginal,
02888    G4ReactionProduct &currentParticle,
02889    G4ReactionProduct &targetParticle,
02890    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
02891    G4int &vecLen )
02892   {
02893     const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
02894     const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
02895     const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
02896     const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
02897     if( pjx*pjx+pjy*pjy > 0.0 )
02898     {
02899       G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
02900       cost = pjz/p;
02901       sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
02902       if( pjy < 0.0 )
02903         ph = 3*halfpi;
02904       else
02905         ph = halfpi;
02906       if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
02907       cosp = std::cos(ph);
02908       sinp = std::sin(ph);
02909       pix = currentParticle.GetMomentum().x()/MeV;
02910       piy = currentParticle.GetMomentum().y()/MeV;
02911       piz = currentParticle.GetMomentum().z()/MeV;
02912       currentParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
02913                                    cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
02914                                    -sint*pix*MeV     + cost*piz*MeV );
02915       pix = targetParticle.GetMomentum().x()/MeV;
02916       piy = targetParticle.GetMomentum().y()/MeV;
02917       piz = targetParticle.GetMomentum().z()/MeV;
02918       targetParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
02919                                   cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
02920                                   -sint*pix*MeV     + cost*piz*MeV );
02921       for( G4int i=0; i<vecLen; ++i )
02922       {
02923         pix = vec[i]->GetMomentum().x()/MeV;
02924         piy = vec[i]->GetMomentum().y()/MeV;
02925         piz = vec[i]->GetMomentum().z()/MeV;
02926         vec[i]->SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
02927                              cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
02928                              -sint*pix*MeV     + cost*piz*MeV );
02929       }
02930     }
02931     else
02932     {
02933       if( pjz < 0.0 )
02934       {
02935         currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
02936         targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
02937         for( G4int i=0; i<vecLen; ++i )
02938           vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
02939       }
02940     }
02941   }
02942  
02943  void FullModelReactionDynamics::Rotate(
02944   const G4double numberofFinalStateNucleons,
02945   const G4ThreeVector &temp,
02946   const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
02947   const G4HadProjectile *originalIncident, // original incident particle
02948   const G4Nucleus &targetNucleus,
02949   G4ReactionProduct &currentParticle,
02950   G4ReactionProduct &targetParticle,
02951   G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
02952   G4int &vecLen )
02953   {
02954     // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
02955     //
02956     //   Rotate in direction of z-axis, this does disturb in some way our
02957     //    inclusive distributions, but it is necessary for momentum conservation
02958     //
02959     const G4double atomicWeight = targetNucleus.GetN();
02960     const G4double logWeight = std::log(atomicWeight);
02961     
02962     G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
02963     G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
02964     G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
02965     
02966     G4int i;
02967     G4ThreeVector pseudoParticle[4];
02968     for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
02969     pseudoParticle[0] = currentParticle.GetMomentum()
02970                         + targetParticle.GetMomentum();
02971     for( i=0; i<vecLen; ++i )
02972       pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
02973     //
02974     //  Some smearing in transverse direction from Fermi motion
02975     //
02976     G4float pp, pp1;
02977     G4double alekw, p, rthnve, phinve;
02978     G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
02979     
02980     r1 = twopi*G4UniformRand();
02981     r2 = G4UniformRand();
02982     a1 = std::sqrt(-2.0*std::log(r2));
02983     ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
02984     ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
02985     G4ThreeVector fermi(ran1, ran2, 0);
02986 
02987     pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
02988     pseudoParticle[2] = temp; // original in cms system
02989     pseudoParticle[3] = pseudoParticle[0];
02990     
02991     pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
02992     G4double rotation = 2.*pi*G4UniformRand();
02993     pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
02994     pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);    
02995     for(G4int ii=1; ii<=3; ii++)
02996     { 
02997       p = pseudoParticle[ii].mag();
02998       if( p == 0.0 )
02999         pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
03000       else
03001         pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
03002     }
03003     
03004     pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
03005     pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
03006     pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
03007     currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
03008     
03009     pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
03010     pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
03011     pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
03012     targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
03013     
03014     for( i=0; i<vecLen; ++i )
03015     {
03016       pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
03017       pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
03018       pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
03019       vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
03020     }
03021     //
03022     //  Rotate in direction of primary particle, subtract binding energies
03023     //   and make some further corrections if required
03024     //
03025     Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
03026     G4double ekin;
03027     G4double dekin = 0.0;
03028     G4double ek1 = 0.0;
03029     G4int npions = 0;
03030     if( atomicWeight >= 1.5 )            // self-absorption in heavy molecules
03031     {
03032       // corrections for single particle spectra (shower particles)
03033       //
03034       const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
03035       const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
03036       alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
03037       exh = 1.0;
03038       if( alekw > alem[0] )   //   get energy bin
03039       {
03040         exh = val0[6];
03041         for( G4int j=1; j<7; ++j )
03042         {
03043           if( alekw < alem[j] ) // use linear interpolation/extrapolation
03044           {
03045             G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
03046             exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
03047             break;
03048           }
03049         }
03050         exh = 1.0 - exh;
03051       }
03052       const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
03053       ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
03054       ekin = std::max( 1.0e-6, ekin );
03055       xxh = 1.0;
03056       /*      if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
03057             (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
03058           (currentParticle.GetDefinition() == aPiZero) &&
03059           (G4UniformRand() <= logWeight) )xxh = exh;*/
03060       dekin += ekin*(1.0-xxh);
03061       ekin *= xxh;
03062       /*      if( (currentParticle.GetDefinition() == aPiPlus) ||
03063           (currentParticle.GetDefinition() == aPiZero) ||
03064           (currentParticle.GetDefinition() == aPiMinus) )
03065       {
03066         ++npions;
03067         ek1 += ekin;
03068         }*/
03069       currentParticle.SetKineticEnergy( ekin*GeV );
03070       pp = currentParticle.GetTotalMomentum()/MeV;
03071       pp1 = currentParticle.GetMomentum().mag()/MeV;
03072       if( pp1 < 0.001*MeV )
03073       {
03074         rthnve = pi*G4UniformRand();
03075         phinve = twopi*G4UniformRand();
03076         currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03077                                      pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03078                                      pp*std::cos(rthnve)*MeV );
03079       }
03080       else
03081         currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
03082       ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
03083       ekin = std::max( 1.0e-6, ekin );
03084       xxh = 1.0;
03085       if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
03086             (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
03087           (targetParticle.GetDefinition() == aPiZero) &&
03088           (G4UniformRand() < logWeight) )xxh = exh;
03089       dekin += ekin*(1.0-xxh);
03090       ekin *= xxh;
03091       if( (targetParticle.GetDefinition() == aPiPlus) ||
03092           (targetParticle.GetDefinition() == aPiZero) ||
03093           (targetParticle.GetDefinition() == aPiMinus) )
03094       {
03095         ++npions;
03096         ek1 += ekin;
03097       }
03098       targetParticle.SetKineticEnergy( ekin*GeV );
03099       pp = targetParticle.GetTotalMomentum()/MeV;
03100       pp1 = targetParticle.GetMomentum().mag()/MeV;
03101       if( pp1 < 0.001*MeV )
03102       {
03103         rthnve = pi*G4UniformRand();
03104         phinve = twopi*G4UniformRand();
03105         targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03106                                     pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03107                                     pp*std::cos(rthnve)*MeV );
03108       }
03109       else
03110         targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
03111       for( i=0; i<vecLen; ++i )
03112       {
03113         ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
03114         ekin = std::max( 1.0e-6, ekin );
03115         xxh = 1.0;
03116         if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
03117               (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
03118             (vec[i]->GetDefinition() == aPiZero) &&
03119             (G4UniformRand() < logWeight) )xxh = exh;
03120         dekin += ekin*(1.0-xxh);
03121         ekin *= xxh;
03122         if( (vec[i]->GetDefinition() == aPiPlus) ||
03123             (vec[i]->GetDefinition() == aPiZero) ||
03124             (vec[i]->GetDefinition() == aPiMinus) )
03125         {
03126           ++npions;
03127           ek1 += ekin;
03128         }
03129         vec[i]->SetKineticEnergy( ekin*GeV );
03130         pp = vec[i]->GetTotalMomentum()/MeV;
03131         pp1 = vec[i]->GetMomentum().mag()/MeV;
03132         if( pp1 < 0.001*MeV )
03133         {
03134           rthnve = pi*G4UniformRand();
03135           phinve = twopi*G4UniformRand();
03136           vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03137                                pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03138                                pp*std::cos(rthnve)*MeV );
03139         }
03140         else
03141           vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
03142       }
03143     }
03144     if( (ek1 != 0.0) && (npions > 0) )
03145     {
03146       dekin = 1.0 + dekin/ek1;
03147       //
03148       //  first do the incident particle
03149       //
03150       if( (currentParticle.GetDefinition() == aPiPlus) ||
03151           (currentParticle.GetDefinition() == aPiZero) ||
03152           (currentParticle.GetDefinition() == aPiMinus) )
03153       {
03154         currentParticle.SetKineticEnergy(
03155          std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
03156         pp = currentParticle.GetTotalMomentum()/MeV;
03157         pp1 = currentParticle.GetMomentum().mag()/MeV;
03158         if( pp1 < 0.001 )
03159         {
03160           rthnve = pi*G4UniformRand();
03161           phinve = twopi*G4UniformRand();
03162           currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03163                                        pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03164                                        pp*std::cos(rthnve)*MeV );
03165         }
03166         else
03167           currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
03168       }
03169       /*      if( (targetParticle.GetDefinition() == aPiPlus) ||
03170           (targetParticle.GetDefinition() == aPiZero) ||
03171           (targetParticle.GetDefinition() == aPiMinus) )
03172       {
03173         targetParticle.SetKineticEnergy(
03174          std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
03175         pp = targetParticle.GetTotalMomentum()/MeV;
03176         pp1 = targetParticle.GetMomentum().mag()/MeV;
03177         if( pp1 < 0.001 )
03178         {
03179           rthnve = pi*G4UniformRand();
03180           phinve = twopi*G4UniformRand();
03181           targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03182                                       pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03183                                       pp*std::cos(rthnve)*MeV );
03184         }
03185         else
03186           targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
03187           }*/
03188       for( i=0; i<vecLen; ++i )
03189       {
03190         if( (vec[i]->GetDefinition() == aPiPlus) ||
03191             (vec[i]->GetDefinition() == aPiZero) ||
03192             (vec[i]->GetDefinition() == aPiMinus) )
03193         {
03194           vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
03195           pp = vec[i]->GetTotalMomentum()/MeV;
03196           pp1 = vec[i]->GetMomentum().mag()/MeV;
03197           if( pp1 < 0.001 )
03198           {
03199             rthnve = pi*G4UniformRand();
03200             phinve = twopi*G4UniformRand();
03201             vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
03202                                  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
03203                                  pp*std::cos(rthnve)*MeV );
03204           }
03205           else
03206             vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
03207         }
03208       }
03209     }
03210   }
03211  
03212  void FullModelReactionDynamics::AddBlackTrackParticles(
03213    const G4double epnb,            // GeV
03214    const G4int npnb,
03215    const G4double edta,            // GeV
03216    const G4int ndta,
03217    const G4double sprob,
03218    const G4double kineticMinimum,  // GeV
03219    const G4double kineticFactor,   // GeV
03220    const G4ReactionProduct &modifiedOriginal,
03221    G4double spall,
03222    const G4Nucleus &targetNucleus,
03223    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
03224    G4int &vecLen )
03225   {
03226     // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
03227     //
03228     // npnb is number of proton/neutron black track particles
03229     // ndta is the number of deuterons, tritons, and alphas produced
03230     // epnb is the kinetic energy available for proton/neutron black track particles
03231     // edta is the kinetic energy available for deuteron/triton/alpha particles
03232     //
03233     
03234     G4ParticleDefinition *aProton = G4Proton::Proton();
03235     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
03236     G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
03237     G4ParticleDefinition *aTriton = G4Triton::Triton();
03238     G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
03239     
03240     const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
03241     const G4double atomicWeight = targetNucleus.GetN();
03242     const G4double atomicNumber = targetNucleus.GetZ();
03243     
03244     const G4double ika1 = 3.6;
03245     const G4double ika2 = 35.56;
03246     const G4double ika3 = 6.45;
03247     const G4double sp1 = 1.066;
03248     
03249     G4int i;
03250     G4double pp;
03251     // G4double totalQ = 0;
03252     G4double kinCreated = 0;
03253     G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
03254     if( npnb > 0)  // first add protons and neutrons
03255     {
03256       G4double backwardKinetic = 0.0;
03257       G4int local_npnb = npnb;
03258       for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
03259       G4double ekin = epnb/local_npnb;
03260       
03261       for( i=0; i<local_npnb; ++i )
03262       {
03263         G4ReactionProduct * p1 = new G4ReactionProduct();
03264         if( backwardKinetic > epnb )
03265         {
03266           delete p1;
03267           break;    
03268         }
03269         G4double ran = G4UniformRand();
03270         G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
03271         if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
03272         backwardKinetic += kinetic;
03273         if( backwardKinetic > epnb )
03274           kinetic = std::max( kineticMinimum, epnb-(backwardKinetic-kinetic) );
03275         if( G4UniformRand() > (1.0-atomicNumber/atomicWeight) )
03276           p1->SetDefinition( aProton );
03277         else
03278           p1->SetDefinition( aNeutron );
03279         vec.SetElement( vecLen, p1 );
03280         ++spall;
03281         G4double cost = G4UniformRand() * 2.0 - 1.0;
03282         G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
03283         G4double phi = twopi * G4UniformRand();
03284         vec[vecLen]->SetNewlyAdded( true );
03285         vec[vecLen]->SetKineticEnergy( kinetic*GeV );
03286         kinCreated+=kinetic;
03287         pp = vec[vecLen]->GetTotalMomentum()/MeV;
03288         vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
03289                                     pp*sint*std::cos(phi)*MeV,
03290                                     pp*cost*MeV );
03291         vecLen++;
03292         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03293       }
03294       if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
03295       {
03296         G4double ekw = ekOriginal/GeV;
03297         G4int ika, kk = 0;
03298         if( ekw > 1.0 )ekw *= ekw;
03299         ekw = std::max( 0.1, ekw );
03300         ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/atomicWeight-ika2)/ika3)/ekw);
03301         if( ika > 0 )
03302         {
03303           for( i=(vecLen-1); i>=0; --i )
03304           {
03305             if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
03306             {
03307               vec[i]->SetDefinitionAndUpdateE( aNeutron );  // modified 22-Oct-97
03308               if( ++kk > ika )break;
03309             }
03310           }
03311         }
03312       }
03313     }
03314     if( ndta > 0 )    //  now, try to add deuterons, tritons and alphas
03315     {
03316       G4double backwardKinetic = 0.0;
03317       G4int local_ndta=ndta;
03318       for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
03319       G4double ekin = edta/local_ndta;
03320 
03321       for( i=0; i<local_ndta; ++i )
03322       {
03323         G4ReactionProduct *p2 = new G4ReactionProduct();
03324         if( backwardKinetic > edta )
03325         {
03326           delete p2;
03327           break;
03328         }
03329         G4double ran = G4UniformRand();
03330         G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
03331         if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
03332         backwardKinetic += kinetic;
03333         if( backwardKinetic > edta )kinetic = edta-(backwardKinetic-kinetic);
03334         if( kinetic < 0.0 )kinetic = kineticMinimum;
03335         G4double cost = 2.0*G4UniformRand() - 1.0;
03336         G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
03337         G4double phi = twopi*G4UniformRand();
03338         ran = G4UniformRand();
03339         if( ran <= 0.60 )
03340           p2->SetDefinition( aDeuteron );
03341         else if( ran <= 0.90 )
03342           p2->SetDefinition( aTriton );
03343         else
03344           p2->SetDefinition( anAlpha );
03345         spall += p2->GetMass()/GeV * sp1;
03346         if( spall > atomicWeight )
03347         {
03348           delete p2;
03349           break;
03350         }
03351         vec.SetElement( vecLen, p2 );
03352         vec[vecLen]->SetNewlyAdded( true );
03353         vec[vecLen]->SetKineticEnergy( kinetic*GeV );
03354         kinCreated+=kinetic;
03355         pp = vec[vecLen]->GetTotalMomentum()/MeV;
03356         vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
03357                                     pp*sint*std::cos(phi)*MeV,
03358                                     pp*cost*MeV );
03359       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03360       }
03361     }
03362     // G4double delta = epnb+edta - kinCreated;
03363   }
03364  
03365  void FullModelReactionDynamics::MomentumCheck(
03366    const G4ReactionProduct &modifiedOriginal,
03367    G4ReactionProduct &currentParticle,
03368    G4ReactionProduct &targetParticle,
03369    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
03370    G4int &vecLen )
03371   {
03372     const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
03373     G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
03374     G4double pMass;
03375     if( testMomentum >= pOriginal )
03376     {
03377       pMass = currentParticle.GetMass()/MeV;
03378       currentParticle.SetTotalEnergy(
03379        std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
03380       currentParticle.SetMomentum(
03381        currentParticle.GetMomentum() * (pOriginal/testMomentum) );
03382     }
03383     testMomentum = targetParticle.GetMomentum().mag()/MeV;
03384     if( testMomentum >= pOriginal )
03385     {
03386       pMass = targetParticle.GetMass()/MeV;
03387       targetParticle.SetTotalEnergy(
03388        std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
03389       targetParticle.SetMomentum(
03390        targetParticle.GetMomentum() * (pOriginal/testMomentum) );
03391     }
03392     for( G4int i=0; i<vecLen; ++i )
03393     {
03394       testMomentum = vec[i]->GetMomentum().mag()/MeV;
03395       if( testMomentum >= pOriginal )
03396       {
03397         pMass = vec[i]->GetMass()/MeV;
03398         vec[i]->SetTotalEnergy(
03399          std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
03400         vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
03401       }
03402     }
03403   }
03404 
03405  void FullModelReactionDynamics::ProduceStrangeParticlePairs(
03406    G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
03407    G4int &vecLen,
03408    const G4ReactionProduct &modifiedOriginal,
03409    const G4DynamicParticle *originalTarget, 
03410    G4ReactionProduct &currentParticle,
03411    G4ReactionProduct &targetParticle,
03412    G4bool &incidentHasChanged,
03413    G4bool &targetHasChanged )
03414   {
03415     // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
03416     //
03417     // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
03418     //                            K+ Y0, K0 Y+,  K0 Y-
03419     // For antibaryon induced reactions half of the cross sections KB YB
03420     // pairs are produced.  Charge is not conserved, no experimental data available
03421     // for exclusive reactions, therefore some average behaviour assumed.
03422     // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
03423     //
03424     if( vecLen == 0 )return;
03425     //
03426     // the following protects against annihilation processes
03427     //
03428     if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
03429     
03430     const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
03431     const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
03432     G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
03433     G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
03434                                         targetMass*targetMass +
03435                                         2.0*targetMass*etOriginal );  // GeV
03436     G4double currentMass = currentParticle.GetMass()/GeV;
03437     G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
03438     if( availableEnergy <= 1.0 )return;
03439     
03440     G4ParticleDefinition *aProton = G4Proton::Proton();
03441     G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
03442     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
03443     G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
03444     G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
03445     G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
03446     G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
03447     G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
03448     G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
03449     G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
03450     G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
03451     G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
03452     G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
03453     G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
03454     G4ParticleDefinition *aLambda = G4Lambda::Lambda();
03455     G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
03456     
03457     const G4double protonMass = aProton->GetPDGMass()/GeV;
03458     const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
03459     //
03460     // determine the center of mass energy bin
03461     //
03462     const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
03463 
03464     G4int ibin, i3, i4;
03465     G4double avk, avy, avn, ran;
03466     G4int i = 1;
03467     while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
03468     if( i == 12 )
03469       ibin = 11;
03470     else
03471       ibin = i;
03472     //
03473     // the fortran code chooses a random replacement of produced kaons
03474     //  but does not take into account charge conservation 
03475     //
03476     if( vecLen == 1 )  // we know that vecLen > 0
03477     {
03478       i3 = 0;
03479       i4 = 1;   // note that we will be adding a new secondary particle in this case only
03480     }
03481     else               // otherwise  0 <= i3,i4 < vecLen
03482     {
03483       G4double ran = G4UniformRand();
03484       while( ran == 1.0 )ran = G4UniformRand();
03485       i4 = i3 = G4int( vecLen*ran );
03486       while( i3 == i4 )
03487       {
03488         ran = G4UniformRand();
03489         while( ran == 1.0 )ran = G4UniformRand();
03490         i4 = G4int( vecLen*ran );
03491       }
03492     }
03493     //
03494     // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
03495     //
03496     const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
03497                                0.0975, 0.123, 0.28,  0.398,  0.495,  0.573 };
03498     const G4double avky[] = { 0.005, 0.03,  0.064, 0.095, 0.115, 0.13,
03499                               0.145, 0.155, 0.20,  0.205, 0.210, 0.212 };
03500     const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
03501                                0.04,    0.05,   0.12,   0.15,   0.18, 0.20 };
03502     
03503     avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03504       /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
03505     avk = std::exp(avk);
03506     
03507     avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03508       /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
03509     avy = std::exp(avy);
03510     
03511     avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
03512       /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
03513     avn = std::exp(avn);
03514     
03515     if( avk+avy+avn <= 0.0 )return;
03516     
03517     if( currentMass < protonMass )avy /= 2.0;
03518     if( targetMass < protonMass )avy = 0.0;
03519     avy += avk+avn;
03520     avk += avn;
03521     ran = G4UniformRand();
03522     if(  ran < avn )
03523     {
03524       if( availableEnergy < 2.0 )return;
03525       if( vecLen == 1 )                              // add a new secondary
03526       {
03527         G4ReactionProduct *p1 = new G4ReactionProduct;
03528         if( G4UniformRand() < 0.5 )
03529         {
03530           vec[0]->SetDefinition( aNeutron );
03531           p1->SetDefinition( anAntiNeutron );
03532           (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03533           vec[0]->SetMayBeKilled(false);
03534           p1->SetMayBeKilled(false);
03535         }
03536         else
03537         {
03538           vec[0]->SetDefinition( aProton );
03539           p1->SetDefinition( anAntiProton );
03540           (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03541           vec[0]->SetMayBeKilled(false);
03542           p1->SetMayBeKilled(false);
03543         }
03544         vec.SetElement( vecLen++, p1 );
03545       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03546       }
03547       else
03548       {                                             // replace two secondaries
03549         if( G4UniformRand() < 0.5 )
03550         {
03551           vec[i3]->SetDefinition( aNeutron );
03552           vec[i4]->SetDefinition( anAntiNeutron );
03553           vec[i3]->SetMayBeKilled(false);
03554           vec[i4]->SetMayBeKilled(false);
03555         }
03556         else
03557         {
03558           vec[i3]->SetDefinition( aProton );
03559           vec[i4]->SetDefinition( anAntiProton );
03560           vec[i3]->SetMayBeKilled(false);
03561           vec[i4]->SetMayBeKilled(false);
03562         }
03563       }
03564     }
03565     else if( ran < avk )
03566     {
03567       if( availableEnergy < 1.0 )return;
03568       
03569       const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
03570                                0.6875, 0.7500, 0.8750, 1.000 };
03571       const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
03572       const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
03573       ran = G4UniformRand();
03574       i = 0;
03575       while( (i<9) && (ran>=kkb[i]) )++i;
03576       if( i == 9 )return;
03577       //
03578       // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
03579       // charge       +  -   +  0   +  0   0  0   0  0   0  0   0  0   0  -   0  -
03580       //
03581       switch( ipakkb1[i] )
03582       {
03583        case 10:
03584          vec[i3]->SetDefinition( aKaonPlus );
03585          vec[i3]->SetMayBeKilled(false);
03586          break;
03587        case 11:
03588          vec[i3]->SetDefinition( aKaonZS );
03589          vec[i3]->SetMayBeKilled(false);
03590          break;
03591        case 12:
03592          vec[i3]->SetDefinition( aKaonZL );
03593          vec[i3]->SetMayBeKilled(false);
03594          break;
03595       }
03596       if( vecLen == 1 )                          // add a secondary
03597       {
03598         G4ReactionProduct *p1 = new G4ReactionProduct;
03599         switch( ipakkb2[i] )
03600         {
03601          case 11:
03602            p1->SetDefinition( aKaonZS );
03603            p1->SetMayBeKilled(false);
03604            break;
03605          case 12:
03606            p1->SetDefinition( aKaonZL );
03607            p1->SetMayBeKilled(false);
03608            break;
03609          case 13:
03610            p1->SetDefinition( aKaonMinus );
03611            p1->SetMayBeKilled(false);
03612            break;
03613         }
03614         (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
03615         vec.SetElement( vecLen++, p1 );
03616       // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
03617       }
03618       else                                        // replace
03619       {
03620         switch( ipakkb2[i] )
03621         {
03622          case 11:
03623            vec[i4]->SetDefinition( aKaonZS );
03624            vec[i4]->SetMayBeKilled(false);
03625            break;
03626          case 12:
03627            vec[i4]->SetDefinition( aKaonZL );
03628            vec[i4]->SetMayBeKilled(false);
03629            break;
03630          case 13:
03631            vec[i4]->SetDefinition( aKaonMinus );
03632            vec[i4]->SetMayBeKilled(false);
03633            break;
03634         }
03635       }
03636     }
03637     else if( ran < avy )
03638     {
03639       if( availableEnergy < 1.6 )return;
03640       
03641       const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
03642                               0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
03643       const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
03644       const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
03645       const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
03646       const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
03647       ran = G4UniformRand();
03648       i = 0;
03649       while( (i<12) && (ran>ky[i]) )++i;
03650       if( i == 12 )return;
03651       if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
03652       {
03653         // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
03654         //             0  +   0  0   0  0   +  +   +  0   +  0
03655         //
03656         //             21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
03657         //             0  +   0  0   0  0   -  +   -  0   -  0
03658         switch( ipaky1[i] )
03659         {
03660          case 18:
03661            targetParticle.SetDefinition( aLambda );
03662            break;
03663          case 20:
03664            targetParticle.SetDefinition( aSigmaPlus );
03665            break;
03666          case 21:
03667            targetParticle.SetDefinition( aSigmaZero );
03668            break;
03669          case 22:
03670            targetParticle.SetDefinition( aSigmaMinus );
03671            break;
03672         }
03673         targetHasChanged = true;
03674         switch( ipaky2[i] )
03675         {
03676          case 10:
03677            vec[i3]->SetDefinition( aKaonPlus ); 
03678            vec[i3]->SetMayBeKilled(false);
03679            break;
03680          case 11:
03681            vec[i3]->SetDefinition( aKaonZS );
03682            vec[i3]->SetMayBeKilled(false);
03683            break;
03684          case 12:
03685            vec[i3]->SetDefinition( aKaonZL );
03686            vec[i3]->SetMayBeKilled(false);
03687            break;
03688         }
03689       }
03690       else  // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
03691       {
03692         // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
03693         //              24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
03694         if( (currentParticle.GetDefinition() == anAntiProton) ||
03695             (currentParticle.GetDefinition() == anAntiNeutron) ||
03696             (currentParticle.GetDefinition() == anAntiLambda) ||
03697             (currentMass > sigmaMinusMass) )
03698         {
03699           switch( ipakyb1[i] )
03700           {
03701            case 19:
03702              currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
03703              break;
03704            case 23:
03705              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
03706              break;
03707            case 24:
03708              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
03709              break;
03710            case 25:
03711              currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
03712              break;
03713           }
03714           incidentHasChanged = true;
03715           switch( ipakyb2[i] )
03716           {
03717            case 11:
03718              vec[i3]->SetDefinition( aKaonZS ); 
03719              vec[i3]->SetMayBeKilled(false);
03720              break;
03721            case 12:
03722              vec[i3]->SetDefinition( aKaonZL );
03723              vec[i3]->SetMayBeKilled(false);
03724              break;
03725            case 13:
03726              vec[i3]->SetDefinition( aKaonMinus );
03727              vec[i3]->SetMayBeKilled(false);
03728              break;
03729           }
03730         }
03731         else
03732         {
03733           switch( ipaky1[i] )
03734           {
03735            case 18:
03736              currentParticle.SetDefinitionAndUpdateE( aLambda );
03737              break;
03738            case 20:
03739              currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
03740              break;
03741            case 21:
03742              currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
03743              break;
03744            case 22:
03745              currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
03746              break;
03747           }
03748           incidentHasChanged = true;
03749           switch( ipaky2[i] )
03750           {
03751            case 10:
03752              vec[i3]->SetDefinition( aKaonPlus ); 
03753              vec[i3]->SetMayBeKilled(false);
03754              break;
03755            case 11:
03756              vec[i3]->SetDefinition( aKaonZS );
03757              vec[i3]->SetMayBeKilled(false);
03758              break;
03759            case 12:
03760              vec[i3]->SetDefinition( aKaonZL );
03761              vec[i3]->SetMayBeKilled(false);
03762              break;
03763           }
03764         }
03765       }
03766     }
03767     else return;
03768     //
03769     //  check the available energy
03770     //   if there is not enough energy for kkb/ky pair production
03771     //   then reduce the number of secondary particles 
03772     //  NOTE:
03773     //        the number of secondaries may have been changed
03774     //        the incident and/or target particles may have changed
03775     //        charge conservation is ignored (as well as strangness conservation)
03776     //
03777     currentMass = currentParticle.GetMass()/GeV;
03778     targetMass = targetParticle.GetMass()/GeV;
03779     
03780     G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
03781     for( i=0; i<vecLen; ++i )
03782     {
03783       energyCheck -= vec[i]->GetMass()/GeV;
03784       if( energyCheck < 0.0 )      // chop off the secondary List
03785       {
03786         vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
03787         G4int j;
03788         for(j=i; j<vecLen; j++) delete vec[j];
03789         break;
03790       }
03791     }
03792     return;
03793   }
03794 
03795  void
03796   FullModelReactionDynamics::NuclearReaction(
03797    G4FastVector<G4ReactionProduct,4> &vec,
03798    G4int &vecLen,
03799    const G4HadProjectile *originalIncident,
03800    const G4Nucleus &targetNucleus,
03801    const G4double theAtomicMass,
03802    const G4double *mass )
03803   {
03804     // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
03805     //
03806     // Nuclear reaction kinematics at low energies
03807     //
03808     G4ParticleDefinition *aGamma = G4Gamma::Gamma();
03809     G4ParticleDefinition *aProton = G4Proton::Proton();
03810     G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
03811     G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
03812     G4ParticleDefinition *aTriton = G4Triton::Triton();
03813     G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
03814     
03815     const G4double aProtonMass = aProton->GetPDGMass()/MeV;
03816     const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
03817     const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
03818     const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
03819     const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
03820 
03821     G4ReactionProduct currentParticle;
03822     currentParticle = *originalIncident;
03823     //
03824     // Set beam particle, take kinetic energy of current particle as the
03825     // fundamental quantity.  Due to the difficult kinematic, all masses have to
03826     // be assigned the best measured values
03827     //
03828     G4double p = currentParticle.GetTotalMomentum();
03829     G4double pp = currentParticle.GetMomentum().mag();
03830     if( pp <= 0.001*MeV )
03831     {
03832       G4double phinve = twopi*G4UniformRand();
03833       G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
03834       currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
03835                                    p*std::sin(rthnve)*std::sin(phinve),
03836                                    p*std::cos(rthnve) );
03837     }
03838     else
03839       currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
03840     //
03841     // calculate Q-value of reactions
03842     //
03843     G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
03844     G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
03845     G4double qv = currentKinetic + theAtomicMass + currentMass;
03846     
03847     G4double qval[9];
03848     qval[0] = qv - mass[0];
03849     qval[1] = qv - mass[1] - aNeutronMass;
03850     qval[2] = qv - mass[2] - aProtonMass;
03851     qval[3] = qv - mass[3] - aDeuteronMass;
03852     qval[4] = qv - mass[4] - aTritonMass;
03853     qval[5] = qv - mass[5] - anAlphaMass;
03854     qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
03855     qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
03856     qval[8] = qv - mass[8] - aProtonMass  - aProtonMass;
03857     
03858     if( currentParticle.GetDefinition() == aNeutron )
03859     {
03860       const G4double A = targetNucleus.GetN();    // atomic weight
03861       if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
03862         qval[0] = 0.0;
03863       if( G4UniformRand() >= currentKinetic/7.9254*A )
03864         qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
03865     }
03866     else
03867       qval[0] = 0.0;
03868     
03869     G4int i;
03870     qv = 0.0;
03871     for( i=0; i<9; ++i )
03872     {
03873       if( mass[i] < 500.0*MeV )qval[i] = 0.0;
03874       if( qval[i] < 0.0 )qval[i] = 0.0;
03875       qv += qval[i];
03876     }
03877     G4double qv1 = 0.0;
03878     G4double ran = G4UniformRand();
03879     G4int index;
03880     for( index=0; index<9; ++index )
03881     {
03882       if( qval[index] > 0.0 )
03883       {
03884         qv1 += qval[index]/qv;
03885         if( ran <= qv1 )break;
03886       }
03887     }
03888     if( index == 9 )  // loop continued to the end
03889     {
03890       throw G4HadronicException(__FILE__, __LINE__,
03891            "FullModelReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
03892     }
03893     G4double ke = currentParticle.GetKineticEnergy()/GeV;
03894     G4int nt = 2;
03895     if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
03896     
03897     G4ReactionProduct **v = new G4ReactionProduct * [3];
03898     v[0] =  new G4ReactionProduct;
03899     v[1] =  new G4ReactionProduct;
03900     v[2] =  new G4ReactionProduct;
03901     
03902     v[0]->SetMass( mass[index]*MeV );
03903     switch( index )
03904     {
03905      case 0:
03906        v[1]->SetDefinition( aGamma );
03907        v[2]->SetDefinition( aGamma );
03908        break;
03909      case 1:
03910        v[1]->SetDefinition( aNeutron );
03911        v[2]->SetDefinition( aGamma );
03912        break;
03913      case 2:
03914        v[1]->SetDefinition( aProton );
03915        v[2]->SetDefinition( aGamma );
03916        break;
03917      case 3:
03918        v[1]->SetDefinition( aDeuteron );
03919        v[2]->SetDefinition( aGamma );
03920        break;
03921      case 4:
03922        v[1]->SetDefinition( aTriton );
03923        v[2]->SetDefinition( aGamma );
03924        break;
03925      case 5:
03926        v[1]->SetDefinition( anAlpha );
03927        v[2]->SetDefinition( aGamma );
03928        break;
03929      case 6:
03930        v[1]->SetDefinition( aNeutron );
03931        v[2]->SetDefinition( aNeutron );
03932        break;
03933      case 7:
03934        v[1]->SetDefinition( aNeutron );
03935        v[2]->SetDefinition( aProton );
03936        break;
03937      case 8:
03938        v[1]->SetDefinition( aProton );
03939        v[2]->SetDefinition( aProton );
03940        break;
03941     }
03942     //
03943     // calculate centre of mass energy
03944     //
03945     G4ReactionProduct pseudo1;
03946     pseudo1.SetMass( theAtomicMass*MeV );
03947     pseudo1.SetTotalEnergy( theAtomicMass*MeV );
03948     G4ReactionProduct pseudo2 = currentParticle + pseudo1;
03949     pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
03950     //
03951     // use phase space routine in centre of mass system
03952     //
03953     G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
03954     tempV.Initialize( nt );
03955     G4int tempLen = 0;
03956     tempV.SetElement( tempLen++, v[0] );
03957     tempV.SetElement( tempLen++, v[1] );
03958     if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
03959     G4bool constantCrossSection = true;
03960     GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
03961     v[0]->Lorentz( *v[0], pseudo2 );
03962     v[1]->Lorentz( *v[1], pseudo2 );
03963     if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
03964     
03965     G4bool particleIsDefined = false;
03966     if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
03967     {
03968       v[0]->SetDefinition( aProton );
03969       particleIsDefined = true;
03970     }
03971     else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
03972     {
03973       v[0]->SetDefinition( aNeutron );
03974       particleIsDefined = true;
03975     }
03976     else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
03977     {
03978       v[0]->SetDefinition( aDeuteron );
03979       particleIsDefined = true;
03980     }
03981     else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
03982     {
03983       v[0]->SetDefinition( aTriton );
03984       particleIsDefined = true;
03985     }
03986     else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
03987     {
03988       v[0]->SetDefinition( anAlpha );
03989       particleIsDefined = true;
03990     }
03991     currentParticle.SetKineticEnergy(
03992      std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
03993     p = currentParticle.GetTotalMomentum();
03994     pp = currentParticle.GetMomentum().mag();
03995     if( pp <= 0.001*MeV )
03996     {
03997       G4double phinve = twopi*G4UniformRand();
03998       G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
03999       currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04000                                    p*std::sin(rthnve)*std::sin(phinve),
04001                                    p*std::cos(rthnve) );
04002     }
04003     else
04004       currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
04005     
04006     if( particleIsDefined )
04007     {
04008       v[0]->SetKineticEnergy(
04009        std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
04010       p = v[0]->GetTotalMomentum();
04011       pp = v[0]->GetMomentum().mag();
04012       if( pp <= 0.001*MeV )
04013       {
04014         G4double phinve = twopi*G4UniformRand();
04015         G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
04016         v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04017                           p*std::sin(rthnve)*std::sin(phinve),
04018                           p*std::cos(rthnve) );
04019       }
04020       else
04021         v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
04022     }
04023     if( (v[1]->GetDefinition() == aDeuteron) ||
04024         (v[1]->GetDefinition() == aTriton)   ||
04025         (v[1]->GetDefinition() == anAlpha) ) 
04026       v[1]->SetKineticEnergy(
04027        std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
04028     else
04029       v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
04030     
04031     p = v[1]->GetTotalMomentum();
04032     pp = v[1]->GetMomentum().mag();
04033     if( pp <= 0.001*MeV )
04034     {
04035       G4double phinve = twopi*G4UniformRand();
04036       G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
04037       v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04038                         p*std::sin(rthnve)*std::sin(phinve),
04039                         p*std::cos(rthnve) );
04040     }
04041     else
04042       v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
04043     
04044     if( nt == 3 )
04045     {
04046       if( (v[2]->GetDefinition() == aDeuteron) ||
04047           (v[2]->GetDefinition() == aTriton)   ||
04048           (v[2]->GetDefinition() == anAlpha) ) 
04049         v[2]->SetKineticEnergy(
04050          std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
04051       else
04052         v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
04053       
04054       p = v[2]->GetTotalMomentum();
04055       pp = v[2]->GetMomentum().mag();
04056       if( pp <= 0.001*MeV )
04057       {
04058         G4double phinve = twopi*G4UniformRand();
04059         G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
04060         v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
04061                           p*std::sin(rthnve)*std::sin(phinve),
04062                           p*std::cos(rthnve) );
04063       }
04064       else
04065         v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
04066     }
04067     G4int del;
04068     for(del=0; del<vecLen; del++) delete vec[del];
04069     vecLen = 0;
04070     if( particleIsDefined )
04071     {
04072       vec.SetElement( vecLen++, v[0] );
04073     }
04074     else
04075     {
04076       delete v[0];
04077     }
04078     vec.SetElement( vecLen++, v[1] );
04079     if( nt == 3 )
04080     {
04081       vec.SetElement( vecLen++, v[2] );
04082     }
04083     else
04084     {
04085       delete v[2];
04086     }
04087     delete [] v;
04088     return;
04089   }
04090  
04091  /* end of file */
04092  

Generated on Tue Jun 9 17:47:02 2009 for CMSSW by  doxygen 1.5.4