source: trunk/source/processes/hadronic/util/src/G4ReactionDynamics.cc @ 819

Last change on this file since 819 was 819, checked in by garnier, 16 years ago

import all except CVS

File size: 154.0 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26//
27//
28 // Hadronic Process: Reaction Dynamics
29 // original by H.P. Wellisch
30 // modified by J.L. Chuma, TRIUMF, 19-Nov-1996
31 // Last modified: 27-Mar-1997
32 // modified by H.P. Wellisch, 24-Apr-97
33 // H.P. Wellisch, 25.Apr-97: Side of current and target particle taken into account
34 // H.P. Wellisch, 29.Apr-97: Bug fix in NuclearReaction. (pseudo1 was without energy)
35 // J.L. Chuma, 30-Apr-97:  Changed return value for GenerateXandPt.  It seems possible
36 //                         that GenerateXandPt could eliminate some secondaries, but
37 //                         still finish its calculations, thus we would not want to
38 //                         then use TwoCluster to again calculate the momenta if vecLen
39 //                         was less than 6.
40 // J.L. Chuma, 10-Jun-97:  Modified NuclearReaction.  Was not creating ReactionProduct's
41 //                         with the new operator, thus they would be meaningless when
42 //                         going out of scope.
43 // J.L. Chuma, 20-Jun-97:  Modified GenerateXandPt and TwoCluster to fix units problems
44 // J.L. Chuma, 23-Jun-97:  Modified ProduceStrangeParticlePairs to fix units problems
45 // J.L. Chuma, 26-Jun-97:  Modified ProduceStrangeParticlePairs to fix array indices
46 //                         which were sometimes going out of bounds
47 // J.L. Chuma, 04-Jul-97:  Many minor modifications to GenerateXandPt and TwoCluster
48 // J.L. Chuma, 06-Aug-97:  Added original incident particle, before Fermi motion and
49 //                         evaporation effects are included, needed for self absorption
50 //                         and corrections for single particle spectra (shower particles)
51 // logging stopped 1997
52 // J. Allison, 17-Jun-99:  Replaced a min function to get correct behaviour on DEC.
53 
54#include "G4ReactionDynamics.hh"
55#include "G4AntiProton.hh"
56#include "G4AntiNeutron.hh"
57#include "Randomize.hh"
58#include <iostream>
59#include "G4HadReentrentException.hh"
60#include <signal.h>
61
62// #include "DumpFrame.hh"
63
64/*         G4double GetQValue(G4ReactionProduct * aSec)
65           {
66             double QValue=0;
67             if(aSec->GetDefinition()->GetParticleType() == "baryon")
68             {
69               if(aSec->GetDefinition()->GetBaryonNumber() < 0)
70               {
71                 QValue = aSec->GetTotalEnergy();
72                 QValue += G4Neutron::Neutron()->GetPDGMass();
73               }
74               else
75               {
76                 G4double ss = 0;
77                 ss +=aSec->GetDefinition()->GetPDGMass();
78                 if(aSec->GetDefinition() == G4Proton::Proton())
79                 {
80                   ss -=G4Proton::Proton()->GetPDGMass();
81                 }
82                 else
83                 {
84                   ss -=G4Neutron::Neutron()->GetPDGMass();
85                 }
86                 ss += aSec->GetKineticEnergy();
87                 QValue = ss;
88               }
89             }
90             else if(aSec->GetDefinition()->GetPDGEncoding() == 0)
91             {
92               QValue = aSec->GetKineticEnergy();
93             }
94             else
95             {
96               QValue = aSec->GetTotalEnergy();
97             }
98             return QValue;
99           }
100*/
101 
102 G4bool G4ReactionDynamics::GenerateXandPt(
103   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
104   G4int &vecLen,
105   G4ReactionProduct &modifiedOriginal,   // Fermi motion & evap. effects included
106   const G4HadProjectile *originalIncident,   // the original incident particle
107   G4ReactionProduct &currentParticle,
108   G4ReactionProduct &targetParticle,
109   const G4DynamicParticle* originalTarget,
110   const G4Nucleus &targetNucleus,
111   G4bool &incidentHasChanged,
112   G4bool &targetHasChanged,
113   G4bool leadFlag,
114   G4ReactionProduct &leadingStrangeParticle )
115  {
116    //
117    // derived from original FORTRAN code GENXPT by H. Fesefeldt (11-Oct-1987)
118    //
119    //  Generation of X- and PT- values for incident, target, and all secondary particles
120    //  A simple single variable description E D3S/DP3= F(Q) with
121    //  Q^2 = (M*X)^2 + PT^2 is used. Final state kinematic is produced
122    //  by an FF-type iterative cascade method
123    //
124    //  internal units are GeV
125    //
126    // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
127   
128    // Protection in case no secondary has been created; cascades down to two-body.
129    if(vecLen == 0) return false;
130
131    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
132    G4ParticleDefinition *aProton = G4Proton::Proton();
133    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
134    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
135    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
136
137    G4int i, l;
138    G4bool veryForward = false;
139   
140    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
141    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
142    const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
143    const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
144    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
145    G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
146                                        targetMass*targetMass +
147                                        2.0*targetMass*etOriginal );  // GeV
148    G4double currentMass = currentParticle.GetMass()/GeV;
149    targetMass = targetParticle.GetMass()/GeV;
150    //
151    //  randomize the order of the secondary particles
152    //  note that the current and target particles are not affected
153    //
154    for( i=0; i<vecLen; ++i )
155    {
156      G4int itemp = G4int( G4UniformRand()*vecLen );
157      G4ReactionProduct pTemp = *vec[itemp];
158      *vec[itemp] = *vec[i];
159      *vec[i] = pTemp;
160      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
161    }
162
163    if( currentMass == 0.0 && targetMass == 0.0 )
164    {
165      // Target and projectile have annihilated.  Replace them with the first
166      // two secondaries in the list.  Current particle KE is maintained.
167 
168      G4double ek = currentParticle.GetKineticEnergy();
169      G4ThreeVector m = currentParticle.GetMomentum();
170      currentParticle = *vec[0];
171      targetParticle = *vec[1];
172      for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
173      G4ReactionProduct *temp = vec[vecLen-1];
174      delete temp;
175      temp = vec[vecLen-2];
176      delete temp;
177      vecLen -= 2;
178      currentMass = currentParticle.GetMass()/GeV;
179      targetMass = targetParticle.GetMass()/GeV;
180      incidentHasChanged = true;
181      targetHasChanged = true;
182      currentParticle.SetKineticEnergy( ek );
183      currentParticle.SetMomentum( m );
184      veryForward = true;
185    }
186    const G4double atomicWeight = targetNucleus.GetN();
187    const G4double atomicNumber = targetNucleus.GetZ();
188    const G4double protonMass = aProton->GetPDGMass()/MeV;
189
190    if (originalIncident->GetDefinition()->GetParticleSubType() == "kaon"
191        && G4UniformRand() >= 0.7) {
192      G4ReactionProduct temp = currentParticle;
193      currentParticle = targetParticle;
194      targetParticle = temp;
195      incidentHasChanged = true;
196      targetHasChanged = true;
197      currentMass = currentParticle.GetMass()/GeV;
198      targetMass = targetParticle.GetMass()/GeV;
199    }
200    const G4double afc = std::min( 0.75,
201          0.312+0.200*std::log(std::log(centerofmassEnergy*centerofmassEnergy))+
202          std::pow(centerofmassEnergy*centerofmassEnergy,1.5)/6000.0 );
203   
204    G4double freeEnergy = centerofmassEnergy-currentMass-targetMass;
205    G4double forwardEnergy = freeEnergy/2.;
206    G4int forwardCount = 1;         // number of particles in forward hemisphere
207   
208    G4double backwardEnergy = freeEnergy/2.;
209    G4int backwardCount = 1;        // number of particles in backward hemisphere
210
211    if(veryForward)
212    {
213      if(currentParticle.GetSide()==-1)
214      {
215        forwardEnergy += currentMass;
216        forwardCount --;
217        backwardEnergy -= currentMass;
218        backwardCount ++;
219      }
220      if(targetParticle.GetSide()!=-1)
221      {
222        backwardEnergy += targetMass;
223        backwardCount --;
224        forwardEnergy -= targetMass;
225        forwardCount ++;
226      }
227    }
228
229    for( i=0; i<vecLen; ++i )
230    {
231      if( vec[i]->GetSide() == -1 )
232      {
233        ++backwardCount;
234        backwardEnergy -= vec[i]->GetMass()/GeV;
235      } else {
236        ++forwardCount;
237        forwardEnergy -= vec[i]->GetMass()/GeV;
238      }
239    }
240    //
241    //  Add particles from intranuclear cascade.
242    //  nuclearExcitationCount = number of new secondaries produced by nuclear excitation
243    //  extraCount = number of nucleons within these new secondaries
244    //
245    G4double xtarg;
246    if( centerofmassEnergy < (2.0+G4UniformRand()) )
247      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount+vecLen+2)/2.0;
248    else
249      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount);
250    if( xtarg <= 0.0 )xtarg = 0.01;
251    G4int nuclearExcitationCount = Poisson( xtarg );
252    if(atomicWeight<1.0001) nuclearExcitationCount = 0;
253    G4int extraNucleonCount = 0;
254    G4double extraNucleonMass = 0.0;
255    if( nuclearExcitationCount > 0 )
256    {
257      const G4double nucsup[] = { 1.00, 0.7, 0.5, 0.4, 0.35, 0.3 };
258      const G4double psup[] = { 3., 6., 20., 50., 100., 1000. };
259      G4int momentumBin = 0;
260      while( (momentumBin < 6) &&
261             (modifiedOriginal.GetTotalMomentum()/GeV > psup[momentumBin]) )
262        ++momentumBin;
263      momentumBin = std::min( 5, momentumBin );
264      //
265      //  NOTE: in GENXPT, these new particles were given negative codes
266      //        here I use  NewlyAdded = true  instead
267      //
268
269      for( i=0; i<nuclearExcitationCount; ++i )
270      {
271        G4ReactionProduct * pVec = new G4ReactionProduct();
272        if( G4UniformRand() < nucsup[momentumBin] )
273        {
274          if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
275            pVec->SetDefinition( aProton );
276          else
277            pVec->SetDefinition( aNeutron );
278          pVec->SetSide( -2 );                // -2 means backside nucleon
279          ++extraNucleonCount;
280          backwardEnergy += pVec->GetMass()/GeV;
281          extraNucleonMass += pVec->GetMass()/GeV;
282        }
283        else
284        {
285          G4double ran = G4UniformRand();
286          if( ran < 0.3181 )
287            pVec->SetDefinition( aPiPlus );
288          else if( ran < 0.6819 )
289            pVec->SetDefinition( aPiZero );
290          else
291            pVec->SetDefinition( aPiMinus );
292          pVec->SetSide( -1 );                // backside particle, but not a nucleon
293        }
294        pVec->SetNewlyAdded( true );                // true is the same as IPA(i)<0
295        vec.SetElement( vecLen++, pVec );   
296        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
297        backwardEnergy -= pVec->GetMass()/GeV;
298        ++backwardCount;
299      }
300    }
301    //
302    //  assume conservation of kinetic energy in forward & backward hemispheres
303    //
304    G4int is, iskip;
305    while( forwardEnergy <= 0.0 )  // must eliminate a particle from the forward side
306    {
307      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
308      iskip = G4int(G4UniformRand()*forwardCount) + 1; // 1 <= iskip <= forwardCount
309      is = 0;
310      G4int forwardParticlesLeft = 0;
311      for( i=(vecLen-1); i>=0; --i )
312      {
313        if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
314        {
315          forwardParticlesLeft = 1; 
316          if( ++is == iskip )
317          { 
318            forwardEnergy += vec[i]->GetMass()/GeV;
319            for( G4int j=i; j<(vecLen-1); j++ )*vec[j] = *vec[j+1];    // shift up
320            --forwardCount;
321            delete vec[vecLen-1];
322            if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
323            break;  // --+
324          }         //   |
325        }           //   |
326      }             // break goes down to here
327      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
328      if( forwardParticlesLeft == 0 )
329      {
330        G4int iremove = -1;
331        for (G4int i = 0; i < vecLen; i++) {
332          if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
333            iremove = i;
334            break;
335          }
336        }
337        if (iremove == -1) {
338          for (G4int i = 0; i < vecLen; i++) {
339            if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
340              iremove = i;
341              break;
342            }
343          }
344        }
345        if (iremove == -1) iremove = 0;
346
347        forwardEnergy += vec[iremove]->GetMass()/GeV;
348        if (vec[iremove]->GetSide() > 0) --forwardCount;
349 
350        for (G4int i = iremove; i < vecLen-1; i++) *vec[i] = *vec[i+1];
351        delete vec[vecLen-1];
352        vecLen--;
353        if (vecLen == 0) return false;  // all secondaries have been eliminated
354        break;
355      }
356    } // while
357
358      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
359    while( backwardEnergy <= 0.0 )  // must eliminate a particle from the backward side
360    {
361      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
362      iskip = G4int(G4UniformRand()*backwardCount) + 1; // 1 <= iskip <= backwardCount
363      is = 0;
364      G4int backwardParticlesLeft = 0;
365      for( i=(vecLen-1); i>=0; --i )
366      {
367        if( vec[i]->GetSide() < 0 && vec[i]->GetMayBeKilled())
368        {
369          backwardParticlesLeft = 1;
370          if( ++is == iskip )        // eliminate the i'th particle
371          {
372            if( vec[i]->GetSide() == -2 )
373            {
374              --extraNucleonCount;
375              extraNucleonMass -= vec[i]->GetMass()/GeV;
376              backwardEnergy -= vec[i]->GetTotalEnergy()/GeV;
377            }
378            backwardEnergy += vec[i]->GetTotalEnergy()/GeV;
379            for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];   // shift up
380            --backwardCount;
381            delete vec[vecLen-1];
382            if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
383            break;
384          }
385        }
386      }
387      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
388      if( backwardParticlesLeft == 0 )
389      {
390        G4int iremove = -1;
391        for (G4int i = 0; i < vecLen; i++) {
392          if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
393            iremove = i;
394            break;
395          }
396        }
397        if (iremove == -1) {
398          for (G4int i = 0; i < vecLen; i++) {
399            if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
400              iremove = i;
401              break;
402            }
403          }
404        }
405        if (iremove == -1) iremove = 0;
406 
407        backwardEnergy += vec[iremove]->GetMass()/GeV;
408        if (vec[iremove]->GetSide() > 0) --backwardCount;
409 
410        for (G4int i = iremove; i < vecLen-1; i++) *vec[i] = *vec[i+1];
411        delete vec[vecLen-1];
412        vecLen--;
413        if (vecLen == 0) return false;  // all secondaries have been eliminated
414        break;
415      }
416    } // while
417
418      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
419    //
420    //  define initial state vectors for Lorentz transformations
421    //  the pseudoParticles have non-standard masses, hence the "pseudo"
422    //
423    G4ReactionProduct pseudoParticle[10];
424    for( i=0; i<10; ++i )pseudoParticle[i].SetZero();
425   
426    pseudoParticle[0].SetMass( mOriginal*GeV );
427    pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
428    pseudoParticle[0].SetTotalEnergy(
429     std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
430   
431    pseudoParticle[1].SetMass( protonMass*MeV );        // this could be targetMass
432    pseudoParticle[1].SetTotalEnergy( protonMass*MeV );
433   
434    pseudoParticle[3].SetMass( protonMass*(1+extraNucleonCount)*MeV );
435    pseudoParticle[3].SetTotalEnergy( protonMass*(1+extraNucleonCount)*MeV );
436   
437    pseudoParticle[8].SetMomentum( 1.0*GeV, 0.0, 0.0 );
438   
439    pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
440    pseudoParticle[3] = pseudoParticle[3] + pseudoParticle[0];
441   
442    pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
443    pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
444   
445    G4double dndl[20];
446    //
447    //  main loop for 4-momentum generation
448    //  see Pitha-report (Aachen) for a detailed description of the method
449    //
450    G4double aspar, pt, et, x, pp, pp1, rmb, wgt;
451    G4int    innerCounter, outerCounter;
452    G4bool   eliminateThisParticle, resetEnergies, constantCrossSection;
453   
454    G4double forwardKinetic = 0.0, backwardKinetic = 0.0;
455    //
456    // process the secondary particles in reverse order
457    // the incident particle is Done after the secondaries
458    // nucleons, including the target, in the backward hemisphere are also Done later
459    //
460    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,
461                         1.43,1.67,2.0,2.5,3.33,5.00,10.00};
462    G4int backwardNucleonCount = 0;       // number of nucleons in backward hemisphere
463    G4double totalEnergy, kineticEnergy, vecMass;
464
465    for( i=(vecLen-1); i>=0; --i )
466    {
467      G4double phi = G4UniformRand()*twopi;
468      if( vec[i]->GetNewlyAdded() )           // added from intranuclear cascade
469      {
470        if( vec[i]->GetSide() == -2 )         //  is a nucleon
471        {
472          if( backwardNucleonCount < 18 )
473          {
474            if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
475              for(G4int i=0; i<vecLen; i++) delete vec[i];
476              vecLen = 0;
477              throw G4HadReentrentException(__FILE__, __LINE__,
478              "G4ReactionDynamics::GenerateXandPt : a pion has been counted as a backward nucleon");
479            }
480            vec[i]->SetSide( -3 );
481            ++backwardNucleonCount;
482            continue;
483          }
484        }
485      }
486      //
487      //  set pt and phi values, they are changed somewhat in the iteration loop
488      //  set mass parameter for lambda fragmentation model
489      //
490      vecMass = vec[i]->GetMass()/GeV;
491      G4double ran = -std::log(1.0-G4UniformRand())/3.5;
492      if( vec[i]->GetSide() == -2 )   // backward nucleon
493      {
494        if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon" ||
495            vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
496          aspar = 0.75;
497          pt = std::sqrt( std::pow( ran, 1.7 ) );
498        } else {                          // vec[i] must be a proton, neutron,
499          aspar = 0.20;                   //  lambda, sigma, xsi, or ion
500          pt = std::sqrt( std::pow( ran, 1.2 ) );
501        }
502
503      } else {                          // not a backward nucleon
504
505        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
506          aspar = 0.75;
507          pt = std::sqrt( std::pow( ran, 1.7 ) );
508        } else if (vec[i]->GetDefinition()->GetParticleSubType() == "kaon") {
509          aspar = 0.70;
510          pt = std::sqrt( std::pow( ran, 1.7 ) );
511        } else {                        // vec[i] must be a proton, neutron,
512          aspar = 0.65;                 //  lambda, sigma, xsi, or ion
513          pt = std::sqrt( std::pow( ran, 1.5 ) );
514        }
515      }
516      pt = std::max( 0.001, pt );
517      vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
518      for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
519      if( vec[i]->GetSide() > 0 )
520        et = pseudoParticle[0].GetTotalEnergy()/GeV;
521      else
522        et = pseudoParticle[1].GetTotalEnergy()/GeV;
523      dndl[0] = 0.0;
524      //
525      //   start of outer iteration loop
526      //
527      outerCounter = 0;
528      eliminateThisParticle = true;
529      resetEnergies = true;
530      while( ++outerCounter < 3 )
531      {
532        for( l=1; l<20; ++l )
533        {
534          x = (binl[l]+binl[l-1])/2.;
535          pt = std::max( 0.001, pt );
536          if( x > 1.0/pt )
537            dndl[l] += dndl[l-1];   //  changed from just  =  on 02 April 98
538          else
539            dndl[l] = et * aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) )
540              * (binl[l]-binl[l-1]) / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass )
541              + dndl[l-1];
542        }
543        innerCounter = 0;
544        vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
545        //
546        //   start of inner iteration loop
547        //
548        while( ++innerCounter < 7 )
549        {
550          ran = G4UniformRand()*dndl[19];
551          l = 1;
552          while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
553          l = std::min( 19, l );
554          x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
555          if( vec[i]->GetSide() < 0 )x *= -1.;
556          vec[i]->SetMomentum( x*et*GeV );              // set the z-momentum
557          totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
558          vec[i]->SetTotalEnergy( totalEnergy*GeV );
559          kineticEnergy = vec[i]->GetKineticEnergy()/GeV;
560          if( vec[i]->GetSide() > 0 )                            // forward side
561          {
562            if( (forwardKinetic+kineticEnergy) < 0.95*forwardEnergy )
563            {
564              pseudoParticle[4] = pseudoParticle[4] + (*vec[i]);
565              forwardKinetic += kineticEnergy;
566              pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
567              pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
568              phi = pseudoParticle[6].Angle( pseudoParticle[8] );
569              if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
570              phi += pi + normal()*pi/12.0;
571              if( phi > twopi )phi -= twopi;
572              if( phi < 0.0 )phi = twopi - phi;
573              outerCounter = 2;                     // leave outer loop
574              eliminateThisParticle = false;        // don't eliminate this particle
575              resetEnergies = false;
576              break;                                // leave inner loop
577            }
578            if( innerCounter > 5 )break;           // leave inner loop
579            if( backwardEnergy >= vecMass )  // switch sides
580            {
581              vec[i]->SetSide( -1 );
582              forwardEnergy += vecMass;
583              backwardEnergy -= vecMass;
584              ++backwardCount;
585            }
586          } else {                                                 // backward side
587           if( extraNucleonCount > 19 )   // commented out to duplicate ?bug? in GENXPT
588             x = 0.999;
589           G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
590           if( (backwardKinetic+kineticEnergy) < xxx*backwardEnergy )
591            {
592              pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
593              backwardKinetic += kineticEnergy;
594              pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
595              pseudoParticle[6].SetMomentum( 0.0 );           // set the z-momentum
596              phi = pseudoParticle[6].Angle( pseudoParticle[8] );
597              if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
598              phi += pi + normal() * pi / 12.0;
599              if( phi > twopi )phi -= twopi;
600              if( phi < 0.0 )phi = twopi - phi;
601              outerCounter = 2;                    // leave outer loop
602              eliminateThisParticle = false;       // don't eliminate this particle
603              resetEnergies = false;
604              break;                               // leave inner loop
605            }
606            if( innerCounter > 5 )break;           // leave inner loop
607            if( forwardEnergy >= vecMass )  // switch sides
608            {
609              vec[i]->SetSide( 1 );
610              forwardEnergy -= vecMass;
611              backwardEnergy += vecMass;
612              backwardCount--;
613            }
614          }
615          G4ThreeVector momentum = vec[i]->GetMomentum();
616          vec[i]->SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
617          pt *= 0.9;
618          dndl[19] *= 0.9;
619        }                       // closes inner loop
620        if( resetEnergies )
621        {
622          //   if we get to here, the inner loop has been Done 6 Times
623          //   reset the kinetic energies of previously Done particles, if they are lighter
624          //    than protons and in the forward hemisphere
625          //   then continue with outer loop
626          //
627          forwardKinetic = 0.0;
628          backwardKinetic = 0.0;
629          pseudoParticle[4].SetZero();
630          pseudoParticle[5].SetZero();
631          for( l=i+1; l<vecLen; ++l )
632          {
633            if (vec[l]->GetSide() > 0 ||
634                vec[l]->GetDefinition()->GetParticleSubType() == "kaon" ||
635                vec[l]->GetDefinition()->GetParticleSubType() == "pi") {
636
637              G4double tempMass = vec[l]->GetMass()/MeV;
638              totalEnergy = 0.95*vec[l]->GetTotalEnergy()/MeV + 0.05*tempMass;
639              totalEnergy = std::max( tempMass, totalEnergy );
640              vec[l]->SetTotalEnergy( totalEnergy*MeV );
641              pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) );
642              pp1 = vec[l]->GetMomentum().mag()/MeV;
643              if( pp1 < 1.0e-6*GeV )
644              {
645                G4double costheta = 2.*G4UniformRand() - 1.;
646                G4double sintheta = std::sqrt(1. - costheta*costheta);
647                G4double phi = twopi*G4UniformRand();
648                vec[l]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
649                                     pp*sintheta*std::sin(phi)*MeV,
650                                     pp*costheta*MeV ) ;
651              } else {
652                vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
653              }
654              G4double px = vec[l]->GetMomentum().x()/MeV;
655              G4double py = vec[l]->GetMomentum().y()/MeV;
656              pt = std::max( 1.0, std::sqrt( px*px + py*py ) )/GeV;
657              if( vec[l]->GetSide() > 0 )
658              {
659                forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
660                pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
661              } else {
662                backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
663                pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
664              }
665            } // if pi, K or forward
666          } // for l
667        } // if resetEnergies
668      } // closes outer loop
669             
670      if( eliminateThisParticle && vec[i]->GetMayBeKilled())  // not enough energy, eliminate this particle
671      {
672        if( vec[i]->GetSide() > 0 )
673        {
674          --forwardCount;
675          forwardEnergy += vecMass;
676        } else {
677          if( vec[i]->GetSide() == -2 )
678          {
679            --extraNucleonCount;
680            extraNucleonMass -= vecMass;
681            backwardEnergy -= vecMass;
682          }
683          --backwardCount;
684          backwardEnergy += vecMass;
685        }
686        for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
687        G4ReactionProduct *temp = vec[vecLen-1];
688        delete temp;
689        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
690        if( --vecLen == 0 )return false;  // all the secondaries have been eliminated
691        pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
692        pseudoParticle[6].SetMomentum( 0.0 );                 // set z-momentum
693        phi = pseudoParticle[6].Angle( pseudoParticle[8] );
694        if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
695        phi += pi + normal() * pi / 12.0;
696        if( phi > twopi )phi -= twopi;
697        if( phi < 0.0 )phi = twopi - phi;
698      }
699    }   // closes main for loop
700
701    //
702    //  for the incident particle:  it was placed in the forward hemisphere
703    //   set pt and phi values, they are changed somewhat in the iteration loop
704    //   set mass parameter for lambda fragmentation model
705    //
706    G4double phi = G4UniformRand()*twopi;
707    G4double ran = -std::log(1.0-G4UniformRand());
708    if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
709      aspar = 0.60;
710      pt = std::sqrt( std::pow( ran/6.0, 1.7 ) );
711    } else if (currentParticle.GetDefinition()->GetParticleSubType() == "kaon") {
712      aspar = 0.50;
713      pt = std::sqrt( std::pow( ran/5.0, 1.4 ) );
714    } else {
715      aspar = 0.40;
716      pt = std::sqrt( std::pow( ran/4.0, 1.2 ) );
717    }
718
719    for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
720    currentParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
721    et = pseudoParticle[0].GetTotalEnergy()/GeV;
722    dndl[0] = 0.0;
723    vecMass = currentParticle.GetMass()/GeV;
724    for( l=1; l<20; ++l )
725    {
726      x = (binl[l]+binl[l-1])/2.;
727      if( x > 1.0/pt )
728        dndl[l] += dndl[l-1];   //  changed from just  =   on 02 April 98
729      else
730        dndl[l] = aspar/std::sqrt( std::pow((1.+sqr(aspar*x)),3) ) *
731          (binl[l]-binl[l-1]) * et / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass ) +
732          dndl[l-1];
733    }
734    ran = G4UniformRand()*dndl[19];
735    l = 1;
736    while( (ran>dndl[l]) && (l<20) )l++;
737    l = std::min( 19, l );
738    x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );   
739    currentParticle.SetMomentum( x*et*GeV );                 // set the z-momentum
740    if( forwardEnergy < forwardKinetic )
741      totalEnergy = vecMass + 0.04*std::fabs(normal());
742    else
743      totalEnergy = vecMass + forwardEnergy - forwardKinetic;
744    currentParticle.SetTotalEnergy( totalEnergy*GeV );
745    pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
746    pp1 = currentParticle.GetMomentum().mag()/MeV;
747    if( pp1 < 1.0e-6*GeV )
748    {
749      G4double costheta = 2.*G4UniformRand() - 1.;
750      G4double sintheta = std::sqrt(1. - costheta*costheta);
751      G4double phi = twopi*G4UniformRand();
752      currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
753                                   pp*sintheta*std::sin(phi)*MeV,
754                                   pp*costheta*MeV ) ;
755    } else {
756      currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
757    }
758    pseudoParticle[4] = pseudoParticle[4] + currentParticle;
759
760    //
761    // Current particle now finished
762    //
763    // Begin target particle
764    //
765
766    if( backwardNucleonCount < 18 )
767    {
768      targetParticle.SetSide( -3 );
769      ++backwardNucleonCount;
770    }
771    else
772    {
773      //  set pt and phi values, they are changed somewhat in the iteration loop
774      //  set mass parameter for lambda fragmentation model
775      //
776      vecMass = targetParticle.GetMass()/GeV;
777      ran = -std::log(1.0-G4UniformRand());
778      aspar = 0.40;
779      pt = std::max( 0.001, std::sqrt( std::pow( ran/4.0, 1.2 ) ) );
780      targetParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
781      for( G4int j=0; j<20; ++j )binl[j] = (j-1.)/(19.*pt);
782      et = pseudoParticle[1].GetTotalEnergy()/GeV;
783      dndl[0] = 0.0;
784      outerCounter = 0;
785      eliminateThisParticle = true;     // should never eliminate the target particle
786      resetEnergies = true;
787      while( ++outerCounter < 3 )     // start of outer iteration loop
788      {
789        for( l=1; l<20; ++l )
790        {
791          x = (binl[l]+binl[l-1])/2.;
792          if( x > 1.0/pt )
793            dndl[l] += dndl[l-1];   // changed from just  =  on 02 April 98
794          else
795            dndl[l] = aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) ) *
796              (binl[l]-binl[l-1])*et / std::sqrt( pt*x*et*pt*x*et+pt*pt+vecMass*vecMass ) +
797              dndl[l-1];
798        }
799        innerCounter = 0;
800        while( ++innerCounter < 7 )    // start of inner iteration loop
801        {
802          l = 1;
803          ran = G4UniformRand()*dndl[19];
804          while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
805          l = std::min( 19, l );
806          x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
807          if( targetParticle.GetSide() < 0 )x *= -1.;
808          targetParticle.SetMomentum( x*et*GeV );                // set the z-momentum
809          totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
810          targetParticle.SetTotalEnergy( totalEnergy*GeV );
811          if( targetParticle.GetSide() < 0 )
812          {
813            if( extraNucleonCount > 19 )x=0.999;
814            G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
815            if( (backwardKinetic+totalEnergy-vecMass) < xxx*backwardEnergy )
816            {
817              pseudoParticle[5] = pseudoParticle[5] + targetParticle;
818              backwardKinetic += totalEnergy - vecMass;
819              pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
820              pseudoParticle[6].SetMomentum( 0.0 );                      // set z-momentum
821              phi = pseudoParticle[6].Angle( pseudoParticle[8] );
822              if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
823              phi += pi + normal() * pi / 12.0;
824              if( phi > twopi )phi -= twopi;
825              if( phi < 0.0 )phi = twopi - phi;
826              outerCounter = 2;                    // leave outer loop
827              eliminateThisParticle = false;       // don't eliminate this particle
828              resetEnergies = false;
829              break;                               // leave inner loop
830            }
831            if( innerCounter > 5 )break;           // leave inner loop
832            if( forwardEnergy >= vecMass )  // switch sides
833            {
834              targetParticle.SetSide( 1 );
835              forwardEnergy -= vecMass;
836              backwardEnergy += vecMass;
837              --backwardCount;
838            }
839            G4ThreeVector momentum = targetParticle.GetMomentum();
840            targetParticle.SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
841            pt *= 0.9;
842            dndl[19] *= 0.9;
843          }
844          else                    // target has gone to forward side
845          {
846            if( forwardEnergy < forwardKinetic )
847              totalEnergy = vecMass + 0.04*std::fabs(normal());
848            else
849              totalEnergy = vecMass + forwardEnergy - forwardKinetic;
850            targetParticle.SetTotalEnergy( totalEnergy*GeV );
851            pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
852            pp1 = targetParticle.GetMomentum().mag()/MeV;
853            if( pp1 < 1.0e-6*GeV )
854            {
855              G4double costheta = 2.*G4UniformRand() - 1.;
856              G4double sintheta = std::sqrt(1. - costheta*costheta);
857              G4double phi = twopi*G4UniformRand();
858              targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
859                                          pp*sintheta*std::sin(phi)*MeV,
860                                          pp*costheta*MeV ) ;
861            }
862            else
863              targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
864
865            pseudoParticle[4] = pseudoParticle[4] + targetParticle;
866            outerCounter = 2;                    // leave outer loop
867            eliminateThisParticle = false;       // don't eliminate this particle
868            resetEnergies = false;
869            break;                               // leave inner loop
870          }
871        }    // closes inner loop
872        if( resetEnergies )
873        {
874          //   if we get to here, the inner loop has been Done 6 Times
875          //   reset the kinetic energies of previously Done particles, if they are lighter
876          //    than protons and in the forward hemisphere
877          //   then continue with outer loop
878         
879          forwardKinetic = backwardKinetic = 0.0;
880          pseudoParticle[4].SetZero();
881          pseudoParticle[5].SetZero();
882          for( l=0; l<vecLen; ++l ) // changed from l=1  on 02 April 98
883          {
884            if (vec[l]->GetSide() > 0 ||
885                vec[l]->GetDefinition()->GetParticleSubType() == "kaon" ||
886                vec[l]->GetDefinition()->GetParticleSubType() == "pi") {
887              G4double tempMass = vec[l]->GetMass()/GeV;
888              totalEnergy =
889                std::max( tempMass, 0.95*vec[l]->GetTotalEnergy()/GeV + 0.05*tempMass );
890              vec[l]->SetTotalEnergy( totalEnergy*GeV );
891              pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) )*GeV;
892              pp1 = vec[l]->GetMomentum().mag()/MeV;
893              if( pp1 < 1.0e-6*GeV )
894              {
895                G4double costheta = 2.*G4UniformRand() - 1.;
896                G4double sintheta = std::sqrt(1. - costheta*costheta);
897                G4double phi = twopi*G4UniformRand();
898                vec[l]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
899                                     pp*sintheta*std::sin(phi)*MeV,
900                                     pp*costheta*MeV ) ;
901              }
902              else
903                vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
904
905              pt = std::max( 0.001*GeV, std::sqrt( sqr(vec[l]->GetMomentum().x()/MeV) +
906                                         sqr(vec[l]->GetMomentum().y()/MeV) ) )/GeV;
907              if( vec[l]->GetSide() > 0)
908              {
909                forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
910                pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
911              } else {
912                backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
913                pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
914              }
915            } // if pi, K or forward
916          } // for l
917        } // if (resetEnergies)
918      } // closes outer loop
919
920//      if( eliminateThisParticle )  // not enough energy, eliminate target
921//      {
922//        G4cerr << "Warning: eliminating target particle" << G4endl;
923//        exit( EXIT_FAILURE );
924//      }
925    }
926    //
927    // Target particle finished.
928    //
929    // Now produce backward nucleons with a cluster model
930    //
931    pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
932    pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
933    pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
934    if( backwardNucleonCount == 1 )  // target particle is the only backward nucleon
935    {
936      G4double ekin =
937        std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
938
939      if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
940      vecMass = targetParticle.GetMass()/GeV;
941      totalEnergy = ekin+vecMass;
942      targetParticle.SetTotalEnergy( totalEnergy*GeV );
943      pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
944      pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
945      if( pp1 < 1.0e-6*GeV )
946      { 
947        G4double costheta = 2.*G4UniformRand() - 1.;
948        G4double sintheta = std::sqrt(1. - costheta*costheta);
949        G4double phi = twopi*G4UniformRand();
950        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
951                                    pp*sintheta*std::sin(phi)*MeV,
952                                    pp*costheta*MeV ) ;
953      } else {
954        targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
955      }
956      pseudoParticle[5] = pseudoParticle[5] + targetParticle;
957    }
958    else  // more than one backward nucleon
959    {
960      const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
961      const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
962      // Replaced the following min function to get correct behaviour on DEC.
963      // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
964      G4int tempCount;
965      if (backwardNucleonCount < 5)
966        {
967          tempCount = backwardNucleonCount;
968        }
969      else
970        {
971          tempCount = 5;
972        }
973      tempCount--;
974      //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
975      //cout << "tempCount " << tempCount << G4endl;
976      G4double rmb0 = 0.0;
977      if( targetParticle.GetSide() == -3 )
978        rmb0 += targetParticle.GetMass()/GeV;
979      for( i=0; i<vecLen; ++i )
980      {
981        if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
982      }
983      rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
984      totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
985      vecMass = std::min( rmb, totalEnergy );
986      pseudoParticle[6].SetMass( vecMass*GeV );
987      pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
988      pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
989      if( pp1 < 1.0e-6*GeV )
990      {
991        G4double costheta = 2.*G4UniformRand() - 1.;
992        G4double sintheta = std::sqrt(1. - costheta*costheta);
993        G4double phi = twopi*G4UniformRand();
994        pseudoParticle[6].SetMomentum( -pp*sintheta*std::cos(phi)*MeV,
995                                       -pp*sintheta*std::sin(phi)*MeV,
996                                       -pp*costheta*MeV ) ;
997      }
998      else
999        pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
1000     
1001      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;  // tempV contains the backward nucleons
1002      tempV.Initialize( backwardNucleonCount );
1003      G4int tempLen = 0;
1004      if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
1005      for( i=0; i<vecLen; ++i )
1006      {
1007        if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
1008      }
1009      if( tempLen != backwardNucleonCount )
1010      {
1011        G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
1012        G4cerr << "tempLen = " << tempLen;
1013        G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
1014        G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
1015        G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
1016        for( i=0; i<vecLen; ++i )
1017          G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
1018        exit( EXIT_FAILURE );
1019      }
1020      constantCrossSection = true;
1021      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1022      if( tempLen >= 2 )
1023      {
1024        wgt = GenerateNBodyEvent(
1025         pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
1026         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1027        if( targetParticle.GetSide() == -3 )
1028        {
1029          targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1030          // tempV contains the real stuff
1031          pseudoParticle[5] = pseudoParticle[5] + targetParticle;
1032        }
1033        for( i=0; i<vecLen; ++i )
1034        {
1035          if( vec[i]->GetSide() == -3 )
1036          {
1037            vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1038            pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
1039          }
1040        }
1041      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1042      }
1043    }
1044    //
1045    //  Lorentz transformation in lab system
1046    //
1047    if( vecLen == 0 )return false;  // all the secondaries have been eliminated
1048      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1049   
1050    currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
1051    targetParticle.Lorentz( targetParticle, pseudoParticle[1] );   
1052    for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
1053
1054      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1055    //
1056    // leadFlag will be true
1057    //  iff original particle is at least as heavy as K+ and not a proton or
1058    //  neutron AND if incident particle is at least as heavy as K+ and it is
1059    //  not a proton or neutron leadFlag is set to the incident particle
1060    //  or
1061    //  target particle is at least as heavy as K+ and it is not a proton or
1062    //  neutron leadFlag is set to the target particle
1063    //
1064    G4bool leadingStrangeParticleHasChanged = true;
1065    if( leadFlag )
1066    {
1067      if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1068        leadingStrangeParticleHasChanged = false;
1069      if( leadingStrangeParticleHasChanged &&
1070          ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
1071        leadingStrangeParticleHasChanged = false;
1072      if( leadingStrangeParticleHasChanged )
1073      {
1074        for( i=0; i<vecLen; i++ )
1075        {
1076          if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1077          {
1078            leadingStrangeParticleHasChanged = false;
1079            break;
1080          }
1081        }
1082      }
1083      if( leadingStrangeParticleHasChanged )
1084      {
1085        G4bool leadTest = 
1086          (leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1087           leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "pi");
1088        G4bool targetTest =
1089          (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1090           targetParticle.GetDefinition()->GetParticleSubType() == "pi");
1091       
1092        // following modified by JLC 22-Oct-97
1093         
1094        if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
1095        {
1096          targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1097          targetHasChanged = true;
1098      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1099        }
1100        else
1101        {
1102          currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1103          incidentHasChanged = false;
1104      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1105        }
1106      }
1107    }   // end of if( leadFlag )
1108
1109    // Get number of final state nucleons and nucleons remaining in
1110    // target nucleus
1111   
1112    std::pair<G4int, G4int> finalStateNucleons = 
1113      GetFinalStateNucleons(originalTarget, vec, vecLen);
1114
1115    G4int protonsInFinalState = finalStateNucleons.first;
1116    G4int neutronsInFinalState = finalStateNucleons.second;
1117
1118    G4int numberofFinalStateNucleons = 
1119      protonsInFinalState + neutronsInFinalState;
1120
1121    if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1122        targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1123        originalIncident->GetDefinition()->GetPDGMass() < 
1124                                   G4Lambda::Lambda()->GetPDGMass())
1125      numberofFinalStateNucleons++;
1126
1127    numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
1128
1129    G4int PinNucleus = std::max(0, 
1130      G4int(targetNucleus.GetZ()) - protonsInFinalState);
1131    G4int NinNucleus = std::max(0,
1132      G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
1133
1134    pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1135    pseudoParticle[3].SetMass( mOriginal*GeV );
1136    pseudoParticle[3].SetTotalEnergy(
1137     std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
1138   
1139    G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
1140    G4int diff = 0;
1141    if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
1142    if(numberofFinalStateNucleons == 1) diff = 0;
1143    pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
1144    pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1145    pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1146   
1147    G4double theoreticalKinetic =
1148      pseudoParticle[3].GetTotalEnergy()/MeV +
1149      pseudoParticle[4].GetTotalEnergy()/MeV -
1150      currentParticle.GetMass()/MeV -
1151      targetParticle.GetMass()/MeV;
1152   
1153    G4double simulatedKinetic =
1154      currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
1155   
1156    pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
1157    pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
1158    pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
1159   
1160    pseudoParticle[7].SetZero();
1161    pseudoParticle[7] = pseudoParticle[7] + currentParticle;
1162    pseudoParticle[7] = pseudoParticle[7] + targetParticle;
1163
1164    for( i=0; i<vecLen; ++i )
1165    {
1166      pseudoParticle[7] = pseudoParticle[7] + *vec[i];
1167      simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
1168      theoreticalKinetic -= vec[i]->GetMass()/MeV;
1169    }
1170
1171    if( vecLen <= 16 && vecLen > 0 )
1172    {
1173      // must create a new set of ReactionProducts here because GenerateNBody will
1174      // modify the momenta for the particles, and we don't want to do this
1175      //
1176      G4ReactionProduct tempR[130];
1177      tempR[0] = currentParticle;
1178      tempR[1] = targetParticle;
1179      for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
1180      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1181      tempV.Initialize( vecLen+2 );
1182      G4int tempLen = 0;
1183      for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
1184      constantCrossSection = true;
1185
1186      wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
1187                                pseudoParticle[4].GetTotalEnergy()/MeV,
1188                                constantCrossSection, tempV, tempLen );
1189      if (wgt == -1) {
1190        G4double Qvalue = 0;
1191        for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
1192        wgt = GenerateNBodyEvent( Qvalue/MeV,
1193                                  constantCrossSection, tempV, tempLen );
1194      }
1195      if(wgt>-.5)
1196      {
1197        theoreticalKinetic = 0.0;
1198        for( i=0; i<tempLen; ++i )
1199        {
1200          pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
1201          theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
1202        }
1203      }
1204      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1205    }
1206    //
1207    //  Make sure, that the kinetic energies are correct
1208    //
1209    if( simulatedKinetic != 0.0 )
1210    {
1211      wgt = (theoreticalKinetic)/simulatedKinetic;
1212      theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
1213      simulatedKinetic = theoreticalKinetic;
1214      currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1215      pp = currentParticle.GetTotalMomentum()/MeV;
1216      pp1 = currentParticle.GetMomentum().mag()/MeV;
1217      if( pp1 < 1.0e-6*GeV )
1218      {
1219        G4double costheta = 2.*G4UniformRand() - 1.;
1220        G4double sintheta = std::sqrt(1. - costheta*costheta);
1221        G4double phi = twopi*G4UniformRand();
1222        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1223                                     pp*sintheta*std::sin(phi)*MeV,
1224                                     pp*costheta*MeV ) ;
1225      }
1226      else
1227      {
1228        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
1229      }
1230      theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
1231      targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1232      simulatedKinetic += theoreticalKinetic;
1233      pp = targetParticle.GetTotalMomentum()/MeV;
1234      pp1 = targetParticle.GetMomentum().mag()/MeV;
1235      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1236      if( pp1 < 1.0e-6*GeV )
1237      {
1238        G4double costheta = 2.*G4UniformRand() - 1.;
1239        G4double sintheta = std::sqrt(1. - costheta*costheta);
1240        G4double phi = twopi*G4UniformRand();
1241        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1242                                    pp*sintheta*std::sin(phi)*MeV,
1243                                    pp*costheta*MeV ) ;
1244      } else {
1245        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1246      }
1247      for( i=0; i<vecLen; ++i )
1248      {
1249        theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
1250        simulatedKinetic += theoreticalKinetic;
1251        vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
1252        pp = vec[i]->GetTotalMomentum()/MeV;
1253        pp1 = vec[i]->GetMomentum().mag()/MeV;
1254        if( pp1 < 1.0e-6*GeV )
1255        {
1256          G4double costheta = 2.*G4UniformRand() - 1.;
1257          G4double sintheta = std::sqrt(1. - costheta*costheta);
1258          G4double phi = twopi*G4UniformRand();
1259          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1260                               pp*sintheta*std::sin(phi)*MeV,
1261                               pp*costheta*MeV ) ;
1262        }
1263        else
1264          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
1265      }
1266    }
1267      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1268
1269    Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
1270            modifiedOriginal, originalIncident, targetNucleus,
1271            currentParticle, targetParticle, vec, vecLen );
1272      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1273    //
1274    // add black track particles
1275    // the total number of particles produced is restricted to 198
1276    // this may have influence on very high energies
1277    //
1278    if( atomicWeight >= 1.5 )
1279    {
1280      // npnb is number of proton/neutron black track particles
1281      // ndta is the number of deuterons, tritons, and alphas produced
1282      // epnb is the kinetic energy available for proton/neutron black track particles
1283      // edta is the kinetic energy available for deuteron/triton/alpha particles
1284      //
1285      G4int npnb = 0;
1286      G4int ndta = 0;
1287     
1288      G4double epnb, edta;
1289      if (veryForward) {
1290        epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
1291        edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
1292      } else {
1293        epnb = targetNucleus.GetPNBlackTrackEnergy();
1294        edta = targetNucleus.GetDTABlackTrackEnergy();
1295      }
1296
1297      const G4double pnCutOff = 0.001;
1298      const G4double dtaCutOff = 0.001;
1299      const G4double kineticMinimum = 1.e-6;
1300      const G4double kineticFactor = -0.010;
1301      G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
1302      const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
1303      if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
1304      if( epnb >= pnCutOff )
1305      {
1306        npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
1307        if( numberofFinalStateNucleons + npnb > atomicWeight )
1308          npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
1309        npnb = std::min( npnb, 127-vecLen );
1310      }
1311      if( edta >= dtaCutOff )
1312      {
1313        ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
1314        ndta = std::min( ndta, 127-vecLen );
1315      }
1316      if (npnb == 0 && ndta == 0) npnb = 1;
1317
1318      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1319
1320      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
1321                             kineticFactor, modifiedOriginal,
1322                             PinNucleus, NinNucleus, targetNucleus,
1323                             vec, vecLen);
1324
1325      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1326    }
1327    //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
1328    //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
1329    //
1330    //  calculate time delay for nuclear reactions
1331    //
1332    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
1333      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
1334    else
1335      currentParticle.SetTOF( 1.0 );
1336    return true;
1337      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1338  }
1339 
1340 void G4ReactionDynamics::SuppressChargedPions(
1341   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1342   G4int &vecLen,
1343   const G4ReactionProduct &modifiedOriginal,
1344   G4ReactionProduct &currentParticle,
1345   G4ReactionProduct &targetParticle,
1346   const G4Nucleus &targetNucleus,
1347   G4bool &incidentHasChanged,
1348   G4bool &targetHasChanged )
1349  {
1350    // this code was originally in the fortran code TWOCLU
1351    //
1352    // suppress charged pions, for various reasons
1353    //
1354    G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1355    G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1356    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1357    G4double cmEnergy = std::sqrt( mOriginal*mOriginal + targetMass*targetMass +
1358                                   2.0*targetMass*etOriginal ); 
1359    G4double eAvailable = cmEnergy - mOriginal - targetMass;
1360    for (G4int i = 0; i < vecLen; i++) eAvailable -= vec[i]->GetMass()/GeV;
1361
1362    const G4double atomicWeight = targetNucleus.GetN();
1363    const G4double atomicNumber = targetNucleus.GetZ();
1364    const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
1365   
1366    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1367    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1368    G4ParticleDefinition* aPiZero = G4PionZero::PionZero();
1369    G4ParticleDefinition *aProton = G4Proton::Proton();
1370    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1371    G4double piMass = aPiPlus->GetPDGMass()/GeV;
1372    G4double nucleonMass = aNeutron->GetPDGMass()/GeV;
1373   
1374    const G4bool antiTest =
1375      modifiedOriginal.GetDefinition() != G4AntiProton::AntiProton() &&
1376      modifiedOriginal.GetDefinition() != G4AntiNeutron::AntiNeutron() &&
1377      modifiedOriginal.GetDefinition() != G4AntiLambda::AntiLambda() &&
1378      modifiedOriginal.GetDefinition() != G4AntiSigmaPlus::AntiSigmaPlus() &&
1379      modifiedOriginal.GetDefinition() != G4AntiSigmaMinus::AntiSigmaMinus() &&
1380      modifiedOriginal.GetDefinition() != G4AntiXiZero::AntiXiZero() &&
1381      modifiedOriginal.GetDefinition() != G4AntiXiMinus::AntiXiMinus() &&
1382      modifiedOriginal.GetDefinition() != G4AntiOmegaMinus::AntiOmegaMinus();
1383
1384    if( antiTest && (
1385          currentParticle.GetDefinition() == aPiPlus ||
1386          currentParticle.GetDefinition() == aPiZero ||
1387          currentParticle.GetDefinition() == aPiMinus ) &&
1388        ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1389        ( G4UniformRand() <= atomicWeight/300.0 ) )
1390    {
1391      if (eAvailable > nucleonMass - piMass) {
1392        if( G4UniformRand() > atomicNumber/atomicWeight )
1393          currentParticle.SetDefinitionAndUpdateE( aNeutron );
1394        else
1395          currentParticle.SetDefinitionAndUpdateE( aProton );
1396        incidentHasChanged = true;
1397      }
1398    }
1399    if( antiTest && (
1400          targetParticle.GetDefinition() == aPiPlus ||
1401          targetParticle.GetDefinition() == aPiZero ||
1402          targetParticle.GetDefinition() == aPiMinus ) &&
1403        ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1404        ( G4UniformRand() <= atomicWeight/300.0 ) )
1405    {
1406      if (eAvailable > nucleonMass - piMass) {
1407        if( G4UniformRand() > atomicNumber/atomicWeight )
1408          targetParticle.SetDefinitionAndUpdateE( aNeutron );
1409        else
1410          targetParticle.SetDefinitionAndUpdateE( aProton );
1411        targetHasChanged = true;
1412      }
1413    }
1414      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1415    for( G4int i=0; i<vecLen; ++i )
1416    {
1417      if( antiTest && (
1418            vec[i]->GetDefinition() == aPiPlus ||
1419            vec[i]->GetDefinition() == aPiZero ||
1420            vec[i]->GetDefinition() == aPiMinus ) &&
1421          ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1422          ( G4UniformRand() <= atomicWeight/300.0 ) )
1423      {
1424        if (eAvailable > nucleonMass - piMass) {
1425          if( G4UniformRand() > atomicNumber/atomicWeight )
1426            vec[i]->SetDefinitionAndUpdateE( aNeutron );
1427          else
1428            vec[i]->SetDefinitionAndUpdateE( aProton );
1429        }
1430      }
1431    }
1432      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1433  }
1434 
1435 G4bool G4ReactionDynamics::TwoCluster(
1436   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1437   G4int &vecLen,
1438   G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
1439   const G4HadProjectile *originalIncident, // the original incident particle
1440   G4ReactionProduct &currentParticle,
1441   G4ReactionProduct &targetParticle,
1442   const G4DynamicParticle* originalTarget,
1443   const G4Nucleus &targetNucleus,
1444   G4bool &incidentHasChanged,
1445   G4bool &targetHasChanged,
1446   G4bool leadFlag,
1447   G4ReactionProduct &leadingStrangeParticle )
1448  {
1449      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1450    // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
1451    //
1452    //  Generation of X- and PT- values for incident, target, and all secondary particles
1453    // 
1454    //  A simple two cluster model is used.
1455    //  This should be sufficient for low energy interactions.
1456    //
1457
1458    // + debugging
1459    // raise(SIGSEGV);
1460    // - debugging
1461
1462    G4int i;
1463    G4ParticleDefinition *aProton = G4Proton::Proton();
1464    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1465    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1466    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1467    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
1468    G4bool veryForward = false;
1469
1470    const G4double protonMass = aProton->GetPDGMass()/MeV;
1471    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
1472    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1473    const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1474    const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
1475    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1476    G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
1477                                        targetMass*targetMass +
1478                                        2.0*targetMass*etOriginal );  // GeV
1479    G4double currentMass = currentParticle.GetMass()/GeV;
1480    targetMass = targetParticle.GetMass()/GeV;
1481
1482    if( currentMass == 0.0 && targetMass == 0.0 )
1483    {
1484      G4double ek = currentParticle.GetKineticEnergy();
1485      G4ThreeVector m = currentParticle.GetMomentum();
1486      currentParticle = *vec[0];
1487      targetParticle = *vec[1];
1488      for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
1489      if(vecLen<2) 
1490      {
1491        for(G4int i=0; i<vecLen; i++) delete vec[i];
1492        vecLen = 0;
1493        throw G4HadReentrentException(__FILE__, __LINE__,
1494        "G4ReactionDynamics::TwoCluster: Negative number of particles");
1495      }
1496      delete vec[vecLen-1];
1497      delete vec[vecLen-2];
1498      vecLen -= 2;
1499      currentMass = currentParticle.GetMass()/GeV;
1500      targetMass = targetParticle.GetMass()/GeV;
1501      incidentHasChanged = true;
1502      targetHasChanged = true;
1503      currentParticle.SetKineticEnergy( ek );
1504      currentParticle.SetMomentum( m );
1505      veryForward = true;
1506    }
1507
1508    const G4double atomicWeight = targetNucleus.GetN();
1509    const G4double atomicNumber = targetNucleus.GetZ();
1510    //
1511    // particles have been distributed in forward and backward hemispheres
1512    // in center of mass system of the hadron nucleon interaction
1513    //
1514    // incident is always in forward hemisphere
1515    G4int forwardCount = 1;            // number of particles in forward hemisphere
1516    currentParticle.SetSide( 1 );
1517    G4double forwardMass = currentParticle.GetMass()/GeV;
1518    G4double cMass = forwardMass;
1519   
1520    // target is always in backward hemisphere
1521    G4int backwardCount = 1;           // number of particles in backward hemisphere
1522    G4int backwardNucleonCount = 1;    // number of nucleons in backward hemisphere
1523    targetParticle.SetSide( -1 );
1524    G4double backwardMass = targetParticle.GetMass()/GeV;
1525    G4double bMass = backwardMass;
1526   
1527    for( i=0; i<vecLen; ++i )
1528    {
1529      if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
1530      // to take care of the case where vec has been preprocessed by GenerateXandPt
1531      // and some of them have been set to -2 or -3
1532      if( vec[i]->GetSide() == -1 )
1533      {
1534        ++backwardCount;
1535        backwardMass += vec[i]->GetMass()/GeV;
1536      }
1537      else
1538      {
1539        ++forwardCount;
1540        forwardMass += vec[i]->GetMass()/GeV;
1541      }
1542    }
1543    //
1544    // nucleons and some pions from intranuclear cascade
1545    //
1546    G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
1547    if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
1548    const G4double afc = 0.312 + 0.2 * std::log(term1);
1549    G4double xtarg;
1550    if( centerofmassEnergy < 2.0+G4UniformRand() )        // added +2 below, JLC 4Jul97
1551      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
1552    else
1553      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
1554    if( xtarg <= 0.0 )xtarg = 0.01;
1555    G4int nuclearExcitationCount = Poisson( xtarg );
1556    if(atomicWeight<1.0001) nuclearExcitationCount = 0;
1557    G4int extraNucleonCount = 0;
1558    G4double extraMass = 0.0;
1559    G4double extraNucleonMass = 0.0;
1560    if( nuclearExcitationCount > 0 )
1561    {
1562      G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );     
1563      const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
1564      //
1565      //  NOTE: in TWOCLU, these new particles were given negative codes
1566      //        here we use  NewlyAdded = true  instead
1567      //
1568//      G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
1569      for( i=0; i<nuclearExcitationCount; ++i )
1570      {
1571        G4ReactionProduct* pVec = new G4ReactionProduct();
1572        if( G4UniformRand() < nucsup[momentumBin] )  // add proton or neutron
1573        {
1574          if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
1575            pVec->SetDefinition( aProton );
1576          else
1577            pVec->SetDefinition( aNeutron );
1578          ++backwardNucleonCount;
1579          ++extraNucleonCount;
1580          extraNucleonMass += pVec->GetMass()/GeV;
1581        }
1582        else
1583        {                                       // add a pion
1584          G4double ran = G4UniformRand();
1585          if( ran < 0.3181 )
1586            pVec->SetDefinition( aPiPlus );
1587          else if( ran < 0.6819 )
1588            pVec->SetDefinition( aPiZero );
1589          else
1590            pVec->SetDefinition( aPiMinus );
1591        }
1592        pVec->SetSide( -2 );    // backside particle
1593        extraMass += pVec->GetMass()/GeV;
1594        pVec->SetNewlyAdded( true );
1595        vec.SetElement( vecLen++, pVec );
1596        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1597      }
1598    }
1599      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1600    G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
1601    G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
1602    G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1603    G4bool secondaryDeleted;
1604    G4double pMass;
1605
1606    while( eAvailable <= 0.0 )   // must eliminate a particle
1607    {
1608      secondaryDeleted = false;
1609      for( i=(vecLen-1); i>=0; --i )
1610      {
1611        if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
1612        {
1613          pMass = vec[i]->GetMass()/GeV;
1614          for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];     // shift up
1615          --forwardCount;
1616          forwardEnergy += pMass;
1617          forwardMass -= pMass;
1618          secondaryDeleted = true;
1619          break;
1620        }
1621        else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
1622        {
1623          pMass = vec[i]->GetMass()/GeV;
1624          for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1625          --backwardCount;
1626          backwardEnergy += pMass;
1627          backwardMass -= pMass;
1628          secondaryDeleted = true;
1629          break;
1630        }
1631      }           // breaks go down to here
1632      if( secondaryDeleted )
1633      {     
1634        delete vec[vecLen-1];
1635        --vecLen;
1636        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1637      }
1638      else
1639      {
1640        if( vecLen == 0 )
1641        {
1642          return false;  // all secondaries have been eliminated
1643        }
1644        if( targetParticle.GetSide() == -1 )
1645        {
1646          pMass = targetParticle.GetMass()/GeV;
1647          targetParticle = *vec[0];
1648          for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1649          --backwardCount;
1650          backwardEnergy += pMass;
1651          backwardMass -= pMass;
1652          secondaryDeleted = true;
1653        }
1654        else if( targetParticle.GetSide() == 1 )
1655        {
1656          pMass = targetParticle.GetMass()/GeV;
1657          targetParticle = *vec[0];
1658          for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1659          --forwardCount;
1660          forwardEnergy += pMass;
1661          forwardMass -= pMass;
1662          secondaryDeleted = true;
1663        }
1664        if( secondaryDeleted )
1665        {
1666          delete vec[vecLen-1];
1667          --vecLen;
1668          // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1669        }
1670        else
1671        {
1672          if( currentParticle.GetSide() == -1 )
1673          {
1674            pMass = currentParticle.GetMass()/GeV;
1675            currentParticle = *vec[0];
1676            for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1677            --backwardCount;
1678            backwardEnergy += pMass;
1679            backwardMass -= pMass;
1680            secondaryDeleted = true;
1681          }
1682          else if( currentParticle.GetSide() == 1 )
1683          {
1684            pMass = currentParticle.GetMass()/GeV;
1685            currentParticle = *vec[0];
1686            for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1687            --forwardCount;
1688            forwardEnergy += pMass;
1689            forwardMass -= pMass;
1690            secondaryDeleted = true;
1691          }
1692          if( secondaryDeleted )
1693          {
1694            delete vec[vecLen-1];
1695            --vecLen;
1696            // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1697          }
1698          else break;
1699        }
1700      }
1701      eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1702    }
1703    //
1704    // This is the start of the TwoCluster function
1705    //  Choose masses for the 3 clusters:
1706    //   forward cluster
1707    //   backward meson cluster
1708    //   backward nucleon cluster
1709    //
1710    G4double rmc = 0.0, rmd = 0.0;
1711    const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
1712    const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
1713   
1714    if (forwardCount <= 0 || backwardCount <= 0) return false;  // array bounds protection
1715
1716    if (forwardCount == 1) rmc = forwardMass;
1717    else 
1718    {
1719      G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
1720      rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1721    }
1722
1723    if (backwardCount == 1) rmd = backwardMass;
1724    else
1725    {
1726      G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
1727      rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1728    }
1729
1730    while( rmc+rmd > centerofmassEnergy )
1731    {
1732      if( (rmc <= forwardMass) && (rmd <= backwardMass) )
1733      {
1734        G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
1735        rmc *= temp;
1736        rmd *= temp;
1737      }
1738      else
1739      {
1740        rmc = 0.1*forwardMass + 0.9*rmc;
1741        rmd = 0.1*backwardMass + 0.9*rmd;
1742      }
1743    }
1744
1745    G4ReactionProduct pseudoParticle[8];
1746    for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
1747   
1748    pseudoParticle[1].SetMass( mOriginal*GeV );
1749    pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
1750    pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1751   
1752    pseudoParticle[2].SetMass( protonMass*MeV );
1753    pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
1754    pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
1755    //
1756    //  transform into centre of mass system
1757    //
1758    pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
1759    pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
1760    pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
1761   
1762    const G4double pfMin = 0.0001;
1763    G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
1764    pf *= pf;
1765    pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
1766    pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
1767    //
1768    //  set final state masses and energies in centre of mass system
1769    //
1770    pseudoParticle[3].SetMass( rmc*GeV );
1771    pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
1772   
1773    pseudoParticle[4].SetMass( rmd*GeV );
1774    pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
1775    //
1776    // set |T| and |TMIN|
1777    //
1778    const G4double bMin = 0.01;
1779    const G4double b1 = 4.0;
1780    const G4double b2 = 1.6;
1781
1782    G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
1783    G4double dtb = 4.0*pin*pf*std::max( bMin, b1+b2*std::log(pOriginal) );
1784    G4double factor = 1.0 - std::exp(-dtb);
1785    G4double costheta = 1.0 + 2.0*std::log(1.0 - G4UniformRand()*factor) / dtb;
1786    costheta = std::max(-1.0, std::min(1.0, costheta));
1787    G4double sintheta = std::sqrt(1.0-costheta*costheta);
1788    G4double phi = G4UniformRand() * twopi;
1789
1790    //
1791    // calculate final state momenta in centre of mass system
1792    //
1793    pseudoParticle[3].SetMomentum( pf*sintheta*std::cos(phi)*GeV,
1794                                   pf*sintheta*std::sin(phi)*GeV,
1795                                   pf*costheta*GeV );
1796
1797    pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1798    //
1799    // simulate backward nucleon cluster in lab. system and transform in cms
1800    //
1801    G4double pp, pp1;
1802    if( nuclearExcitationCount > 0 )
1803    {
1804      const G4double ga = 1.2;
1805      G4double ekit1 = 0.04;
1806      G4double ekit2 = 0.6;
1807      if( ekOriginal <= 5.0 )
1808      {
1809        ekit1 *= ekOriginal*ekOriginal/25.0;
1810        ekit2 *= ekOriginal*ekOriginal/25.0;
1811      }
1812      const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
1813      for( i=0; i<vecLen; ++i )
1814      {
1815        if( vec[i]->GetSide() == -2 )
1816        {
1817          G4double kineticE =
1818            std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
1819          vec[i]->SetKineticEnergy( kineticE*GeV );
1820          G4double vMass = vec[i]->GetMass()/MeV;
1821          G4double totalE = kineticE*GeV + vMass;
1822          pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
1823          G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
1824          G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
1825          phi = twopi*G4UniformRand();
1826          vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
1827                               pp*sint*std::cos(phi)*MeV,
1828                               pp*cost*MeV );
1829          vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
1830        }
1831      }
1832      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1833    }
1834    //
1835    // fragmentation of forward cluster and backward meson cluster
1836    //
1837    currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
1838    currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1839   
1840    targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
1841    targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1842   
1843    pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1844    pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
1845    pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1846   
1847    pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
1848    pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
1849    pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1850   
1851    G4double wgt;
1852      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1853    if( forwardCount > 1 )     // tempV will contain the forward particles
1854    {
1855      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1856      tempV.Initialize( forwardCount );
1857      G4bool constantCrossSection = true;
1858      G4int tempLen = 0;
1859      if( currentParticle.GetSide() == 1 )
1860        tempV.SetElement( tempLen++, &currentParticle );
1861      if( targetParticle.GetSide() == 1 )
1862        tempV.SetElement( tempLen++, &targetParticle );
1863      for( i=0; i<vecLen; ++i )
1864      {
1865        if( vec[i]->GetSide() == 1 )
1866        {
1867          if( tempLen < 18 )
1868            tempV.SetElement( tempLen++, vec[i] );
1869          else
1870          {
1871            vec[i]->SetSide( -1 );
1872            continue;
1873          }
1874        }
1875      }
1876      if( tempLen >= 2 )
1877      {
1878        wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
1879                                  constantCrossSection, tempV, tempLen );
1880        if( currentParticle.GetSide() == 1 )
1881          currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
1882        if( targetParticle.GetSide() == 1 )
1883          targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
1884        for( i=0; i<vecLen; ++i )
1885        {
1886          if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
1887        }
1888      }
1889    }
1890      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1891    if( backwardCount > 1 )   //  tempV will contain the backward particles,
1892    {                         //  but not those created from the intranuclear cascade
1893      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1894      tempV.Initialize( backwardCount );
1895      G4bool constantCrossSection = true;
1896      G4int tempLen = 0;
1897      if( currentParticle.GetSide() == -1 )
1898        tempV.SetElement( tempLen++, &currentParticle );
1899      if( targetParticle.GetSide() == -1 )
1900        tempV.SetElement( tempLen++, &targetParticle );
1901      for( i=0; i<vecLen; ++i )
1902      {
1903        if( vec[i]->GetSide() == -1 )
1904        {
1905          if( tempLen < 18 )
1906            tempV.SetElement( tempLen++, vec[i] );
1907          else
1908          {
1909            vec[i]->SetSide( -2 );
1910            vec[i]->SetKineticEnergy( 0.0 );
1911            vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
1912            continue;
1913          }
1914        }
1915      }
1916      if( tempLen >= 2 )
1917      {
1918        wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
1919                                  constantCrossSection, tempV, tempLen );
1920        if( currentParticle.GetSide() == -1 )
1921          currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
1922        if( targetParticle.GetSide() == -1 )
1923          targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1924        for( i=0; i<vecLen; ++i )
1925        {
1926          if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1927        }
1928      }
1929    }
1930      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1931    //
1932    // Lorentz transformation in lab system
1933    //
1934    currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
1935    targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
1936    for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
1937
1938      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1939    //
1940    // sometimes the leading strange particle is lost, set it back
1941    //
1942    G4bool dum = true;
1943    if( leadFlag )
1944    {
1945      // leadFlag will be true
1946      //  iff original particle is at least as heavy as K+ and not a proton or
1947      //  neutron AND if incident particle is at least as heavy as K+ and it is
1948      //  not a proton or neutron leadFlag is set to the incident particle
1949      //  or
1950      //  target particle is at least as heavy as K+ and it is not a proton or
1951      //  neutron leadFlag is set to the target particle
1952      //
1953      if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1954        dum = false;
1955      else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1956        dum = false;
1957      else
1958      {
1959        for( i=0; i<vecLen; ++i )
1960        {
1961          if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1962          {
1963            dum = false;
1964            break;
1965          }
1966        }
1967      }
1968      if( dum )
1969      {
1970        G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
1971        G4double ekin;
1972        if( ((leadMass <  protonMass) && (targetParticle.GetMass()/MeV <  protonMass)) ||
1973            ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
1974        {
1975          ekin = targetParticle.GetKineticEnergy()/GeV;
1976          pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
1977          targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1978          targetParticle.SetKineticEnergy( ekin*GeV );
1979          pp = targetParticle.GetTotalMomentum()/MeV;   // new momentum
1980          if( pp1 < 1.0e-3 )
1981          {
1982            G4double costheta = 2.*G4UniformRand() - 1.;
1983            G4double sintheta = std::sqrt(1. - costheta*costheta);
1984            G4double phi = twopi*G4UniformRand();
1985            targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1986                                        pp*sintheta*std::sin(phi)*MeV,
1987                                        pp*costheta*MeV ) ;
1988          }
1989          else
1990            targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1991         
1992          targetHasChanged = true;
1993        }
1994        else
1995        {
1996          ekin = currentParticle.GetKineticEnergy()/GeV;
1997          pp1 = currentParticle.GetMomentum().mag()/MeV;
1998          currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1999          currentParticle.SetKineticEnergy( ekin*GeV );
2000          pp = currentParticle.GetTotalMomentum()/MeV;
2001          if( pp1 < 1.0e-3 )
2002          {
2003            G4double costheta = 2.*G4UniformRand() - 1.;
2004            G4double sintheta = std::sqrt(1. - costheta*costheta);
2005            G4double phi = twopi*G4UniformRand();
2006            currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2007                                         pp*sintheta*std::sin(phi)*MeV,
2008                                         pp*costheta*MeV ) ;
2009          }
2010          else
2011            currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2012         
2013          incidentHasChanged = true;
2014        }
2015      }
2016    }    // end of if( leadFlag )
2017
2018    // Get number of final state nucleons and nucleons remaining in
2019    // target nucleus
2020   
2021    std::pair<G4int, G4int> finalStateNucleons = 
2022      GetFinalStateNucleons(originalTarget, vec, vecLen);
2023
2024    G4int protonsInFinalState = finalStateNucleons.first;
2025    G4int neutronsInFinalState = finalStateNucleons.second;
2026
2027    G4int numberofFinalStateNucleons = 
2028      protonsInFinalState + neutronsInFinalState;
2029
2030    if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2031        targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2032        originalIncident->GetDefinition()->GetPDGMass() < 
2033                                   G4Lambda::Lambda()->GetPDGMass())
2034      numberofFinalStateNucleons++;
2035
2036    numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
2037
2038    G4int PinNucleus = std::max(0, 
2039      G4int(targetNucleus.GetZ()) - protonsInFinalState);
2040    G4int NinNucleus = std::max(0,
2041      G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
2042    //
2043    //  for various reasons, the energy balance is not sufficient,
2044    //  check that,  energy balance, angle of final system, etc.
2045    //
2046    pseudoParticle[4].SetMass( mOriginal*GeV );
2047    pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
2048    pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2049   
2050    G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
2051    G4int diff = 0;
2052    if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
2053    if(numberofFinalStateNucleons == 1) diff = 0;
2054    pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
2055    pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2056    pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2057   
2058    G4double theoreticalKinetic =
2059      pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
2060   
2061    pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
2062    pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
2063    pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
2064     
2065    if( vecLen < 16 )
2066    {
2067      G4ReactionProduct tempR[130];
2068      tempR[0] = currentParticle;
2069      tempR[1] = targetParticle;
2070      for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
2071
2072      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
2073      tempV.Initialize( vecLen+2 );
2074      G4bool constantCrossSection = true;
2075      G4int tempLen = 0;
2076      for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
2077
2078      if( tempLen >= 2 )
2079      {
2080      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2081        wgt = GenerateNBodyEvent( pseudoParticle[4].GetTotalEnergy()/MeV +
2082                                  pseudoParticle[5].GetTotalEnergy()/MeV,
2083                                  constantCrossSection, tempV, tempLen );
2084        if (wgt == -1) {
2085          G4double Qvalue = 0;
2086          for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
2087          wgt = GenerateNBodyEvent( Qvalue/MeV,
2088                                    constantCrossSection, tempV, tempLen );
2089        }
2090        theoreticalKinetic = 0.0;
2091        for( i=0; i<vecLen+2; ++i )
2092        {
2093          pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
2094          pseudoParticle[7].SetMass( tempV[i]->GetMass() );
2095          pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
2096          pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
2097          theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
2098        }
2099      }
2100      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2101    }
2102    else
2103    {
2104      theoreticalKinetic -=
2105        ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
2106      for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
2107    }
2108    G4double simulatedKinetic =
2109      currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
2110    for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
2111    //
2112    // make sure that kinetic energies are correct
2113    // the backward nucleon cluster is not produced within proper kinematics!!!
2114    //
2115   
2116    if( simulatedKinetic != 0.0 )
2117    {
2118      wgt = (theoreticalKinetic)/simulatedKinetic;
2119      currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
2120      pp = currentParticle.GetTotalMomentum()/MeV;
2121      pp1 = currentParticle.GetMomentum().mag()/MeV;
2122      if( pp1 < 0.001*MeV )
2123      {
2124        G4double costheta = 2.*G4UniformRand() - 1.;
2125        G4double sintheta = std::sqrt(1. - costheta*costheta);
2126        G4double phi = twopi*G4UniformRand();
2127        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2128                                     pp*sintheta*std::sin(phi)*MeV,
2129                                     pp*costheta*MeV ) ;
2130      }
2131      else
2132        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2133     
2134      targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
2135      pp = targetParticle.GetTotalMomentum()/MeV;
2136      pp1 = targetParticle.GetMomentum().mag()/MeV;
2137      if( pp1 < 0.001*MeV )
2138      {
2139        G4double costheta = 2.*G4UniformRand() - 1.;
2140        G4double sintheta = std::sqrt(1. - costheta*costheta);
2141        G4double phi = twopi*G4UniformRand();
2142        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2143                                    pp*sintheta*std::sin(phi)*MeV,
2144                                    pp*costheta*MeV ) ;
2145      }
2146      else
2147        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2148     
2149      for( i=0; i<vecLen; ++i )
2150      {
2151        vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
2152        pp = vec[i]->GetTotalMomentum()/MeV;
2153        pp1 = vec[i]->GetMomentum().mag()/MeV;
2154        if( pp1 < 0.001 )
2155        {
2156          G4double costheta = 2.*G4UniformRand() - 1.;
2157          G4double sintheta = std::sqrt(1. - costheta*costheta);
2158          G4double phi = twopi*G4UniformRand();
2159          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2160                               pp*sintheta*std::sin(phi)*MeV,
2161                               pp*costheta*MeV ) ;
2162        }
2163        else
2164          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2165      }
2166    }
2167      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2168
2169    Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
2170            modifiedOriginal, originalIncident, targetNucleus,
2171            currentParticle, targetParticle, vec, vecLen );
2172    //
2173    //  add black track particles
2174    //  the total number of particles produced is restricted to 198
2175    //  this may have influence on very high energies
2176    //
2177    if( atomicWeight >= 1.5 )
2178    {
2179      // npnb is number of proton/neutron black track particles
2180      // ndta is the number of deuterons, tritons, and alphas produced
2181      // epnb is the kinetic energy available for proton/neutron black track
2182      //   particles
2183      // edta is the kinetic energy available for deuteron/triton/alpha
2184      //   particles
2185
2186      G4int npnb = 0;
2187      G4int ndta = 0;
2188
2189      G4double epnb, edta;
2190      if (veryForward) {
2191        epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
2192        edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
2193      } else {
2194        epnb = targetNucleus.GetPNBlackTrackEnergy();
2195        edta = targetNucleus.GetDTABlackTrackEnergy();
2196      }
2197
2198      const G4double pnCutOff = 0.001;     // GeV
2199      const G4double dtaCutOff = 0.001;    // GeV
2200      const G4double kineticMinimum = 1.e-6;
2201      const G4double kineticFactor = -0.005;
2202     
2203      G4double sprob = 0.0;   // sprob = probability of self-absorption in
2204                              // heavy molecules
2205      const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
2206      if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
2207     
2208      if( epnb >= pnCutOff )
2209      {
2210        npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
2211        if( numberofFinalStateNucleons + npnb > atomicWeight )
2212          npnb = G4int(atomicWeight - numberofFinalStateNucleons);
2213        npnb = std::min( npnb, 127-vecLen );
2214      }
2215      if( edta >= dtaCutOff )
2216      {
2217        ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
2218        ndta = std::min( ndta, 127-vecLen );
2219      }
2220      if (npnb == 0 && ndta == 0) npnb = 1;
2221
2222      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2223
2224      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
2225                             kineticFactor, modifiedOriginal, 
2226                             PinNucleus, NinNucleus, targetNucleus,
2227                             vec, vecLen );
2228      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2229    }
2230    //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
2231    //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2232    //
2233    //  calculate time delay for nuclear reactions
2234    //
2235    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2236      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2237    else
2238      currentParticle.SetTOF( 1.0 );
2239   
2240      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2241    return true;
2242  }
2243 
2244 void G4ReactionDynamics::TwoBody(
2245  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2246  G4int &vecLen,
2247  G4ReactionProduct &modifiedOriginal,
2248  const G4DynamicParticle* originalTarget,
2249  G4ReactionProduct &currentParticle,
2250  G4ReactionProduct &targetParticle,
2251  const G4Nucleus &targetNucleus,
2252  G4bool &/* targetHasChanged*/ )
2253  {
2254    //
2255    // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
2256    //
2257    // Generation of momenta for elastic and quasi-elastic 2 body reactions
2258    //
2259    // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
2260    // The b values are parametrizations from experimental data.
2261    // Not available values are taken from those of similar reactions.
2262    //
2263   
2264      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);   
2265    static const G4double expxu =  82.;           // upper bound for arg. of exp
2266    static const G4double expxl = -expxu;         // lower bound for arg. of exp
2267   
2268    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
2269    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
2270    const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
2271    const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
2272    G4double currentMass = currentParticle.GetMass()/GeV;
2273    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
2274
2275    targetMass = targetParticle.GetMass()/GeV;
2276    const G4double atomicWeight = targetNucleus.GetN();
2277   
2278    G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
2279    G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
2280
2281    G4double cmEnergy = std::sqrt( currentMass*currentMass +
2282                              targetMass*targetMass +
2283                              2.0*targetMass*etCurrent );  // in GeV
2284
2285    //if( (pOriginal < 0.1) ||
2286    //    (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
2287    // Continue with original particle, but spend the nuclear evaporation energy
2288    //  targetParticle.SetMass( 0.0 );  // flag that the target doesn't exist
2289    //else                           // Two-body scattering is possible
2290
2291    if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
2292    {
2293      targetParticle.SetMass( 0.0 );  // flag that the target particle doesn't exist
2294    }
2295    else
2296    {
2297// moved this if-block to a later stage, i.e. to the assignment of the scattering angle
2298// @@@@@ double-check.
2299//      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2300//          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2301//        if( G4UniformRand() < 0.5 )
2302//          targetParticle.SetDefinitionAndUpdateE( aNeutron );
2303//        else
2304//          targetParticle.SetDefinitionAndUpdateE( aProton );
2305//        targetHasChanged = true;
2306//        targetMass = targetParticle.GetMass()/GeV;
2307//      }
2308      //
2309      // Set masses and momenta for final state particles
2310      //
2311      G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
2312      pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
2313     
2314      if( pf < 0.001 )
2315      {
2316        for(G4int i=0; i<vecLen; i++) delete vec[i];
2317        vecLen = 0;
2318        throw G4HadronicException(__FILE__, __LINE__, "G4ReactionDynamics::TwoBody: pf is too small ");
2319      }
2320     
2321      pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
2322      //
2323      // Set beam and target in centre of mass system
2324      //
2325      G4ReactionProduct pseudoParticle[3];
2326     
2327      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2328          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2329        pseudoParticle[0].SetMass( targetMass*GeV );
2330        pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
2331        pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2332     
2333        pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2334        pseudoParticle[1].SetMass( mOriginal*GeV );
2335        pseudoParticle[1].SetKineticEnergy( 0.0 );
2336
2337      } else {
2338        pseudoParticle[0].SetMass( currentMass*GeV );
2339        pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
2340        pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
2341     
2342        pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2343        pseudoParticle[1].SetMass( targetMass*GeV );
2344        pseudoParticle[1].SetKineticEnergy( 0.0 );
2345      }
2346      //
2347      // Transform into centre of mass system
2348      //
2349      pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
2350      pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
2351      pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
2352      //
2353      // Set final state masses and energies in centre of mass system
2354      //
2355      currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
2356      targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
2357      //
2358      // Set |t| and |tmin|
2359      //
2360      const G4double cb = 0.01;
2361      const G4double b1 = 4.225;
2362      const G4double b2 = 1.795;
2363      //
2364      // Calculate slope b for elastic scattering on proton/neutron
2365      //
2366      G4double b = std::max( cb, b1+b2*std::log(pOriginal) );     
2367      G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
2368     
2369      G4double exindt = -1.0;
2370      exindt += std::exp(std::max(-btrang,expxl));
2371      //
2372      // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
2373      //
2374      G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
2375      if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
2376      G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
2377      G4double phi = twopi * G4UniformRand();
2378      //
2379      // Calculate final state momenta in centre of mass system
2380      //
2381      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2382          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2383
2384        currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
2385                                     -pf*stet*std::cos(phi)*GeV,
2386                                     -pf*ctet*GeV );
2387      } else {
2388
2389        currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
2390                                     pf*stet*std::cos(phi)*GeV,
2391                                     pf*ctet*GeV );
2392      }
2393      targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
2394      //
2395      // Transform into lab system
2396      //
2397      currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
2398      targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
2399     
2400      Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2401     
2402      G4double pp, pp1, ekin;
2403      if( atomicWeight >= 1.5 )
2404      {
2405        const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2406        pp1 = currentParticle.GetMomentum().mag()/MeV;
2407        if( pp1 >= 1.0 )
2408        {
2409          ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
2410          ekin = std::max( 0.0001*GeV, ekin );
2411          currentParticle.SetKineticEnergy( ekin*MeV );
2412          pp = currentParticle.GetTotalMomentum()/MeV;
2413          currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2414        }
2415        pp1 = targetParticle.GetMomentum().mag()/MeV;
2416        if( pp1 >= 1.0 )
2417        {
2418          ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
2419          ekin = std::max( 0.0001*GeV, ekin );
2420          targetParticle.SetKineticEnergy( ekin*MeV );
2421          pp = targetParticle.GetTotalMomentum()/MeV;
2422          targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2423        }
2424      }
2425    }
2426
2427    // Get number of final state nucleons and nucleons remaining in
2428    // target nucleus
2429   
2430    std::pair<G4int, G4int> finalStateNucleons = 
2431      GetFinalStateNucleons(originalTarget, vec, vecLen);
2432    G4int protonsInFinalState = finalStateNucleons.first;
2433    G4int neutronsInFinalState = finalStateNucleons.second;
2434
2435    G4int PinNucleus = std::max(0, 
2436      G4int(targetNucleus.GetZ()) - protonsInFinalState);
2437    G4int NinNucleus = std::max(0,
2438      G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
2439
2440      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2441    if( atomicWeight >= 1.5 )
2442    {
2443      // Add black track particles
2444      // npnb is number of proton/neutron black track particles
2445      // ndta is the number of deuterons, tritons, and alphas produced
2446      // epnb is the kinetic energy available for proton/neutron black track particles
2447      // edta is the kinetic energy available for deuteron/triton/alpha particles
2448      //
2449      G4double epnb, edta;
2450      G4int npnb=0, ndta=0;
2451     
2452      epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
2453      edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
2454      const G4double pnCutOff = 0.0001;       // GeV
2455      const G4double dtaCutOff = 0.0001;      // GeV
2456      const G4double kineticMinimum = 0.0001;
2457      const G4double kineticFactor = -0.010;
2458      G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2459      if( epnb >= pnCutOff )
2460      {
2461        npnb = Poisson( epnb/0.02 );
2462        if( npnb > atomicWeight )npnb = G4int(atomicWeight);
2463        if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
2464        npnb = std::min( npnb, 127-vecLen );
2465      }
2466      if( edta >= dtaCutOff )
2467      {
2468        ndta = G4int(2.0 * std::log(atomicWeight));
2469        ndta = std::min( ndta, 127-vecLen );
2470      }
2471
2472      if (npnb == 0 && ndta == 0) npnb = 1;
2473
2474      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2475
2476      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
2477                             kineticFactor, modifiedOriginal, 
2478                             PinNucleus, NinNucleus, targetNucleus,
2479                             vec, vecLen);
2480      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2481    }
2482    //
2483    //  calculate time delay for nuclear reactions
2484    //
2485    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2486      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2487    else
2488      currentParticle.SetTOF( 1.0 );
2489    return;
2490  }
2491 
2492 G4double G4ReactionDynamics::GenerateNBodyEvent(
2493  const G4double totalEnergy,                // MeV
2494  const G4bool constantCrossSection,
2495  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2496  G4int &vecLen )
2497  {
2498      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2499    // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
2500    // Returns the weight of the event
2501    //
2502    G4int i;
2503    const G4double expxu =  82.;           // upper bound for arg. of exp
2504    const G4double expxl = -expxu;         // lower bound for arg. of exp
2505    if( vecLen < 2 )
2506    {
2507      G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2508      G4cerr << "    number of particles < 2" << G4endl;
2509      G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
2510      return -1.0;
2511    }
2512    G4double mass[18];    // mass of each particle
2513    G4double energy[18];  // total energy of each particle
2514    G4double pcm[3][18];           // pcm is an array with 3 rows and vecLen columns
2515   
2516    G4double totalMass = 0.0;
2517    G4double extraMass = 0;
2518    G4double sm[18];
2519   
2520    for( i=0; i<vecLen; ++i )
2521    {
2522      mass[i] = vec[i]->GetMass()/GeV;
2523      if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
2524      vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
2525      pcm[0][i] = 0.0;      // x-momentum of i-th particle
2526      pcm[1][i] = 0.0;      // y-momentum of i-th particle
2527      pcm[2][i] = 0.0;      // z-momentum of i-th particle
2528      energy[i] = mass[i];  // total energy of i-th particle
2529      totalMass += mass[i];
2530      sm[i] = totalMass;
2531    }
2532    G4double totalE = totalEnergy/GeV;
2533    if( totalMass > totalE )
2534    {
2535      //G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2536      //G4cerr << "    total mass (" << totalMass*GeV << "MeV) > total energy ("
2537      //     << totalEnergy << "MeV)" << G4endl;
2538      totalE = totalMass;
2539      return -1.0;
2540    }
2541    G4double kineticEnergy = totalE - totalMass;
2542    G4double emm[18];
2543    //G4double *emm = new G4double [vecLen];
2544    emm[0] = mass[0];
2545    emm[vecLen-1] = totalE;
2546    if( vecLen > 2 )          // the random numbers are sorted
2547    {
2548      G4double ran[18];
2549      for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
2550      for( i=0; i<vecLen-2; ++i )
2551      {
2552        for( G4int j=vecLen-2; j>i; --j )
2553        {
2554          if( ran[i] > ran[j] )
2555          {
2556            G4double temp = ran[i];
2557            ran[i] = ran[j];
2558            ran[j] = temp;
2559          }
2560        }
2561      }
2562      for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
2563    }
2564    //   Weight is the sum of logarithms of terms instead of the product of terms
2565    G4bool lzero = true;   
2566    G4double wtmax = 0.0;
2567    if( constantCrossSection )     // this is KGENEV=1 in PHASP
2568    {
2569      G4double emmax = kineticEnergy + mass[0];
2570      G4double emmin = 0.0;
2571      for( i=1; i<vecLen; ++i )
2572      {
2573        emmin += mass[i-1];
2574        emmax += mass[i];
2575        G4double wtfc = 0.0;
2576        if( emmax*emmax > 0.0 )
2577        {
2578          G4double arg = emmax*emmax
2579            + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
2580            - 2.0*(emmin*emmin+mass[i]*mass[i]);
2581          if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
2582        }
2583        if( wtfc == 0.0 )
2584        {
2585          lzero = false;
2586          break;
2587        }
2588        wtmax += std::log( wtfc );
2589      }
2590      if( lzero )
2591        wtmax = -wtmax;
2592      else
2593        wtmax = expxu;
2594    }
2595    else
2596    {
2597      //   ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
2598      const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
2599                                 256.3704, 268.4705, 240.9780, 189.2637,
2600                                 132.1308,  83.0202,  47.4210,  24.8295,
2601                                 12.0006,   5.3858,   2.2560,   0.8859 };
2602      wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
2603    }
2604    lzero = true;
2605    G4double pd[50];
2606    //G4double *pd = new G4double [vecLen-1];
2607    for( i=0; i<vecLen-1; ++i )
2608    {
2609      pd[i] = 0.0;
2610      if( emm[i+1]*emm[i+1] > 0.0 )
2611      {
2612        G4double arg = emm[i+1]*emm[i+1]
2613          + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
2614            /(emm[i+1]*emm[i+1])
2615          - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
2616        if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
2617      }
2618      if( pd[i] <= 0.0 )    //  changed from  ==  on 02 April 98
2619        lzero = false;
2620      else
2621        wtmax += std::log( pd[i] );
2622    }
2623    G4double weight = 0.0;           // weight is returned by GenerateNBodyEvent
2624    if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
2625   
2626    G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
2627    pcm[0][0] = 0.0;
2628    pcm[1][0] = pd[0];
2629    pcm[2][0] = 0.0;
2630    for( i=1; i<vecLen; ++i )
2631    {
2632      pcm[0][i] = 0.0;
2633      pcm[1][i] = -pd[i-1];
2634      pcm[2][i] = 0.0;
2635      bang = twopi*G4UniformRand();
2636      cb = std::cos(bang);
2637      sb = std::sin(bang);
2638      c = 2.0*G4UniformRand() - 1.0;
2639      s = std::sqrt( std::fabs( 1.0-c*c ) );
2640      if( i < vecLen-1 )
2641      {
2642        esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
2643        beta = pd[i]/esys;
2644        gama = esys/emm[i];
2645        for( G4int j=0; j<=i; ++j )
2646        {
2647          s0 = pcm[0][j];
2648          s1 = pcm[1][j];
2649          s2 = pcm[2][j];
2650          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2651          a = s0*c - s1*s;                           //  rotation
2652          pcm[1][j] = s0*s + s1*c;
2653          b = pcm[2][j];
2654          pcm[0][j] = a*cb - b*sb;
2655          pcm[2][j] = a*sb + b*cb;
2656          pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
2657        }
2658      }
2659      else
2660      {
2661        for( G4int j=0; j<=i; ++j )
2662        {
2663          s0 = pcm[0][j];
2664          s1 = pcm[1][j];
2665          s2 = pcm[2][j];
2666          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2667          a = s0*c - s1*s;                           //  rotation
2668          pcm[1][j] = s0*s + s1*c;
2669          b = pcm[2][j];
2670          pcm[0][j] = a*cb - b*sb;
2671          pcm[2][j] = a*sb + b*cb;
2672        }
2673      }
2674    }
2675    for( i=0; i<vecLen; ++i )
2676    {
2677      vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
2678      vec[i]->SetTotalEnergy( energy[i]*GeV );
2679    }
2680
2681      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2682    return weight;
2683  }
2684 
2685 G4double
2686   G4ReactionDynamics::normal()
2687   {
2688     G4double ran = -6.0;
2689     for( G4int i=0; i<12; ++i )ran += G4UniformRand();
2690     return ran;
2691   }
2692 
2693 G4int
2694   G4ReactionDynamics::Poisson( G4double x )  // generation of poisson distribution
2695   {
2696     G4int iran;
2697     G4double ran;
2698     
2699     if( x > 9.9 )    // use normal distribution with sigma^2 = <x>
2700       iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
2701     else {
2702      G4int mm = G4int(5.0*x);
2703      if( mm <= 0 )   // for very small x try iran=1,2,3
2704      {
2705        G4double p1 = x*std::exp(-x);
2706        G4double p2 = x*p1/2.0;
2707        G4double p3 = x*p2/3.0;
2708        ran = G4UniformRand();
2709        if( ran < p3 )
2710          iran = 3;
2711        else if( ran < p2 )   // this is original Geisha, it should be ran < p2+p3
2712          iran = 2;
2713        else if( ran < p1 )   // should be ran < p1+p2+p3
2714          iran = 1;
2715        else
2716          iran = 0;
2717      }
2718      else
2719      {
2720        iran = 0;
2721        G4double r = std::exp(-x);
2722        ran = G4UniformRand();
2723        if( ran > r )
2724        {
2725          G4double rrr;
2726          G4double rr = r;
2727          for( G4int i=1; i<=mm; ++i )
2728          {
2729            iran++;
2730            if( i > 5 )   // Stirling's formula for large numbers
2731              rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
2732            else
2733              rrr = std::pow(x,i)/Factorial(i);
2734            rr += r*rrr;
2735            if( ran <= rr )break;
2736          }
2737        }
2738      }
2739    }
2740    return iran;
2741  }
2742 
2743 G4int
2744   G4ReactionDynamics::Factorial( G4int n )
2745   {   // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
2746     G4int m = std::min(n,10);
2747     G4int result = 1;
2748     if( m <= 1 )return result;
2749     for( G4int i=2; i<=m; ++i )result *= i;
2750     return result;
2751   }
2752 
2753 void G4ReactionDynamics::Defs1(
2754   const G4ReactionProduct &modifiedOriginal,
2755   G4ReactionProduct &currentParticle,
2756   G4ReactionProduct &targetParticle,
2757   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2758   G4int &vecLen )
2759  {
2760    const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
2761    const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
2762    const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
2763    const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
2764    if( pjx*pjx+pjy*pjy > 0.0 )
2765    {
2766      G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
2767      cost = pjz/p;
2768      sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
2769      if( pjy < 0.0 )
2770        ph = 3*halfpi;
2771      else
2772        ph = halfpi;
2773      if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
2774      cosp = std::cos(ph);
2775      sinp = std::sin(ph);
2776      pix = currentParticle.GetMomentum().x()/MeV;
2777      piy = currentParticle.GetMomentum().y()/MeV;
2778      piz = currentParticle.GetMomentum().z()/MeV;
2779      currentParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2780                                   cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2781                                   -sint*pix*MeV     + cost*piz*MeV );
2782      pix = targetParticle.GetMomentum().x()/MeV;
2783      piy = targetParticle.GetMomentum().y()/MeV;
2784      piz = targetParticle.GetMomentum().z()/MeV;
2785      targetParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2786                                  cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2787                                  -sint*pix*MeV     + cost*piz*MeV );
2788      for( G4int i=0; i<vecLen; ++i )
2789      {
2790        pix = vec[i]->GetMomentum().x()/MeV;
2791        piy = vec[i]->GetMomentum().y()/MeV;
2792        piz = vec[i]->GetMomentum().z()/MeV;
2793        vec[i]->SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2794                             cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2795                             -sint*pix*MeV     + cost*piz*MeV );
2796      }
2797    }
2798    else
2799    {
2800      if( pjz < 0.0 )
2801      {
2802        currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
2803        targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
2804        for( G4int i=0; i<vecLen; ++i )
2805          vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
2806      }
2807    }
2808  }
2809 
2810 void G4ReactionDynamics::Rotate(
2811  const G4double numberofFinalStateNucleons,
2812  const G4ThreeVector &temp,
2813  const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
2814  const G4HadProjectile *originalIncident, // original incident particle
2815  const G4Nucleus &targetNucleus,
2816  G4ReactionProduct &currentParticle,
2817  G4ReactionProduct &targetParticle,
2818  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2819  G4int &vecLen )
2820  {
2821    // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
2822    //
2823    //   Rotate in direction of z-axis, this does disturb in some way our
2824    //    inclusive distributions, but it is necessary for momentum conservation
2825    //
2826    const G4double atomicWeight = targetNucleus.GetN();
2827    const G4double logWeight = std::log(atomicWeight);
2828   
2829    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2830    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2831    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2832   
2833    G4int i;
2834    G4ThreeVector pseudoParticle[4];
2835    for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
2836    pseudoParticle[0] = currentParticle.GetMomentum()
2837                        + targetParticle.GetMomentum();
2838    for( i=0; i<vecLen; ++i )
2839      pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
2840    //
2841    //  Some smearing in transverse direction from Fermi motion
2842    //
2843    G4float pp, pp1;
2844    G4double alekw, p;
2845    G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
2846   
2847    r1 = twopi*G4UniformRand();
2848    r2 = G4UniformRand();
2849    a1 = std::sqrt(-2.0*std::log(r2));
2850    ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
2851    ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
2852    G4ThreeVector fermi(ran1, ran2, 0);
2853
2854    pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
2855    pseudoParticle[2] = temp; // original in cms system
2856    pseudoParticle[3] = pseudoParticle[0];
2857   
2858    pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
2859    G4double rotation = 2.*pi*G4UniformRand();
2860    pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
2861    pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);   
2862    for(G4int ii=1; ii<=3; ii++)
2863    { 
2864      p = pseudoParticle[ii].mag();
2865      if( p == 0.0 )
2866        pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
2867      else
2868        pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
2869    }
2870   
2871    pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
2872    pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
2873    pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
2874    currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2875   
2876    pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
2877    pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
2878    pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
2879    targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2880   
2881    for( i=0; i<vecLen; ++i )
2882    {
2883      pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
2884      pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
2885      pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
2886      vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
2887    }
2888    //
2889    //  Rotate in direction of primary particle, subtract binding energies
2890    //   and make some further corrections if required
2891    //
2892    Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2893    G4double ekin;
2894    G4double dekin = 0.0;
2895    G4double ek1 = 0.0;
2896    G4int npions = 0;
2897    if( atomicWeight >= 1.5 )            // self-absorption in heavy molecules
2898    {
2899      // corrections for single particle spectra (shower particles)
2900      //
2901      const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
2902      const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
2903      alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
2904      exh = 1.0;
2905      if( alekw > alem[0] )   //   get energy bin
2906      {
2907        exh = val0[6];
2908        for( G4int j=1; j<7; ++j )
2909        {
2910          if( alekw < alem[j] ) // use linear interpolation/extrapolation
2911          {
2912            G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
2913            exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
2914            break;
2915          }
2916        }
2917        exh = 1.0 - exh;
2918      }
2919      const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2920      ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2921      ekin = std::max( 1.0e-6, ekin );
2922      xxh = 1.0;
2923      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2924           modifiedOriginal.GetDefinition() == aPiMinus) &&
2925           currentParticle.GetDefinition() == aPiZero &&
2926           G4UniformRand() <= logWeight) xxh = exh;
2927      dekin += ekin*(1.0-xxh);
2928      ekin *= xxh;
2929      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
2930        ++npions;
2931        ek1 += ekin;
2932      }
2933      currentParticle.SetKineticEnergy( ekin*GeV );
2934      pp = currentParticle.GetTotalMomentum()/MeV;
2935      pp1 = currentParticle.GetMomentum().mag()/MeV;
2936      if( pp1 < 0.001*MeV )
2937      {
2938        G4double costheta = 2.*G4UniformRand() - 1.;
2939        G4double sintheta = std::sqrt(1. - costheta*costheta);
2940        G4double phi = twopi*G4UniformRand();
2941        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2942                                     pp*sintheta*std::sin(phi)*MeV,
2943                                     pp*costheta*MeV ) ;
2944      }
2945      else
2946        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2947      ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2948      ekin = std::max( 1.0e-6, ekin );
2949      xxh = 1.0;
2950      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2951           modifiedOriginal.GetDefinition() == aPiMinus) &&
2952           targetParticle.GetDefinition() == aPiZero &&
2953           G4UniformRand() < logWeight) xxh = exh;
2954      dekin += ekin*(1.0-xxh);
2955      ekin *= xxh;
2956      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2957        ++npions;
2958        ek1 += ekin;
2959      }
2960      targetParticle.SetKineticEnergy( ekin*GeV );
2961      pp = targetParticle.GetTotalMomentum()/MeV;
2962      pp1 = targetParticle.GetMomentum().mag()/MeV;
2963      if( pp1 < 0.001*MeV )
2964      {
2965        G4double costheta = 2.*G4UniformRand() - 1.;
2966        G4double sintheta = std::sqrt(1. - costheta*costheta);
2967        G4double phi = twopi*G4UniformRand();
2968        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2969                                    pp*sintheta*std::sin(phi)*MeV,
2970                                    pp*costheta*MeV ) ;
2971      }
2972      else
2973        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2974      for( i=0; i<vecLen; ++i )
2975      {
2976        ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2977        ekin = std::max( 1.0e-6, ekin );
2978        xxh = 1.0;
2979        if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2980             modifiedOriginal.GetDefinition() == aPiMinus) &&
2981             vec[i]->GetDefinition() == aPiZero &&
2982             G4UniformRand() < logWeight) xxh = exh;
2983        dekin += ekin*(1.0-xxh);
2984        ekin *= xxh;
2985        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
2986          ++npions;
2987          ek1 += ekin;
2988        }
2989        vec[i]->SetKineticEnergy( ekin*GeV );
2990        pp = vec[i]->GetTotalMomentum()/MeV;
2991        pp1 = vec[i]->GetMomentum().mag()/MeV;
2992        if( pp1 < 0.001*MeV )
2993        {
2994          G4double costheta = 2.*G4UniformRand() - 1.;
2995          G4double sintheta = std::sqrt(1. - costheta*costheta);
2996          G4double phi = twopi*G4UniformRand();
2997          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2998                               pp*sintheta*std::sin(phi)*MeV,
2999                               pp*costheta*MeV ) ;
3000        }
3001        else
3002          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3003      }
3004    }
3005    if( (ek1 != 0.0) && (npions > 0) )
3006    {
3007      dekin = 1.0 + dekin/ek1;
3008      //
3009      //  first do the incident particle
3010      //
3011      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") 
3012      {
3013        currentParticle.SetKineticEnergy(
3014         std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
3015        pp = currentParticle.GetTotalMomentum()/MeV;
3016        pp1 = currentParticle.GetMomentum().mag()/MeV;
3017        if( pp1 < 0.001 )
3018        {
3019          G4double costheta = 2.*G4UniformRand() - 1.;
3020          G4double sintheta = std::sqrt(1. - costheta*costheta);
3021          G4double phi = twopi*G4UniformRand();
3022          currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3023                                       pp*sintheta*std::sin(phi)*MeV,
3024                                       pp*costheta*MeV ) ;
3025        } else {
3026          currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3027        }
3028      }
3029
3030      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") 
3031      {
3032        targetParticle.SetKineticEnergy(
3033         std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
3034        pp = targetParticle.GetTotalMomentum()/MeV;
3035        pp1 = targetParticle.GetMomentum().mag()/MeV;
3036        if( pp1 < 0.001 )
3037        {
3038          G4double costheta = 2.*G4UniformRand() - 1.;
3039          G4double sintheta = std::sqrt(1. - costheta*costheta);
3040          G4double phi = twopi*G4UniformRand();
3041          targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3042                                      pp*sintheta*std::sin(phi)*MeV,
3043                                      pp*costheta*MeV ) ;
3044        } else {
3045          targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3046        }
3047      }
3048
3049      for( i=0; i<vecLen; ++i )
3050      {
3051        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi")
3052        {
3053          vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
3054          pp = vec[i]->GetTotalMomentum()/MeV;
3055          pp1 = vec[i]->GetMomentum().mag()/MeV;
3056          if( pp1 < 0.001 )
3057          {
3058            G4double costheta = 2.*G4UniformRand() - 1.;
3059            G4double sintheta = std::sqrt(1. - costheta*costheta);
3060            G4double phi = twopi*G4UniformRand();
3061            vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3062                                 pp*sintheta*std::sin(phi)*MeV,
3063                                 pp*costheta*MeV ) ;
3064          } else {
3065            vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3066          }
3067        }
3068      } // for i
3069    } // if (ek1 != 0)
3070  }
3071 
3072 void G4ReactionDynamics::AddBlackTrackParticles(
3073   const G4double epnb,            // GeV
3074   const G4int npnb,
3075   const G4double edta,            // GeV
3076   const G4int ndta,
3077   const G4double sprob,
3078   const G4double kineticMinimum,  // GeV
3079   const G4double kineticFactor,   // GeV
3080   const G4ReactionProduct &modifiedOriginal,
3081   G4int PinNucleus,
3082   G4int NinNucleus,
3083   const G4Nucleus &targetNucleus,
3084   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3085   G4int &vecLen )
3086  {
3087    // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
3088    //
3089    // npnb is number of proton/neutron black track particles
3090    // ndta is the number of deuterons, tritons, and alphas produced
3091    // epnb is the kinetic energy available for proton/neutron black track particles
3092    // edta is the kinetic energy available for deuteron/triton/alpha particles
3093    //
3094   
3095    G4ParticleDefinition *aProton = G4Proton::Proton();
3096    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3097    G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3098    G4ParticleDefinition *aTriton = G4Triton::Triton();
3099    G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3100   
3101    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
3102    const G4double atomicWeight = targetNucleus.GetN();
3103    const G4double atomicNumber = targetNucleus.GetZ();
3104   
3105    const G4double ika1 = 3.6;
3106    const G4double ika2 = 35.56;
3107    const G4double ika3 = 6.45;
3108   
3109    G4int i;
3110    G4double pp;
3111    G4double kinCreated = 0;
3112    G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
3113
3114    // First add protons and neutrons to final state
3115
3116    if (npnb > 0)
3117    {
3118      G4double backwardKinetic = 0.0;
3119      G4int local_npnb = npnb;
3120      for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
3121      G4double local_epnb = epnb;
3122      if (ndta == 0) local_epnb += edta;   // Retrieve unused kinetic energy
3123      G4double ekin = local_epnb/std::max(1,local_npnb);
3124     
3125      for( i=0; i<local_npnb; ++i )
3126      {
3127        G4ReactionProduct * p1 = new G4ReactionProduct();
3128        if( backwardKinetic > local_epnb )
3129        {
3130          delete p1;
3131          break;   
3132        }
3133        G4double ran = G4UniformRand();
3134        G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
3135        if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
3136        backwardKinetic += kinetic;
3137        if( backwardKinetic > local_epnb )
3138           kinetic = std::max( kineticMinimum, local_epnb-(backwardKinetic-kinetic) );
3139
3140        if (G4UniformRand() > (1.0-atomicNumber/atomicWeight)) {
3141
3142          // Boil off a proton if there are any left, otherwise a neutron
3143
3144          if (PinNucleus > 0) {
3145            p1->SetDefinition( aProton );
3146            PinNucleus--;
3147          } else if (NinNucleus > 0) {
3148            p1->SetDefinition( aNeutron );
3149            NinNucleus--;
3150          } else {
3151            delete p1;
3152            break;     // no nucleons left in nucleus
3153          }
3154        } else {
3155
3156          // Boil off a neutron if there are any left, otherwise a proton
3157
3158          if (NinNucleus > 0) {
3159            p1->SetDefinition( aNeutron );
3160            NinNucleus--;
3161          } else if (PinNucleus > 0) {
3162            p1->SetDefinition( aProton );
3163            PinNucleus--;
3164          } else {
3165            delete p1;
3166            break;     // no nucleons left in nucleus
3167          }
3168        }
3169
3170        vec.SetElement( vecLen, p1 );
3171        G4double cost = G4UniformRand() * 2.0 - 1.0;
3172        G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
3173        G4double phi = twopi * G4UniformRand();
3174        vec[vecLen]->SetNewlyAdded( true );
3175        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3176        kinCreated+=kinetic;
3177        pp = vec[vecLen]->GetTotalMomentum()/MeV;
3178        vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3179                                    pp*sint*std::cos(phi)*MeV,
3180                                    pp*cost*MeV );
3181        vecLen++;
3182        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3183      }
3184
3185      if (NinNucleus > 0) {
3186        if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
3187        {
3188          G4double ekw = ekOriginal/GeV;
3189          G4int ika, kk = 0;
3190          if( ekw > 1.0 )ekw *= ekw;
3191          ekw = std::max( 0.1, ekw );
3192          ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/
3193                                             atomicWeight-ika2)/ika3)/ekw);
3194          if( ika > 0 )
3195          {
3196            for( i=(vecLen-1); i>=0; --i )
3197            {
3198              if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
3199              {
3200                vec[i]->SetDefinitionAndUpdateE( aNeutron );  // modified 22-Oct-97
3201                PinNucleus++;
3202                NinNucleus--;
3203                if( ++kk > ika )break;
3204              }
3205            }
3206          }
3207        }
3208      } // if (NinNucleus >0)
3209    } // if (npnb > 0)
3210
3211    //  Next try to add deuterons, tritons and alphas to final state
3212
3213    if (ndta > 0)
3214    {
3215      G4double backwardKinetic = 0.0;
3216      G4int local_ndta=ndta;
3217      for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
3218      G4double local_edta = edta;
3219      if (npnb == 0) local_edta += epnb;  // Retrieve unused kinetic energy
3220      G4double ekin = local_edta/std::max(1,local_ndta);
3221
3222      for( i=0; i<local_ndta; ++i )
3223      {
3224        G4ReactionProduct *p2 = new G4ReactionProduct();
3225        if( backwardKinetic > local_edta )
3226        {
3227          delete p2;
3228          break;
3229        }
3230        G4double ran = G4UniformRand();
3231        G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
3232        if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
3233        backwardKinetic += kinetic;
3234        if( backwardKinetic > local_edta )kinetic = local_edta-(backwardKinetic-kinetic);
3235        if( kinetic < 0.0 )kinetic = kineticMinimum;
3236        G4double cost = 2.0*G4UniformRand() - 1.0;
3237        G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
3238        G4double phi = twopi*G4UniformRand();
3239        ran = G4UniformRand();
3240        if (ran < 0.60) {
3241          if (PinNucleus > 0 && NinNucleus > 0) {
3242            p2->SetDefinition( aDeuteron );
3243            PinNucleus--;
3244            NinNucleus--;
3245          } else if (NinNucleus > 0) {
3246            p2->SetDefinition( aNeutron );
3247            NinNucleus--;
3248          } else if (PinNucleus > 0) {
3249            p2->SetDefinition( aProton );
3250            PinNucleus--;
3251          } else {
3252            delete p2;
3253            break;
3254          }
3255        } else if (ran < 0.90) {
3256          if (PinNucleus > 0 && NinNucleus > 1) {
3257            p2->SetDefinition( aTriton );
3258            PinNucleus--;
3259            NinNucleus -= 2;
3260          } else if (PinNucleus > 0 && NinNucleus > 0) {
3261            p2->SetDefinition( aDeuteron );
3262            PinNucleus--;
3263            NinNucleus--;
3264          } else if (NinNucleus > 0) {
3265            p2->SetDefinition( aNeutron );
3266            NinNucleus--;
3267          } else if (PinNucleus > 0) {
3268            p2->SetDefinition( aProton );
3269            PinNucleus--;
3270          } else {
3271            delete p2;
3272            break;
3273          }
3274        } else {
3275          if (PinNucleus > 1 && NinNucleus > 1) {
3276            p2->SetDefinition( anAlpha );
3277            PinNucleus -= 2;
3278            NinNucleus -= 2;
3279          } else if (PinNucleus > 0 && NinNucleus > 1) {
3280            p2->SetDefinition( aTriton );
3281            PinNucleus--;
3282            NinNucleus -= 2;
3283          } else if (PinNucleus > 0 && NinNucleus > 0) {
3284            p2->SetDefinition( aDeuteron );
3285            PinNucleus--;
3286            NinNucleus--;
3287          } else if (NinNucleus > 0) {
3288            p2->SetDefinition( aNeutron );
3289            NinNucleus--;
3290          } else if (PinNucleus > 0) {
3291            p2->SetDefinition( aProton );
3292            PinNucleus--;
3293          } else {
3294            delete p2;
3295            break;
3296          }
3297        }
3298
3299        vec.SetElement( vecLen, p2 );
3300        vec[vecLen]->SetNewlyAdded( true );
3301        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3302        kinCreated+=kinetic;
3303        pp = vec[vecLen]->GetTotalMomentum()/MeV;
3304        vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3305                                    pp*sint*std::cos(phi)*MeV,
3306                                    pp*cost*MeV );
3307      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3308      }
3309    } // if (ndta > 0)
3310
3311    //    G4double delta = epnb+edta - kinCreated;
3312  }
3313
3314
3315 std::pair<G4int, G4int> G4ReactionDynamics::GetFinalStateNucleons(
3316   const G4DynamicParticle* originalTarget,
3317   const G4FastVector<G4ReactionProduct,GHADLISTSIZE>& vec, 
3318   const G4int& vecLen)
3319  {
3320    // Get number of protons and neutrons removed from the target nucleus
3321 
3322    G4int protonsRemoved = 0;
3323    G4int neutronsRemoved = 0;
3324    if (originalTarget->GetDefinition()->GetParticleName() == "proton")
3325      protonsRemoved++;
3326    else
3327      neutronsRemoved++;
3328 
3329    G4String secName;
3330    for (G4int i = 0; i < vecLen; i++) {
3331      secName = vec[i]->GetDefinition()->GetParticleName();
3332      if (secName == "proton") {
3333        protonsRemoved++;
3334      } else if (secName == "neutron") {
3335        neutronsRemoved++;
3336      } else if (secName == "anti_proton") {
3337        protonsRemoved--;
3338      } else if (secName == "anti_neutron") {
3339        neutronsRemoved--;
3340      }
3341    }
3342
3343    return std::pair<G4int, G4int>(protonsRemoved, neutronsRemoved);
3344  }
3345
3346
3347 void G4ReactionDynamics::MomentumCheck(
3348   const G4ReactionProduct &modifiedOriginal,
3349   G4ReactionProduct &currentParticle,
3350   G4ReactionProduct &targetParticle,
3351   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3352   G4int &vecLen )
3353  {
3354    const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
3355    G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
3356    G4double pMass;
3357    if( testMomentum >= pOriginal )
3358    {
3359      pMass = currentParticle.GetMass()/MeV;
3360      currentParticle.SetTotalEnergy(
3361       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3362      currentParticle.SetMomentum(
3363       currentParticle.GetMomentum() * (pOriginal/testMomentum) );
3364    }
3365    testMomentum = targetParticle.GetMomentum().mag()/MeV;
3366    if( testMomentum >= pOriginal )
3367    {
3368      pMass = targetParticle.GetMass()/MeV;
3369      targetParticle.SetTotalEnergy(
3370       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3371      targetParticle.SetMomentum(
3372       targetParticle.GetMomentum() * (pOriginal/testMomentum) );
3373    }
3374    for( G4int i=0; i<vecLen; ++i )
3375    {
3376      testMomentum = vec[i]->GetMomentum().mag()/MeV;
3377      if( testMomentum >= pOriginal )
3378      {
3379        pMass = vec[i]->GetMass()/MeV;
3380        vec[i]->SetTotalEnergy(
3381         std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3382        vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
3383      }
3384    }
3385  }
3386
3387 void G4ReactionDynamics::ProduceStrangeParticlePairs(
3388   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3389   G4int &vecLen,
3390   const G4ReactionProduct &modifiedOriginal,
3391   const G4DynamicParticle *originalTarget, 
3392   G4ReactionProduct &currentParticle,
3393   G4ReactionProduct &targetParticle,
3394   G4bool &incidentHasChanged,
3395   G4bool &targetHasChanged )
3396  {
3397    // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
3398    //
3399    // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
3400    //                            K+ Y0, K0 Y+,  K0 Y-
3401    // For antibaryon induced reactions half of the cross sections KB YB
3402    // pairs are produced.  Charge is not conserved, no experimental data available
3403    // for exclusive reactions, therefore some average behaviour assumed.
3404    // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
3405    //
3406    if( vecLen == 0 )return;
3407    //
3408    // the following protects against annihilation processes
3409    //
3410    if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
3411   
3412    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
3413    const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
3414    G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
3415    G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
3416                                        targetMass*targetMass +
3417                                        2.0*targetMass*etOriginal );  // GeV
3418    G4double currentMass = currentParticle.GetMass()/GeV;
3419    G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
3420    if( availableEnergy <= 1.0 )return;
3421   
3422    G4ParticleDefinition *aProton = G4Proton::Proton();
3423    G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
3424    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3425    G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
3426    G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
3427    G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
3428    G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
3429    G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
3430    G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
3431    G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
3432    G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
3433    G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
3434    G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
3435    G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
3436    G4ParticleDefinition *aLambda = G4Lambda::Lambda();
3437    G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
3438   
3439    const G4double protonMass = aProton->GetPDGMass()/GeV;
3440    const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
3441    //
3442    // determine the center of mass energy bin
3443    //
3444    const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
3445
3446    G4int ibin, i3, i4;
3447    G4double avk, avy, avn, ran;
3448    G4int i = 1;
3449    while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
3450    if( i == 12 )
3451      ibin = 11;
3452    else
3453      ibin = i;
3454    //
3455    // the fortran code chooses a random replacement of produced kaons
3456    //  but does not take into account charge conservation
3457    //
3458    if( vecLen == 1 )  // we know that vecLen > 0
3459    {
3460      i3 = 0;
3461      i4 = 1;   // note that we will be adding a new secondary particle in this case only
3462    }
3463    else               // otherwise  0 <= i3,i4 < vecLen
3464    {
3465      G4double ran = G4UniformRand();
3466      while( ran == 1.0 )ran = G4UniformRand();
3467      i4 = i3 = G4int( vecLen*ran );
3468      while( i3 == i4 )
3469      {
3470        ran = G4UniformRand();
3471        while( ran == 1.0 )ran = G4UniformRand();
3472        i4 = G4int( vecLen*ran );
3473      }
3474    }
3475    //
3476    // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
3477    //
3478    const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
3479                               0.0975, 0.123, 0.28,  0.398,  0.495,  0.573 };
3480    const G4double avky[] = { 0.005, 0.03,  0.064, 0.095, 0.115, 0.13,
3481                              0.145, 0.155, 0.20,  0.205, 0.210, 0.212 };
3482    const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
3483                               0.04,    0.05,   0.12,   0.15,   0.18, 0.20 };
3484   
3485    avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3486      /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
3487    avk = std::exp(avk);
3488   
3489    avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3490      /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
3491    avy = std::exp(avy);
3492   
3493    avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3494      /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
3495    avn = std::exp(avn);
3496   
3497    if( avk+avy+avn <= 0.0 )return;
3498   
3499    if( currentMass < protonMass )avy /= 2.0;
3500    if( targetMass < protonMass )avy = 0.0;
3501    avy += avk+avn;
3502    avk += avn;
3503    ran = G4UniformRand();
3504    if(  ran < avn )
3505    {
3506      if( availableEnergy < 2.0 )return;
3507      if( vecLen == 1 )                              // add a new secondary
3508      {
3509        G4ReactionProduct *p1 = new G4ReactionProduct;
3510        if( G4UniformRand() < 0.5 )
3511        {
3512          vec[0]->SetDefinition( aNeutron );
3513          p1->SetDefinition( anAntiNeutron );
3514          (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3515          vec[0]->SetMayBeKilled(false);
3516          p1->SetMayBeKilled(false);
3517        }
3518        else
3519        {
3520          vec[0]->SetDefinition( aProton );
3521          p1->SetDefinition( anAntiProton );
3522          (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3523          vec[0]->SetMayBeKilled(false);
3524          p1->SetMayBeKilled(false);
3525        }
3526        vec.SetElement( vecLen++, p1 );
3527      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3528      }
3529      else
3530      {                                             // replace two secondaries
3531        if( G4UniformRand() < 0.5 )
3532        {
3533          vec[i3]->SetDefinition( aNeutron );
3534          vec[i4]->SetDefinition( anAntiNeutron );
3535          vec[i3]->SetMayBeKilled(false);
3536          vec[i4]->SetMayBeKilled(false);
3537        }
3538        else
3539        {
3540          vec[i3]->SetDefinition( aProton );
3541          vec[i4]->SetDefinition( anAntiProton );
3542          vec[i3]->SetMayBeKilled(false);
3543          vec[i4]->SetMayBeKilled(false);
3544        }
3545      }
3546    }
3547    else if( ran < avk )
3548    {
3549      if( availableEnergy < 1.0 )return;
3550     
3551      const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
3552                               0.6875, 0.7500, 0.8750, 1.000 };
3553      const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
3554      const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
3555      ran = G4UniformRand();
3556      i = 0;
3557      while( (i<9) && (ran>=kkb[i]) )++i;
3558      if( i == 9 )return;
3559      //
3560      // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
3561      // charge       +  -   +  0   +  0   0  0   0  0   0  0   0  0   0  -   0  -
3562      //
3563      switch( ipakkb1[i] )
3564      {
3565       case 10:
3566         vec[i3]->SetDefinition( aKaonPlus );
3567         vec[i3]->SetMayBeKilled(false);
3568         break;
3569       case 11:
3570         vec[i3]->SetDefinition( aKaonZS );
3571         vec[i3]->SetMayBeKilled(false);
3572         break;
3573       case 12:
3574         vec[i3]->SetDefinition( aKaonZL );
3575         vec[i3]->SetMayBeKilled(false);
3576         break;
3577      }
3578      if( vecLen == 1 )                          // add a secondary
3579      {
3580        G4ReactionProduct *p1 = new G4ReactionProduct;
3581        switch( ipakkb2[i] )
3582        {
3583         case 11:
3584           p1->SetDefinition( aKaonZS );
3585           p1->SetMayBeKilled(false);
3586           break;
3587         case 12:
3588           p1->SetDefinition( aKaonZL );
3589           p1->SetMayBeKilled(false);
3590           break;
3591         case 13:
3592           p1->SetDefinition( aKaonMinus );
3593           p1->SetMayBeKilled(false);
3594           break;
3595        }
3596        (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3597        vec.SetElement( vecLen++, p1 );
3598      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3599      }
3600      else                                        // replace
3601      {
3602        switch( ipakkb2[i] )
3603        {
3604         case 11:
3605           vec[i4]->SetDefinition( aKaonZS );
3606           vec[i4]->SetMayBeKilled(false);
3607           break;
3608         case 12:
3609           vec[i4]->SetDefinition( aKaonZL );
3610           vec[i4]->SetMayBeKilled(false);
3611           break;
3612         case 13:
3613           vec[i4]->SetDefinition( aKaonMinus );
3614           vec[i4]->SetMayBeKilled(false);
3615           break;
3616        }
3617      }
3618    }
3619    else if( ran < avy )
3620    {
3621      if( availableEnergy < 1.6 )return;
3622     
3623      const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
3624                              0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
3625      const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
3626      const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
3627      const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
3628      const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
3629      ran = G4UniformRand();
3630      i = 0;
3631      while( (i<12) && (ran>ky[i]) )++i;
3632      if( i == 12 )return;
3633      if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
3634      {
3635        // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
3636        //             0  +   0  0   0  0   +  +   +  0   +  0
3637        //
3638        //             21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
3639        //             0  +   0  0   0  0   -  +   -  0   -  0
3640        switch( ipaky1[i] )
3641        {
3642         case 18:
3643           targetParticle.SetDefinition( aLambda );
3644           break;
3645         case 20:
3646           targetParticle.SetDefinition( aSigmaPlus );
3647           break;
3648         case 21:
3649           targetParticle.SetDefinition( aSigmaZero );
3650           break;
3651         case 22:
3652           targetParticle.SetDefinition( aSigmaMinus );
3653           break;
3654        }
3655        targetHasChanged = true;
3656        switch( ipaky2[i] )
3657        {
3658         case 10:
3659           vec[i3]->SetDefinition( aKaonPlus ); 
3660           vec[i3]->SetMayBeKilled(false);
3661           break;
3662         case 11:
3663           vec[i3]->SetDefinition( aKaonZS );
3664           vec[i3]->SetMayBeKilled(false);
3665           break;
3666         case 12:
3667           vec[i3]->SetDefinition( aKaonZL );
3668           vec[i3]->SetMayBeKilled(false);
3669           break;
3670        }
3671      }
3672      else  // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
3673      {
3674        // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
3675        //              24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
3676        if( (currentParticle.GetDefinition() == anAntiProton) ||
3677            (currentParticle.GetDefinition() == anAntiNeutron) ||
3678            (currentParticle.GetDefinition() == anAntiLambda) ||
3679            (currentMass > sigmaMinusMass) )
3680        {
3681          switch( ipakyb1[i] )
3682          {
3683           case 19:
3684             currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
3685             break;
3686           case 23:
3687             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
3688             break;
3689           case 24:
3690             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
3691             break;
3692           case 25:
3693             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
3694             break;
3695          }
3696          incidentHasChanged = true;
3697          switch( ipakyb2[i] )
3698          {
3699           case 11:
3700             vec[i3]->SetDefinition( aKaonZS ); 
3701             vec[i3]->SetMayBeKilled(false);
3702             break;
3703           case 12:
3704             vec[i3]->SetDefinition( aKaonZL );
3705             vec[i3]->SetMayBeKilled(false);
3706             break;
3707           case 13:
3708             vec[i3]->SetDefinition( aKaonMinus );
3709             vec[i3]->SetMayBeKilled(false);
3710             break;
3711          }
3712        }
3713        else
3714        {
3715          switch( ipaky1[i] )
3716          {
3717           case 18:
3718             currentParticle.SetDefinitionAndUpdateE( aLambda );
3719             break;
3720           case 20:
3721             currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
3722             break;
3723           case 21:
3724             currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
3725             break;
3726           case 22:
3727             currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
3728             break;
3729          }
3730          incidentHasChanged = true;
3731          switch( ipaky2[i] )
3732          {
3733           case 10:
3734             vec[i3]->SetDefinition( aKaonPlus ); 
3735             vec[i3]->SetMayBeKilled(false);
3736             break;
3737           case 11:
3738             vec[i3]->SetDefinition( aKaonZS );
3739             vec[i3]->SetMayBeKilled(false);
3740             break;
3741           case 12:
3742             vec[i3]->SetDefinition( aKaonZL );
3743             vec[i3]->SetMayBeKilled(false);
3744             break;
3745          }
3746        }
3747      }
3748    }
3749    else return;
3750    //
3751    //  check the available energy
3752    //   if there is not enough energy for kkb/ky pair production
3753    //   then reduce the number of secondary particles
3754    //  NOTE:
3755    //        the number of secondaries may have been changed
3756    //        the incident and/or target particles may have changed
3757    //        charge conservation is ignored (as well as strangness conservation)
3758    //
3759    currentMass = currentParticle.GetMass()/GeV;
3760    targetMass = targetParticle.GetMass()/GeV;
3761   
3762    G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
3763    for( i=0; i<vecLen; ++i )
3764    {
3765      energyCheck -= vec[i]->GetMass()/GeV;
3766      if( energyCheck < 0.0 )      // chop off the secondary List
3767      {
3768        vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
3769        G4int j;
3770        for(j=i; j<vecLen; j++) delete vec[j];
3771        break;
3772      }
3773    }
3774    return;
3775  }
3776
3777 void
3778  G4ReactionDynamics::NuclearReaction(
3779   G4FastVector<G4ReactionProduct,4> &vec,
3780   G4int &vecLen,
3781   const G4HadProjectile *originalIncident,
3782   const G4Nucleus &targetNucleus,
3783   const G4double theAtomicMass,
3784   const G4double *mass )
3785  {
3786    // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
3787    //
3788    // Nuclear reaction kinematics at low energies
3789    //
3790    G4ParticleDefinition *aGamma = G4Gamma::Gamma();
3791    G4ParticleDefinition *aProton = G4Proton::Proton();
3792    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3793    G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3794    G4ParticleDefinition *aTriton = G4Triton::Triton();
3795    G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3796   
3797    const G4double aProtonMass = aProton->GetPDGMass()/MeV;
3798    const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
3799    const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
3800    const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
3801    const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
3802
3803    G4ReactionProduct currentParticle;
3804    currentParticle = *originalIncident;
3805    //
3806    // Set beam particle, take kinetic energy of current particle as the
3807    // fundamental quantity.  Due to the difficult kinematic, all masses have to
3808    // be assigned the best measured values
3809    //
3810    G4double p = currentParticle.GetTotalMomentum();
3811    G4double pp = currentParticle.GetMomentum().mag();
3812    if( pp <= 0.001*MeV )
3813    {
3814      G4double phinve = twopi*G4UniformRand();
3815      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3816      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3817                                   p*std::sin(rthnve)*std::sin(phinve),
3818                                   p*std::cos(rthnve) );
3819    }
3820    else
3821      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3822    //
3823    // calculate Q-value of reactions
3824    //
3825    G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
3826    G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
3827    G4double qv = currentKinetic + theAtomicMass + currentMass;
3828   
3829    G4double qval[9];
3830    qval[0] = qv - mass[0];
3831    qval[1] = qv - mass[1] - aNeutronMass;
3832    qval[2] = qv - mass[2] - aProtonMass;
3833    qval[3] = qv - mass[3] - aDeuteronMass;
3834    qval[4] = qv - mass[4] - aTritonMass;
3835    qval[5] = qv - mass[5] - anAlphaMass;
3836    qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
3837    qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
3838    qval[8] = qv - mass[8] - aProtonMass  - aProtonMass;
3839   
3840    if( currentParticle.GetDefinition() == aNeutron )
3841    {
3842      const G4double A = targetNucleus.GetN();    // atomic weight
3843      if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
3844        qval[0] = 0.0;
3845      if( G4UniformRand() >= currentKinetic/7.9254*A )
3846        qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
3847    }
3848    else
3849      qval[0] = 0.0;
3850   
3851    G4int i;
3852    qv = 0.0;
3853    for( i=0; i<9; ++i )
3854    {
3855      if( mass[i] < 500.0*MeV )qval[i] = 0.0;
3856      if( qval[i] < 0.0 )qval[i] = 0.0;
3857      qv += qval[i];
3858    }
3859    G4double qv1 = 0.0;
3860    G4double ran = G4UniformRand();
3861    G4int index;
3862    for( index=0; index<9; ++index )
3863    {
3864      if( qval[index] > 0.0 )
3865      {
3866        qv1 += qval[index]/qv;
3867        if( ran <= qv1 )break;
3868      }
3869    }
3870    if( index == 9 )  // loop continued to the end
3871    {
3872      throw G4HadronicException(__FILE__, __LINE__,
3873           "G4ReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
3874    }
3875    G4double ke = currentParticle.GetKineticEnergy()/GeV;
3876    G4int nt = 2;
3877    if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
3878   
3879    G4ReactionProduct **v = new G4ReactionProduct * [3];
3880    v[0] =  new G4ReactionProduct;
3881    v[1] =  new G4ReactionProduct;
3882    v[2] =  new G4ReactionProduct;
3883   
3884    v[0]->SetMass( mass[index]*MeV );
3885    switch( index )
3886    {
3887     case 0:
3888       v[1]->SetDefinition( aGamma );
3889       v[2]->SetDefinition( aGamma );
3890       break;
3891     case 1:
3892       v[1]->SetDefinition( aNeutron );
3893       v[2]->SetDefinition( aGamma );
3894       break;
3895     case 2:
3896       v[1]->SetDefinition( aProton );
3897       v[2]->SetDefinition( aGamma );
3898       break;
3899     case 3:
3900       v[1]->SetDefinition( aDeuteron );
3901       v[2]->SetDefinition( aGamma );
3902       break;
3903     case 4:
3904       v[1]->SetDefinition( aTriton );
3905       v[2]->SetDefinition( aGamma );
3906       break;
3907     case 5:
3908       v[1]->SetDefinition( anAlpha );
3909       v[2]->SetDefinition( aGamma );
3910       break;
3911     case 6:
3912       v[1]->SetDefinition( aNeutron );
3913       v[2]->SetDefinition( aNeutron );
3914       break;
3915     case 7:
3916       v[1]->SetDefinition( aNeutron );
3917       v[2]->SetDefinition( aProton );
3918       break;
3919     case 8:
3920       v[1]->SetDefinition( aProton );
3921       v[2]->SetDefinition( aProton );
3922       break;
3923    }
3924    //
3925    // calculate centre of mass energy
3926    //
3927    G4ReactionProduct pseudo1;
3928    pseudo1.SetMass( theAtomicMass*MeV );
3929    pseudo1.SetTotalEnergy( theAtomicMass*MeV );
3930    G4ReactionProduct pseudo2 = currentParticle + pseudo1;
3931    pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
3932    //
3933    // use phase space routine in centre of mass system
3934    //
3935    G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
3936    tempV.Initialize( nt );
3937    G4int tempLen = 0;
3938    tempV.SetElement( tempLen++, v[0] );
3939    tempV.SetElement( tempLen++, v[1] );
3940    if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
3941    G4bool constantCrossSection = true;
3942    GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
3943    v[0]->Lorentz( *v[0], pseudo2 );
3944    v[1]->Lorentz( *v[1], pseudo2 );
3945    if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
3946   
3947    G4bool particleIsDefined = false;
3948    if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
3949    {
3950      v[0]->SetDefinition( aProton );
3951      particleIsDefined = true;
3952    }
3953    else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
3954    {
3955      v[0]->SetDefinition( aNeutron );
3956      particleIsDefined = true;
3957    }
3958    else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
3959    {
3960      v[0]->SetDefinition( aDeuteron );
3961      particleIsDefined = true;
3962    }
3963    else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
3964    {
3965      v[0]->SetDefinition( aTriton );
3966      particleIsDefined = true;
3967    }
3968    else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
3969    {
3970      v[0]->SetDefinition( anAlpha );
3971      particleIsDefined = true;
3972    }
3973    currentParticle.SetKineticEnergy(
3974     std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
3975    p = currentParticle.GetTotalMomentum();
3976    pp = currentParticle.GetMomentum().mag();
3977    if( pp <= 0.001*MeV )
3978    {
3979      G4double phinve = twopi*G4UniformRand();
3980      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3981      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3982                                   p*std::sin(rthnve)*std::sin(phinve),
3983                                   p*std::cos(rthnve) );
3984    }
3985    else
3986      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3987   
3988    if( particleIsDefined )
3989    {
3990      v[0]->SetKineticEnergy(
3991       std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
3992      p = v[0]->GetTotalMomentum();
3993      pp = v[0]->GetMomentum().mag();
3994      if( pp <= 0.001*MeV )
3995      {
3996        G4double phinve = twopi*G4UniformRand();
3997        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
3998        v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3999                          p*std::sin(rthnve)*std::sin(phinve),
4000                          p*std::cos(rthnve) );
4001      }
4002      else
4003        v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
4004    }
4005    if( (v[1]->GetDefinition() == aDeuteron) ||
4006        (v[1]->GetDefinition() == aTriton)   ||
4007        (v[1]->GetDefinition() == anAlpha) ) 
4008      v[1]->SetKineticEnergy(
4009       std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
4010    else
4011      v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
4012   
4013    p = v[1]->GetTotalMomentum();
4014    pp = v[1]->GetMomentum().mag();
4015    if( pp <= 0.001*MeV )
4016    {
4017      G4double phinve = twopi*G4UniformRand();
4018      G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4019      v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4020                        p*std::sin(rthnve)*std::sin(phinve),
4021                        p*std::cos(rthnve) );
4022    }
4023    else
4024      v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
4025   
4026    if( nt == 3 )
4027    {
4028      if( (v[2]->GetDefinition() == aDeuteron) ||
4029          (v[2]->GetDefinition() == aTriton)   ||
4030          (v[2]->GetDefinition() == anAlpha) ) 
4031        v[2]->SetKineticEnergy(
4032         std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
4033      else
4034        v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
4035     
4036      p = v[2]->GetTotalMomentum();
4037      pp = v[2]->GetMomentum().mag();
4038      if( pp <= 0.001*MeV )
4039      {
4040        G4double phinve = twopi*G4UniformRand();
4041        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4042        v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4043                          p*std::sin(rthnve)*std::sin(phinve),
4044                          p*std::cos(rthnve) );
4045      }
4046      else
4047        v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
4048    }
4049    G4int del;
4050    for(del=0; del<vecLen; del++) delete vec[del];
4051    vecLen = 0;
4052    if( particleIsDefined )
4053    {
4054      vec.SetElement( vecLen++, v[0] );
4055    }
4056    else
4057    {
4058      delete v[0];
4059    }
4060    vec.SetElement( vecLen++, v[1] );
4061    if( nt == 3 )
4062    {
4063      vec.SetElement( vecLen++, v[2] );
4064    }
4065    else
4066    {
4067      delete v[2];
4068    }
4069    delete [] v;
4070    return;
4071  }
4072 
4073 /* end of file */
4074 
Note: See TracBrowser for help on using the repository browser.