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

Last change on this file since 1315 was 1315, checked in by garnier, 14 years ago

update geant4-09-04-beta-cand-01 interfaces-V09-03-09 vis-V09-03-08

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 = G4double(targetNucleus.GetA_asInt());
187    const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
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]) ) );
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]) ) );
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]) ) );
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
921    //
922    // Target particle finished.
923    //
924    // Now produce backward nucleons with a cluster model
925    //
926    pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
927    pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
928    pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
929    if( backwardNucleonCount == 1 )  // target particle is the only backward nucleon
930    {
931      G4double ekin =
932        std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
933
934      if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
935      vecMass = targetParticle.GetMass()/GeV;
936      totalEnergy = ekin+vecMass;
937      targetParticle.SetTotalEnergy( totalEnergy*GeV );
938      pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
939      pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
940      if( pp1 < 1.0e-6*GeV )
941      { 
942        G4double costheta = 2.*G4UniformRand() - 1.;
943        G4double sintheta = std::sqrt(1. - costheta*costheta);
944        G4double phi = twopi*G4UniformRand();
945        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
946                                    pp*sintheta*std::sin(phi)*MeV,
947                                    pp*costheta*MeV ) ;
948      } else {
949        targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
950      }
951      pseudoParticle[5] = pseudoParticle[5] + targetParticle;
952    }
953    else  // more than one backward nucleon
954    {
955      const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
956      const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
957      // Replaced the following min function to get correct behaviour on DEC.
958      // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
959      G4int tempCount;
960      if (backwardNucleonCount < 5)
961        {
962          tempCount = backwardNucleonCount;
963        }
964      else
965        {
966          tempCount = 5;
967        }
968      tempCount--;
969      //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
970      //cout << "tempCount " << tempCount << G4endl;
971      G4double rmb0 = 0.0;
972      if( targetParticle.GetSide() == -3 )
973        rmb0 += targetParticle.GetMass()/GeV;
974      for( i=0; i<vecLen; ++i )
975      {
976        if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
977      }
978      rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
979      totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
980      vecMass = std::min( rmb, totalEnergy );
981      pseudoParticle[6].SetMass( vecMass*GeV );
982      pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
983      pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
984      if( pp1 < 1.0e-6*GeV )
985      {
986        G4double costheta = 2.*G4UniformRand() - 1.;
987        G4double sintheta = std::sqrt(1. - costheta*costheta);
988        G4double phi = twopi*G4UniformRand();
989        pseudoParticle[6].SetMomentum( -pp*sintheta*std::cos(phi)*MeV,
990                                       -pp*sintheta*std::sin(phi)*MeV,
991                                       -pp*costheta*MeV ) ;
992      }
993      else
994        pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
995     
996      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;  // tempV contains the backward nucleons
997      tempV.Initialize( backwardNucleonCount );
998      G4int tempLen = 0;
999      if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
1000      for( i=0; i<vecLen; ++i )
1001      {
1002        if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
1003      }
1004      if( tempLen != backwardNucleonCount )
1005      {
1006        G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
1007        G4cerr << "tempLen = " << tempLen;
1008        G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
1009        G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
1010        G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
1011        for( i=0; i<vecLen; ++i )
1012          G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
1013        G4Exception("G4ReactionDynamics::GenerateXandPt", "601", 
1014                    FatalException, "Mismatch in nucleon count");
1015      }
1016      constantCrossSection = true;
1017      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1018      if( tempLen >= 2 )
1019      {
1020        wgt = GenerateNBodyEvent(
1021         pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
1022         // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1023        if( targetParticle.GetSide() == -3 )
1024        {
1025          targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1026          // tempV contains the real stuff
1027          pseudoParticle[5] = pseudoParticle[5] + targetParticle;
1028        }
1029        for( i=0; i<vecLen; ++i )
1030        {
1031          if( vec[i]->GetSide() == -3 )
1032          {
1033            vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1034            pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
1035          }
1036        }
1037      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1038      }
1039    }
1040    //
1041    //  Lorentz transformation in lab system
1042    //
1043    if( vecLen == 0 )return false;  // all the secondaries have been eliminated
1044      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1045   
1046    currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
1047    targetParticle.Lorentz( targetParticle, pseudoParticle[1] );   
1048    for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
1049
1050      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1051    //
1052    // leadFlag will be true
1053    //  iff original particle is at least as heavy as K+ and not a proton or
1054    //  neutron AND if incident particle is at least as heavy as K+ and it is
1055    //  not a proton or neutron leadFlag is set to the incident particle
1056    //  or
1057    //  target particle is at least as heavy as K+ and it is not a proton or
1058    //  neutron leadFlag is set to the target particle
1059    //
1060    G4bool leadingStrangeParticleHasChanged = true;
1061    if( leadFlag )
1062    {
1063      if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1064        leadingStrangeParticleHasChanged = false;
1065      if( leadingStrangeParticleHasChanged &&
1066          ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
1067        leadingStrangeParticleHasChanged = false;
1068      if( leadingStrangeParticleHasChanged )
1069      {
1070        for( i=0; i<vecLen; i++ )
1071        {
1072          if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1073          {
1074            leadingStrangeParticleHasChanged = false;
1075            break;
1076          }
1077        }
1078      }
1079      if( leadingStrangeParticleHasChanged )
1080      {
1081        G4bool leadTest = 
1082          (leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1083           leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "pi");
1084        G4bool targetTest =
1085          (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1086           targetParticle.GetDefinition()->GetParticleSubType() == "pi");
1087       
1088        // following modified by JLC 22-Oct-97
1089         
1090        if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
1091        {
1092          targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1093          targetHasChanged = true;
1094      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1095        }
1096        else
1097        {
1098          currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1099          incidentHasChanged = false;
1100      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1101        }
1102      }
1103    }   // end of if( leadFlag )
1104
1105    // Get number of final state nucleons and nucleons remaining in
1106    // target nucleus
1107   
1108    std::pair<G4int, G4int> finalStateNucleons = 
1109      GetFinalStateNucleons(originalTarget, vec, vecLen);
1110
1111    G4int protonsInFinalState = finalStateNucleons.first;
1112    G4int neutronsInFinalState = finalStateNucleons.second;
1113
1114    G4int numberofFinalStateNucleons = 
1115      protonsInFinalState + neutronsInFinalState;
1116
1117    if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1118        targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1119        originalIncident->GetDefinition()->GetPDGMass() < 
1120                                   G4Lambda::Lambda()->GetPDGMass())
1121      numberofFinalStateNucleons++;
1122
1123    numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
1124
1125    G4int PinNucleus = std::max(0, 
1126      targetNucleus.GetZ_asInt() - protonsInFinalState);
1127    G4int NinNucleus = std::max(0,
1128      targetNucleus.GetN_asInt() - neutronsInFinalState);
1129
1130    pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1131    pseudoParticle[3].SetMass( mOriginal*GeV );
1132    pseudoParticle[3].SetTotalEnergy(
1133     std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
1134   
1135    G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
1136    G4int diff = 0;
1137    if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
1138    if(numberofFinalStateNucleons == 1) diff = 0;
1139    pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
1140    pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1141    pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1142   
1143    G4double theoreticalKinetic =
1144      pseudoParticle[3].GetTotalEnergy()/MeV +
1145      pseudoParticle[4].GetTotalEnergy()/MeV -
1146      currentParticle.GetMass()/MeV -
1147      targetParticle.GetMass()/MeV;
1148   
1149    G4double simulatedKinetic =
1150      currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
1151   
1152    pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
1153    pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
1154    pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
1155   
1156    pseudoParticle[7].SetZero();
1157    pseudoParticle[7] = pseudoParticle[7] + currentParticle;
1158    pseudoParticle[7] = pseudoParticle[7] + targetParticle;
1159
1160    for( i=0; i<vecLen; ++i )
1161    {
1162      pseudoParticle[7] = pseudoParticle[7] + *vec[i];
1163      simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
1164      theoreticalKinetic -= vec[i]->GetMass()/MeV;
1165    }
1166
1167    if( vecLen <= 16 && vecLen > 0 )
1168    {
1169      // must create a new set of ReactionProducts here because GenerateNBody will
1170      // modify the momenta for the particles, and we don't want to do this
1171      //
1172      G4ReactionProduct tempR[130];
1173      tempR[0] = currentParticle;
1174      tempR[1] = targetParticle;
1175      for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
1176      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1177      tempV.Initialize( vecLen+2 );
1178      G4int tempLen = 0;
1179      for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
1180      constantCrossSection = true;
1181
1182      wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
1183                                pseudoParticle[4].GetTotalEnergy()/MeV,
1184                                constantCrossSection, tempV, tempLen );
1185      if (wgt == -1) {
1186        G4double Qvalue = 0;
1187        for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
1188        wgt = GenerateNBodyEvent( Qvalue/MeV,
1189                                  constantCrossSection, tempV, tempLen );
1190      }
1191      if(wgt>-.5)
1192      {
1193        theoreticalKinetic = 0.0;
1194        for( i=0; i<tempLen; ++i )
1195        {
1196          pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
1197          theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
1198        }
1199      }
1200      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1201    }
1202    //
1203    //  Make sure, that the kinetic energies are correct
1204    //
1205    if( simulatedKinetic != 0.0 )
1206    {
1207      wgt = (theoreticalKinetic)/simulatedKinetic;
1208      theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
1209      simulatedKinetic = theoreticalKinetic;
1210      currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1211      pp = currentParticle.GetTotalMomentum()/MeV;
1212      pp1 = currentParticle.GetMomentum().mag()/MeV;
1213      if( pp1 < 1.0e-6*GeV )
1214      {
1215        G4double costheta = 2.*G4UniformRand() - 1.;
1216        G4double sintheta = std::sqrt(1. - costheta*costheta);
1217        G4double phi = twopi*G4UniformRand();
1218        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1219                                     pp*sintheta*std::sin(phi)*MeV,
1220                                     pp*costheta*MeV ) ;
1221      }
1222      else
1223      {
1224        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
1225      }
1226      theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
1227      targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1228      simulatedKinetic += theoreticalKinetic;
1229      pp = targetParticle.GetTotalMomentum()/MeV;
1230      pp1 = targetParticle.GetMomentum().mag()/MeV;
1231      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1232      if( pp1 < 1.0e-6*GeV )
1233      {
1234        G4double costheta = 2.*G4UniformRand() - 1.;
1235        G4double sintheta = std::sqrt(1. - costheta*costheta);
1236        G4double phi = twopi*G4UniformRand();
1237        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1238                                    pp*sintheta*std::sin(phi)*MeV,
1239                                    pp*costheta*MeV ) ;
1240      } else {
1241        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1242      }
1243      for( i=0; i<vecLen; ++i )
1244      {
1245        theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
1246        simulatedKinetic += theoreticalKinetic;
1247        vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
1248        pp = vec[i]->GetTotalMomentum()/MeV;
1249        pp1 = vec[i]->GetMomentum().mag()/MeV;
1250        if( pp1 < 1.0e-6*GeV )
1251        {
1252          G4double costheta = 2.*G4UniformRand() - 1.;
1253          G4double sintheta = std::sqrt(1. - costheta*costheta);
1254          G4double phi = twopi*G4UniformRand();
1255          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1256                               pp*sintheta*std::sin(phi)*MeV,
1257                               pp*costheta*MeV ) ;
1258        }
1259        else
1260          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
1261      }
1262    }
1263      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1264
1265    Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
1266            modifiedOriginal, originalIncident, targetNucleus,
1267            currentParticle, targetParticle, vec, vecLen );
1268      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1269    //
1270    // add black track particles
1271    // the total number of particles produced is restricted to 198
1272    // this may have influence on very high energies
1273    //
1274    if( atomicWeight >= 1.5 )
1275    {
1276      // npnb is number of proton/neutron black track particles
1277      // ndta is the number of deuterons, tritons, and alphas produced
1278      // epnb is the kinetic energy available for proton/neutron black track particles
1279      // edta is the kinetic energy available for deuteron/triton/alpha particles
1280      //
1281      G4int npnb = 0;
1282      G4int ndta = 0;
1283     
1284      G4double epnb, edta;
1285      if (veryForward) {
1286        epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
1287        edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
1288      } else {
1289        epnb = targetNucleus.GetPNBlackTrackEnergy();
1290        edta = targetNucleus.GetDTABlackTrackEnergy();
1291      }
1292
1293      const G4double pnCutOff = 0.001;
1294      const G4double dtaCutOff = 0.001;
1295      const G4double kineticMinimum = 1.e-6;
1296      const G4double kineticFactor = -0.010;
1297      G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
1298      const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
1299      if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
1300      if( epnb >= pnCutOff )
1301      {
1302        npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
1303        if( numberofFinalStateNucleons + npnb > atomicWeight )
1304          npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
1305        npnb = std::min( npnb, 127-vecLen );
1306      }
1307      if( edta >= dtaCutOff )
1308      {
1309        ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
1310        ndta = std::min( ndta, 127-vecLen );
1311      }
1312      if (npnb == 0 && ndta == 0) npnb = 1;
1313
1314      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1315
1316      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
1317                             kineticFactor, modifiedOriginal,
1318                             PinNucleus, NinNucleus, targetNucleus,
1319                             vec, vecLen);
1320
1321      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1322    }
1323    //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
1324    //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
1325    //
1326    //  calculate time delay for nuclear reactions
1327    //
1328    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
1329      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
1330    else
1331      currentParticle.SetTOF( 1.0 );
1332    return true;
1333      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1334  }
1335 
1336 void G4ReactionDynamics::SuppressChargedPions(
1337   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1338   G4int &vecLen,
1339   const G4ReactionProduct &modifiedOriginal,
1340   G4ReactionProduct &currentParticle,
1341   G4ReactionProduct &targetParticle,
1342   const G4Nucleus &targetNucleus,
1343   G4bool &incidentHasChanged,
1344   G4bool &targetHasChanged )
1345  {
1346    // this code was originally in the fortran code TWOCLU
1347    //
1348    // suppress charged pions, for various reasons
1349    //
1350    G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1351    G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1352    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1353    G4double cmEnergy = std::sqrt( mOriginal*mOriginal + targetMass*targetMass +
1354                                   2.0*targetMass*etOriginal ); 
1355    G4double eAvailable = cmEnergy - mOriginal - targetMass;
1356    for (G4int i = 0; i < vecLen; i++) eAvailable -= vec[i]->GetMass()/GeV;
1357
1358    const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
1359    const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
1360    const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
1361   
1362    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1363    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1364    G4ParticleDefinition* aPiZero = G4PionZero::PionZero();
1365    G4ParticleDefinition *aProton = G4Proton::Proton();
1366    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1367    G4double piMass = aPiPlus->GetPDGMass()/GeV;
1368    G4double nucleonMass = aNeutron->GetPDGMass()/GeV;
1369   
1370    const G4bool antiTest =
1371      modifiedOriginal.GetDefinition() != G4AntiProton::AntiProton() &&
1372      modifiedOriginal.GetDefinition() != G4AntiNeutron::AntiNeutron() &&
1373      modifiedOriginal.GetDefinition() != G4AntiLambda::AntiLambda() &&
1374      modifiedOriginal.GetDefinition() != G4AntiSigmaPlus::AntiSigmaPlus() &&
1375      modifiedOriginal.GetDefinition() != G4AntiSigmaMinus::AntiSigmaMinus() &&
1376      modifiedOriginal.GetDefinition() != G4AntiXiZero::AntiXiZero() &&
1377      modifiedOriginal.GetDefinition() != G4AntiXiMinus::AntiXiMinus() &&
1378      modifiedOriginal.GetDefinition() != G4AntiOmegaMinus::AntiOmegaMinus();
1379
1380    if( antiTest && (
1381          currentParticle.GetDefinition() == aPiPlus ||
1382          currentParticle.GetDefinition() == aPiZero ||
1383          currentParticle.GetDefinition() == aPiMinus ) &&
1384        ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1385        ( G4UniformRand() <= atomicWeight/300.0 ) )
1386    {
1387      if (eAvailable > nucleonMass - piMass) {
1388        if( G4UniformRand() > atomicNumber/atomicWeight )
1389          currentParticle.SetDefinitionAndUpdateE( aNeutron );
1390        else
1391          currentParticle.SetDefinitionAndUpdateE( aProton );
1392        incidentHasChanged = true;
1393      }
1394    }
1395    if( antiTest && (
1396          targetParticle.GetDefinition() == aPiPlus ||
1397          targetParticle.GetDefinition() == aPiZero ||
1398          targetParticle.GetDefinition() == aPiMinus ) &&
1399        ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1400        ( G4UniformRand() <= atomicWeight/300.0 ) )
1401    {
1402      if (eAvailable > nucleonMass - piMass) {
1403        if( G4UniformRand() > atomicNumber/atomicWeight )
1404          targetParticle.SetDefinitionAndUpdateE( aNeutron );
1405        else
1406          targetParticle.SetDefinitionAndUpdateE( aProton );
1407        targetHasChanged = true;
1408      }
1409    }
1410      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1411    for( G4int i=0; i<vecLen; ++i )
1412    {
1413      if( antiTest && (
1414            vec[i]->GetDefinition() == aPiPlus ||
1415            vec[i]->GetDefinition() == aPiZero ||
1416            vec[i]->GetDefinition() == aPiMinus ) &&
1417          ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1418          ( G4UniformRand() <= atomicWeight/300.0 ) )
1419      {
1420        if (eAvailable > nucleonMass - piMass) {
1421          if( G4UniformRand() > atomicNumber/atomicWeight )
1422            vec[i]->SetDefinitionAndUpdateE( aNeutron );
1423          else
1424            vec[i]->SetDefinitionAndUpdateE( aProton );
1425        }
1426      }
1427    }
1428      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1429  }
1430 
1431 G4bool G4ReactionDynamics::TwoCluster(
1432   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1433   G4int &vecLen,
1434   G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
1435   const G4HadProjectile *originalIncident, // the original incident particle
1436   G4ReactionProduct &currentParticle,
1437   G4ReactionProduct &targetParticle,
1438   const G4DynamicParticle* originalTarget,
1439   const G4Nucleus &targetNucleus,
1440   G4bool &incidentHasChanged,
1441   G4bool &targetHasChanged,
1442   G4bool leadFlag,
1443   G4ReactionProduct &leadingStrangeParticle )
1444  {
1445      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1446    // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
1447    //
1448    //  Generation of X- and PT- values for incident, target, and all secondary particles
1449    // 
1450    //  A simple two cluster model is used.
1451    //  This should be sufficient for low energy interactions.
1452    //
1453
1454    // + debugging
1455    // raise(SIGSEGV);
1456    // - debugging
1457
1458    G4int i;
1459    G4ParticleDefinition *aProton = G4Proton::Proton();
1460    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1461    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1462    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1463    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
1464    G4bool veryForward = false;
1465
1466    const G4double protonMass = aProton->GetPDGMass()/MeV;
1467    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
1468    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1469    const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1470    const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
1471    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1472    G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
1473                                        targetMass*targetMass +
1474                                        2.0*targetMass*etOriginal );  // GeV
1475    G4double currentMass = currentParticle.GetMass()/GeV;
1476    targetMass = targetParticle.GetMass()/GeV;
1477
1478    if( currentMass == 0.0 && targetMass == 0.0 )
1479    {
1480      G4double ek = currentParticle.GetKineticEnergy();
1481      G4ThreeVector m = currentParticle.GetMomentum();
1482      currentParticle = *vec[0];
1483      targetParticle = *vec[1];
1484      for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
1485      if(vecLen<2) 
1486      {
1487        for(G4int i=0; i<vecLen; i++) delete vec[i];
1488        vecLen = 0;
1489        throw G4HadReentrentException(__FILE__, __LINE__,
1490        "G4ReactionDynamics::TwoCluster: Negative number of particles");
1491      }
1492      delete vec[vecLen-1];
1493      delete vec[vecLen-2];
1494      vecLen -= 2;
1495      currentMass = currentParticle.GetMass()/GeV;
1496      targetMass = targetParticle.GetMass()/GeV;
1497      incidentHasChanged = true;
1498      targetHasChanged = true;
1499      currentParticle.SetKineticEnergy( ek );
1500      currentParticle.SetMomentum( m );
1501      veryForward = true;
1502    }
1503
1504    const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
1505    const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
1506    //
1507    // particles have been distributed in forward and backward hemispheres
1508    // in center of mass system of the hadron nucleon interaction
1509    //
1510    // incident is always in forward hemisphere
1511    G4int forwardCount = 1;            // number of particles in forward hemisphere
1512    currentParticle.SetSide( 1 );
1513    G4double forwardMass = currentParticle.GetMass()/GeV;
1514    G4double cMass = forwardMass;
1515   
1516    // target is always in backward hemisphere
1517    G4int backwardCount = 1;           // number of particles in backward hemisphere
1518    G4int backwardNucleonCount = 1;    // number of nucleons in backward hemisphere
1519    targetParticle.SetSide( -1 );
1520    G4double backwardMass = targetParticle.GetMass()/GeV;
1521    G4double bMass = backwardMass;
1522   
1523    for( i=0; i<vecLen; ++i )
1524    {
1525      if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
1526      // to take care of the case where vec has been preprocessed by GenerateXandPt
1527      // and some of them have been set to -2 or -3
1528      if( vec[i]->GetSide() == -1 )
1529      {
1530        ++backwardCount;
1531        backwardMass += vec[i]->GetMass()/GeV;
1532      }
1533      else
1534      {
1535        ++forwardCount;
1536        forwardMass += vec[i]->GetMass()/GeV;
1537      }
1538    }
1539    //
1540    // nucleons and some pions from intranuclear cascade
1541    //
1542    G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
1543    if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
1544    const G4double afc = 0.312 + 0.2 * std::log(term1);
1545    G4double xtarg;
1546    if( centerofmassEnergy < 2.0+G4UniformRand() )        // added +2 below, JLC 4Jul97
1547      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
1548    else
1549      xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
1550    if( xtarg <= 0.0 )xtarg = 0.01;
1551    G4int nuclearExcitationCount = Poisson( xtarg );
1552    if(atomicWeight<1.0001) nuclearExcitationCount = 0;
1553    G4int extraNucleonCount = 0;
1554    G4double extraMass = 0.0;
1555    G4double extraNucleonMass = 0.0;
1556    if( nuclearExcitationCount > 0 )
1557    {
1558      G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );     
1559      const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
1560      //
1561      //  NOTE: in TWOCLU, these new particles were given negative codes
1562      //        here we use  NewlyAdded = true  instead
1563      //
1564//      G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
1565      for( i=0; i<nuclearExcitationCount; ++i )
1566      {
1567        G4ReactionProduct* pVec = new G4ReactionProduct();
1568        if( G4UniformRand() < nucsup[momentumBin] )  // add proton or neutron
1569        {
1570          if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
1571            pVec->SetDefinition( aProton );
1572          else
1573            pVec->SetDefinition( aNeutron );
1574          ++backwardNucleonCount;
1575          ++extraNucleonCount;
1576          extraNucleonMass += pVec->GetMass()/GeV;
1577        }
1578        else
1579        {                                       // add a pion
1580          G4double ran = G4UniformRand();
1581          if( ran < 0.3181 )
1582            pVec->SetDefinition( aPiPlus );
1583          else if( ran < 0.6819 )
1584            pVec->SetDefinition( aPiZero );
1585          else
1586            pVec->SetDefinition( aPiMinus );
1587        }
1588        pVec->SetSide( -2 );    // backside particle
1589        extraMass += pVec->GetMass()/GeV;
1590        pVec->SetNewlyAdded( true );
1591        vec.SetElement( vecLen++, pVec );
1592        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1593      }
1594    }
1595      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1596    G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
1597    G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
1598    G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1599    G4bool secondaryDeleted;
1600    G4double pMass;
1601
1602    while( eAvailable <= 0.0 )   // must eliminate a particle
1603    {
1604      secondaryDeleted = false;
1605      for( i=(vecLen-1); i>=0; --i )
1606      {
1607        if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
1608        {
1609          pMass = vec[i]->GetMass()/GeV;
1610          for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];     // shift up
1611          --forwardCount;
1612          forwardEnergy += pMass;
1613          forwardMass -= pMass;
1614          secondaryDeleted = true;
1615          break;
1616        }
1617        else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
1618        {
1619          pMass = vec[i]->GetMass()/GeV;
1620          for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1621          --backwardCount;
1622          backwardEnergy += pMass;
1623          backwardMass -= pMass;
1624          secondaryDeleted = true;
1625          break;
1626        }
1627      }           // breaks go down to here
1628      if( secondaryDeleted )
1629      {     
1630        delete vec[vecLen-1];
1631        --vecLen;
1632        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1633      }
1634      else
1635      {
1636        if( vecLen == 0 )
1637        {
1638          return false;  // all secondaries have been eliminated
1639        }
1640        if( targetParticle.GetSide() == -1 )
1641        {
1642          pMass = targetParticle.GetMass()/GeV;
1643          targetParticle = *vec[0];
1644          for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1645          --backwardCount;
1646          backwardEnergy += pMass;
1647          backwardMass -= pMass;
1648          secondaryDeleted = true;
1649        }
1650        else if( targetParticle.GetSide() == 1 )
1651        {
1652          pMass = targetParticle.GetMass()/GeV;
1653          targetParticle = *vec[0];
1654          for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1655          --forwardCount;
1656          forwardEnergy += pMass;
1657          forwardMass -= pMass;
1658          secondaryDeleted = true;
1659        }
1660        if( secondaryDeleted )
1661        {
1662          delete vec[vecLen-1];
1663          --vecLen;
1664          // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1665        }
1666        else
1667        {
1668          if( currentParticle.GetSide() == -1 )
1669          {
1670            pMass = currentParticle.GetMass()/GeV;
1671            currentParticle = *vec[0];
1672            for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1673            --backwardCount;
1674            backwardEnergy += pMass;
1675            backwardMass -= pMass;
1676            secondaryDeleted = true;
1677          }
1678          else if( currentParticle.GetSide() == 1 )
1679          {
1680            pMass = currentParticle.GetMass()/GeV;
1681            currentParticle = *vec[0];
1682            for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];    // shift up
1683            --forwardCount;
1684            forwardEnergy += pMass;
1685            forwardMass -= pMass;
1686            secondaryDeleted = true;
1687          }
1688          if( secondaryDeleted )
1689          {
1690            delete vec[vecLen-1];
1691            --vecLen;
1692            // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1693          }
1694          else break;
1695        }
1696      }
1697      eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1698    }
1699    //
1700    // This is the start of the TwoCluster function
1701    //  Choose masses for the 3 clusters:
1702    //   forward cluster
1703    //   backward meson cluster
1704    //   backward nucleon cluster
1705    //
1706    G4double rmc = 0.0, rmd = 0.0;
1707    const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
1708    const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
1709   
1710    if (forwardCount <= 0 || backwardCount <= 0) return false;  // array bounds protection
1711
1712    if (forwardCount == 1) rmc = forwardMass;
1713    else 
1714    {
1715      G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
1716      rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1717    }
1718
1719    if (backwardCount == 1) rmd = backwardMass;
1720    else
1721    {
1722      G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
1723      rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1724    }
1725
1726    while( rmc+rmd > centerofmassEnergy )
1727    {
1728      if( (rmc <= forwardMass) && (rmd <= backwardMass) )
1729      {
1730        G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
1731        rmc *= temp;
1732        rmd *= temp;
1733      }
1734      else
1735      {
1736        rmc = 0.1*forwardMass + 0.9*rmc;
1737        rmd = 0.1*backwardMass + 0.9*rmd;
1738      }
1739    }
1740
1741    G4ReactionProduct pseudoParticle[8];
1742    for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
1743   
1744    pseudoParticle[1].SetMass( mOriginal*GeV );
1745    pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
1746    pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1747   
1748    pseudoParticle[2].SetMass( protonMass*MeV );
1749    pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
1750    pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
1751    //
1752    //  transform into centre of mass system
1753    //
1754    pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
1755    pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
1756    pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
1757   
1758    const G4double pfMin = 0.0001;
1759    G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
1760    pf *= pf;
1761    pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
1762    pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
1763    //
1764    //  set final state masses and energies in centre of mass system
1765    //
1766    pseudoParticle[3].SetMass( rmc*GeV );
1767    pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
1768   
1769    pseudoParticle[4].SetMass( rmd*GeV );
1770    pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
1771    //
1772    // set |T| and |TMIN|
1773    //
1774    const G4double bMin = 0.01;
1775    const G4double b1 = 4.0;
1776    const G4double b2 = 1.6;
1777
1778    G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
1779    G4double dtb = 4.0*pin*pf*std::max( bMin, b1+b2*std::log(pOriginal) );
1780    G4double factor = 1.0 - std::exp(-dtb);
1781    G4double costheta = 1.0 + 2.0*std::log(1.0 - G4UniformRand()*factor) / dtb;
1782    costheta = std::max(-1.0, std::min(1.0, costheta));
1783    G4double sintheta = std::sqrt(1.0-costheta*costheta);
1784    G4double phi = G4UniformRand() * twopi;
1785
1786    //
1787    // calculate final state momenta in centre of mass system
1788    //
1789    pseudoParticle[3].SetMomentum( pf*sintheta*std::cos(phi)*GeV,
1790                                   pf*sintheta*std::sin(phi)*GeV,
1791                                   pf*costheta*GeV );
1792
1793    pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1794    //
1795    // simulate backward nucleon cluster in lab. system and transform in cms
1796    //
1797    G4double pp, pp1;
1798    if( nuclearExcitationCount > 0 )
1799    {
1800      const G4double ga = 1.2;
1801      G4double ekit1 = 0.04;
1802      G4double ekit2 = 0.6;
1803      if( ekOriginal <= 5.0 )
1804      {
1805        ekit1 *= ekOriginal*ekOriginal/25.0;
1806        ekit2 *= ekOriginal*ekOriginal/25.0;
1807      }
1808      const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
1809      for( i=0; i<vecLen; ++i )
1810      {
1811        if( vec[i]->GetSide() == -2 )
1812        {
1813          G4double kineticE =
1814            std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
1815          vec[i]->SetKineticEnergy( kineticE*GeV );
1816          G4double vMass = vec[i]->GetMass()/MeV;
1817          G4double totalE = kineticE*GeV + vMass;
1818          pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
1819          G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
1820          G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
1821          phi = twopi*G4UniformRand();
1822          vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
1823                               pp*sint*std::cos(phi)*MeV,
1824                               pp*cost*MeV );
1825          vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
1826        }
1827      }
1828      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1829    }
1830    //
1831    // fragmentation of forward cluster and backward meson cluster
1832    //
1833    currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
1834    currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1835   
1836    targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
1837    targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1838   
1839    pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1840    pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
1841    pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1842   
1843    pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
1844    pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
1845    pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1846   
1847    G4double wgt;
1848      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1849    if( forwardCount > 1 )     // tempV will contain the forward particles
1850    {
1851      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1852      tempV.Initialize( forwardCount );
1853      G4bool constantCrossSection = true;
1854      G4int tempLen = 0;
1855      if( currentParticle.GetSide() == 1 )
1856        tempV.SetElement( tempLen++, &currentParticle );
1857      if( targetParticle.GetSide() == 1 )
1858        tempV.SetElement( tempLen++, &targetParticle );
1859      for( i=0; i<vecLen; ++i )
1860      {
1861        if( vec[i]->GetSide() == 1 )
1862        {
1863          if( tempLen < 18 )
1864            tempV.SetElement( tempLen++, vec[i] );
1865          else
1866          {
1867            vec[i]->SetSide( -1 );
1868            continue;
1869          }
1870        }
1871      }
1872      if( tempLen >= 2 )
1873      {
1874        wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
1875                                  constantCrossSection, tempV, tempLen );
1876        if( currentParticle.GetSide() == 1 )
1877          currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
1878        if( targetParticle.GetSide() == 1 )
1879          targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
1880        for( i=0; i<vecLen; ++i )
1881        {
1882          if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
1883        }
1884      }
1885    }
1886      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1887    if( backwardCount > 1 )   //  tempV will contain the backward particles,
1888    {                         //  but not those created from the intranuclear cascade
1889      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1890      tempV.Initialize( backwardCount );
1891      G4bool constantCrossSection = true;
1892      G4int tempLen = 0;
1893      if( currentParticle.GetSide() == -1 )
1894        tempV.SetElement( tempLen++, &currentParticle );
1895      if( targetParticle.GetSide() == -1 )
1896        tempV.SetElement( tempLen++, &targetParticle );
1897      for( i=0; i<vecLen; ++i )
1898      {
1899        if( vec[i]->GetSide() == -1 )
1900        {
1901          if( tempLen < 18 )
1902            tempV.SetElement( tempLen++, vec[i] );
1903          else
1904          {
1905            vec[i]->SetSide( -2 );
1906            vec[i]->SetKineticEnergy( 0.0 );
1907            vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
1908            continue;
1909          }
1910        }
1911      }
1912      if( tempLen >= 2 )
1913      {
1914        wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
1915                                  constantCrossSection, tempV, tempLen );
1916        if( currentParticle.GetSide() == -1 )
1917          currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
1918        if( targetParticle.GetSide() == -1 )
1919          targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1920        for( i=0; i<vecLen; ++i )
1921        {
1922          if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1923        }
1924      }
1925    }
1926      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1927    //
1928    // Lorentz transformation in lab system
1929    //
1930    currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
1931    targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
1932    for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
1933
1934      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1935    //
1936    // sometimes the leading strange particle is lost, set it back
1937    //
1938    G4bool dum = true;
1939    if( leadFlag )
1940    {
1941      // leadFlag will be true
1942      //  iff original particle is at least as heavy as K+ and not a proton or
1943      //  neutron AND if incident particle is at least as heavy as K+ and it is
1944      //  not a proton or neutron leadFlag is set to the incident particle
1945      //  or
1946      //  target particle is at least as heavy as K+ and it is not a proton or
1947      //  neutron leadFlag is set to the target particle
1948      //
1949      if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1950        dum = false;
1951      else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1952        dum = false;
1953      else
1954      {
1955        for( i=0; i<vecLen; ++i )
1956        {
1957          if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1958          {
1959            dum = false;
1960            break;
1961          }
1962        }
1963      }
1964      if( dum )
1965      {
1966        G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
1967        G4double ekin;
1968        if( ((leadMass <  protonMass) && (targetParticle.GetMass()/MeV <  protonMass)) ||
1969            ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
1970        {
1971          ekin = targetParticle.GetKineticEnergy()/GeV;
1972          pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
1973          targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1974          targetParticle.SetKineticEnergy( ekin*GeV );
1975          pp = targetParticle.GetTotalMomentum()/MeV;   // new momentum
1976          if( pp1 < 1.0e-3 )
1977          {
1978            G4double costheta = 2.*G4UniformRand() - 1.;
1979            G4double sintheta = std::sqrt(1. - costheta*costheta);
1980            G4double phi = twopi*G4UniformRand();
1981            targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1982                                        pp*sintheta*std::sin(phi)*MeV,
1983                                        pp*costheta*MeV ) ;
1984          }
1985          else
1986            targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1987         
1988          targetHasChanged = true;
1989        }
1990        else
1991        {
1992          ekin = currentParticle.GetKineticEnergy()/GeV;
1993          pp1 = currentParticle.GetMomentum().mag()/MeV;
1994          currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1995          currentParticle.SetKineticEnergy( ekin*GeV );
1996          pp = currentParticle.GetTotalMomentum()/MeV;
1997          if( pp1 < 1.0e-3 )
1998          {
1999            G4double costheta = 2.*G4UniformRand() - 1.;
2000            G4double sintheta = std::sqrt(1. - costheta*costheta);
2001            G4double phi = twopi*G4UniformRand();
2002            currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2003                                         pp*sintheta*std::sin(phi)*MeV,
2004                                         pp*costheta*MeV ) ;
2005          }
2006          else
2007            currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2008         
2009          incidentHasChanged = true;
2010        }
2011      }
2012    }    // end of if( leadFlag )
2013
2014    // Get number of final state nucleons and nucleons remaining in
2015    // target nucleus
2016   
2017    std::pair<G4int, G4int> finalStateNucleons = 
2018      GetFinalStateNucleons(originalTarget, vec, vecLen);
2019
2020    G4int protonsInFinalState = finalStateNucleons.first;
2021    G4int neutronsInFinalState = finalStateNucleons.second;
2022
2023    G4int numberofFinalStateNucleons = 
2024      protonsInFinalState + neutronsInFinalState;
2025
2026    if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2027        targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2028        originalIncident->GetDefinition()->GetPDGMass() < 
2029                                   G4Lambda::Lambda()->GetPDGMass())
2030      numberofFinalStateNucleons++;
2031
2032    numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
2033
2034    G4int PinNucleus = std::max(0, 
2035      targetNucleus.GetZ_asInt() - protonsInFinalState);
2036    G4int NinNucleus = std::max(0,
2037      targetNucleus.GetN_asInt() - neutronsInFinalState);
2038    //
2039    //  for various reasons, the energy balance is not sufficient,
2040    //  check that,  energy balance, angle of final system, etc.
2041    //
2042    pseudoParticle[4].SetMass( mOriginal*GeV );
2043    pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
2044    pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2045   
2046    G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
2047    G4int diff = 0;
2048    if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() )  diff = 1;
2049    if(numberofFinalStateNucleons == 1) diff = 0;
2050    pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
2051    pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2052    pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2053   
2054    G4double theoreticalKinetic =
2055      pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
2056   
2057    pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
2058    pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
2059    pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
2060     
2061    if( vecLen < 16 )
2062    {
2063      G4ReactionProduct tempR[130];
2064      tempR[0] = currentParticle;
2065      tempR[1] = targetParticle;
2066      for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
2067
2068      G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
2069      tempV.Initialize( vecLen+2 );
2070      G4bool constantCrossSection = true;
2071      G4int tempLen = 0;
2072      for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
2073
2074      if( tempLen >= 2 )
2075      {
2076      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2077        wgt = GenerateNBodyEvent( pseudoParticle[4].GetTotalEnergy()/MeV +
2078                                  pseudoParticle[5].GetTotalEnergy()/MeV,
2079                                  constantCrossSection, tempV, tempLen );
2080        if (wgt == -1) {
2081          G4double Qvalue = 0;
2082          for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
2083          wgt = GenerateNBodyEvent( Qvalue/MeV,
2084                                    constantCrossSection, tempV, tempLen );
2085        }
2086        theoreticalKinetic = 0.0;
2087        for( i=0; i<vecLen+2; ++i )
2088        {
2089          pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
2090          pseudoParticle[7].SetMass( tempV[i]->GetMass() );
2091          pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
2092          pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
2093          theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
2094        }
2095      }
2096      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2097    }
2098    else
2099    {
2100      theoreticalKinetic -=
2101        ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
2102      for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
2103    }
2104    G4double simulatedKinetic =
2105      currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
2106    for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
2107    //
2108    // make sure that kinetic energies are correct
2109    // the backward nucleon cluster is not produced within proper kinematics!!!
2110    //
2111   
2112    if( simulatedKinetic != 0.0 )
2113    {
2114      wgt = (theoreticalKinetic)/simulatedKinetic;
2115      currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
2116      pp = currentParticle.GetTotalMomentum()/MeV;
2117      pp1 = currentParticle.GetMomentum().mag()/MeV;
2118      if( pp1 < 0.001*MeV )
2119      {
2120        G4double costheta = 2.*G4UniformRand() - 1.;
2121        G4double sintheta = std::sqrt(1. - costheta*costheta);
2122        G4double phi = twopi*G4UniformRand();
2123        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2124                                     pp*sintheta*std::sin(phi)*MeV,
2125                                     pp*costheta*MeV ) ;
2126      }
2127      else
2128        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2129     
2130      targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
2131      pp = targetParticle.GetTotalMomentum()/MeV;
2132      pp1 = targetParticle.GetMomentum().mag()/MeV;
2133      if( pp1 < 0.001*MeV )
2134      {
2135        G4double costheta = 2.*G4UniformRand() - 1.;
2136        G4double sintheta = std::sqrt(1. - costheta*costheta);
2137        G4double phi = twopi*G4UniformRand();
2138        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2139                                    pp*sintheta*std::sin(phi)*MeV,
2140                                    pp*costheta*MeV ) ;
2141      }
2142      else
2143        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2144     
2145      for( i=0; i<vecLen; ++i )
2146      {
2147        vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
2148        pp = vec[i]->GetTotalMomentum()/MeV;
2149        pp1 = vec[i]->GetMomentum().mag()/MeV;
2150        if( pp1 < 0.001 )
2151        {
2152          G4double costheta = 2.*G4UniformRand() - 1.;
2153          G4double sintheta = std::sqrt(1. - costheta*costheta);
2154          G4double phi = twopi*G4UniformRand();
2155          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2156                               pp*sintheta*std::sin(phi)*MeV,
2157                               pp*costheta*MeV ) ;
2158        }
2159        else
2160          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2161      }
2162    }
2163      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2164
2165    Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
2166            modifiedOriginal, originalIncident, targetNucleus,
2167            currentParticle, targetParticle, vec, vecLen );
2168    //
2169    //  add black track particles
2170    //  the total number of particles produced is restricted to 198
2171    //  this may have influence on very high energies
2172    //
2173    if( atomicWeight >= 1.5 )
2174    {
2175      // npnb is number of proton/neutron black track particles
2176      // ndta is the number of deuterons, tritons, and alphas produced
2177      // epnb is the kinetic energy available for proton/neutron black track
2178      //   particles
2179      // edta is the kinetic energy available for deuteron/triton/alpha
2180      //   particles
2181
2182      G4int npnb = 0;
2183      G4int ndta = 0;
2184
2185      G4double epnb, edta;
2186      if (veryForward) {
2187        epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
2188        edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
2189      } else {
2190        epnb = targetNucleus.GetPNBlackTrackEnergy();
2191        edta = targetNucleus.GetDTABlackTrackEnergy();
2192      }
2193
2194      const G4double pnCutOff = 0.001;     // GeV
2195      const G4double dtaCutOff = 0.001;    // GeV
2196      const G4double kineticMinimum = 1.e-6;
2197      const G4double kineticFactor = -0.005;
2198     
2199      G4double sprob = 0.0;   // sprob = probability of self-absorption in
2200                              // heavy molecules
2201      const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
2202      if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
2203     
2204      if( epnb >= pnCutOff )
2205      {
2206        npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
2207        if( numberofFinalStateNucleons + npnb > atomicWeight )
2208          npnb = G4int(atomicWeight - numberofFinalStateNucleons);
2209        npnb = std::min( npnb, 127-vecLen );
2210      }
2211      if( edta >= dtaCutOff )
2212      {
2213        ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
2214        ndta = std::min( ndta, 127-vecLen );
2215      }
2216      if (npnb == 0 && ndta == 0) npnb = 1;
2217
2218      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2219
2220      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
2221                             kineticFactor, modifiedOriginal, 
2222                             PinNucleus, NinNucleus, targetNucleus,
2223                             vec, vecLen );
2224      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2225    }
2226    //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
2227    //  MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2228    //
2229    //  calculate time delay for nuclear reactions
2230    //
2231    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2232      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2233    else
2234      currentParticle.SetTOF( 1.0 );
2235   
2236      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2237    return true;
2238  }
2239 
2240 void G4ReactionDynamics::TwoBody(
2241  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2242  G4int &vecLen,
2243  G4ReactionProduct &modifiedOriginal,
2244  const G4DynamicParticle* originalTarget,
2245  G4ReactionProduct &currentParticle,
2246  G4ReactionProduct &targetParticle,
2247  const G4Nucleus &targetNucleus,
2248  G4bool &/* targetHasChanged*/ )
2249  {
2250    //
2251    // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
2252    //
2253    // Generation of momenta for elastic and quasi-elastic 2 body reactions
2254    //
2255    // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
2256    // The b values are parametrizations from experimental data.
2257    // Not available values are taken from those of similar reactions.
2258    //
2259   
2260      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);   
2261    static const G4double expxu =  82.;           // upper bound for arg. of exp
2262    static const G4double expxl = -expxu;         // lower bound for arg. of exp
2263   
2264    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
2265    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
2266    const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
2267    const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
2268    G4double currentMass = currentParticle.GetMass()/GeV;
2269    G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
2270
2271    targetMass = targetParticle.GetMass()/GeV;
2272    const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
2273   
2274    G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
2275    G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
2276
2277    G4double cmEnergy = std::sqrt( currentMass*currentMass +
2278                              targetMass*targetMass +
2279                              2.0*targetMass*etCurrent );  // in GeV
2280
2281    //if( (pOriginal < 0.1) ||
2282    //    (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
2283    // Continue with original particle, but spend the nuclear evaporation energy
2284    //  targetParticle.SetMass( 0.0 );  // flag that the target doesn't exist
2285    //else                           // Two-body scattering is possible
2286
2287    if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
2288    {
2289      targetParticle.SetMass( 0.0 );  // flag that the target particle doesn't exist
2290    }
2291    else
2292    {
2293// moved this if-block to a later stage, i.e. to the assignment of the scattering angle
2294// @@@@@ double-check.
2295//      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2296//          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2297//        if( G4UniformRand() < 0.5 )
2298//          targetParticle.SetDefinitionAndUpdateE( aNeutron );
2299//        else
2300//          targetParticle.SetDefinitionAndUpdateE( aProton );
2301//        targetHasChanged = true;
2302//        targetMass = targetParticle.GetMass()/GeV;
2303//      }
2304      //
2305      // Set masses and momenta for final state particles
2306      //
2307      G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
2308      pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
2309     
2310      if( pf < 0.001 )
2311      {
2312        for(G4int i=0; i<vecLen; i++) delete vec[i];
2313        vecLen = 0;
2314        throw G4HadronicException(__FILE__, __LINE__, "G4ReactionDynamics::TwoBody: pf is too small ");
2315      }
2316     
2317      pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
2318      //
2319      // Set beam and target in centre of mass system
2320      //
2321      G4ReactionProduct pseudoParticle[3];
2322     
2323      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2324          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2325        pseudoParticle[0].SetMass( targetMass*GeV );
2326        pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
2327        pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2328     
2329        pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2330        pseudoParticle[1].SetMass( mOriginal*GeV );
2331        pseudoParticle[1].SetKineticEnergy( 0.0 );
2332
2333      } else {
2334        pseudoParticle[0].SetMass( currentMass*GeV );
2335        pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
2336        pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
2337     
2338        pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2339        pseudoParticle[1].SetMass( targetMass*GeV );
2340        pseudoParticle[1].SetKineticEnergy( 0.0 );
2341      }
2342      //
2343      // Transform into centre of mass system
2344      //
2345      pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
2346      pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
2347      pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
2348      //
2349      // Set final state masses and energies in centre of mass system
2350      //
2351      currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
2352      targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
2353      //
2354      // Set |t| and |tmin|
2355      //
2356      const G4double cb = 0.01;
2357      const G4double b1 = 4.225;
2358      const G4double b2 = 1.795;
2359      //
2360      // Calculate slope b for elastic scattering on proton/neutron
2361      //
2362      G4double b = std::max( cb, b1+b2*std::log(pOriginal) );     
2363      G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
2364     
2365      G4double exindt = -1.0;
2366      exindt += std::exp(std::max(-btrang,expxl));
2367      //
2368      // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
2369      //
2370      G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
2371      if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
2372      G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
2373      G4double phi = twopi * G4UniformRand();
2374      //
2375      // Calculate final state momenta in centre of mass system
2376      //
2377      if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2378          targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2379
2380        currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
2381                                     -pf*stet*std::cos(phi)*GeV,
2382                                     -pf*ctet*GeV );
2383      } else {
2384
2385        currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
2386                                     pf*stet*std::cos(phi)*GeV,
2387                                     pf*ctet*GeV );
2388      }
2389      targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
2390      //
2391      // Transform into lab system
2392      //
2393      currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
2394      targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
2395     
2396      Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2397     
2398      G4double pp, pp1, ekin;
2399      if( atomicWeight >= 1.5 )
2400      {
2401        const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2402        pp1 = currentParticle.GetMomentum().mag()/MeV;
2403        if( pp1 >= 1.0 )
2404        {
2405          ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
2406          ekin = std::max( 0.0001*GeV, ekin );
2407          currentParticle.SetKineticEnergy( ekin*MeV );
2408          pp = currentParticle.GetTotalMomentum()/MeV;
2409          currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2410        }
2411        pp1 = targetParticle.GetMomentum().mag()/MeV;
2412        if( pp1 >= 1.0 )
2413        {
2414          ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
2415          ekin = std::max( 0.0001*GeV, ekin );
2416          targetParticle.SetKineticEnergy( ekin*MeV );
2417          pp = targetParticle.GetTotalMomentum()/MeV;
2418          targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2419        }
2420      }
2421    }
2422
2423    // Get number of final state nucleons and nucleons remaining in
2424    // target nucleus
2425   
2426    std::pair<G4int, G4int> finalStateNucleons = 
2427      GetFinalStateNucleons(originalTarget, vec, vecLen);
2428    G4int protonsInFinalState = finalStateNucleons.first;
2429    G4int neutronsInFinalState = finalStateNucleons.second;
2430
2431    G4int PinNucleus = std::max(0, 
2432      targetNucleus.GetZ_asInt() - protonsInFinalState);
2433    G4int NinNucleus = std::max(0,
2434      targetNucleus.GetN_asInt() - neutronsInFinalState);
2435
2436      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2437    if( atomicWeight >= 1.5 )
2438    {
2439      // Add black track particles
2440      // npnb is number of proton/neutron black track particles
2441      // ndta is the number of deuterons, tritons, and alphas produced
2442      // epnb is the kinetic energy available for proton/neutron black track particles
2443      // edta is the kinetic energy available for deuteron/triton/alpha particles
2444      //
2445      G4double epnb, edta;
2446      G4int npnb=0, ndta=0;
2447     
2448      epnb = targetNucleus.GetPNBlackTrackEnergy();            // was enp1 in fortran code
2449      edta = targetNucleus.GetDTABlackTrackEnergy();           // was enp3 in fortran code
2450      const G4double pnCutOff = 0.0001;       // GeV
2451      const G4double dtaCutOff = 0.0001;      // GeV
2452      const G4double kineticMinimum = 0.0001;
2453      const G4double kineticFactor = -0.010;
2454      G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2455      if( epnb >= pnCutOff )
2456      {
2457        npnb = Poisson( epnb/0.02 );
2458        if( npnb > atomicWeight )npnb = G4int(atomicWeight);
2459        if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
2460        npnb = std::min( npnb, 127-vecLen );
2461      }
2462      if( edta >= dtaCutOff )
2463      {
2464        ndta = G4int(2.0 * std::log(atomicWeight));
2465        ndta = std::min( ndta, 127-vecLen );
2466      }
2467
2468      if (npnb == 0 && ndta == 0) npnb = 1;
2469
2470      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2471
2472      AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum, 
2473                             kineticFactor, modifiedOriginal, 
2474                             PinNucleus, NinNucleus, targetNucleus,
2475                             vec, vecLen);
2476      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2477    }
2478    //
2479    //  calculate time delay for nuclear reactions
2480    //
2481    if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2482      currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2483    else
2484      currentParticle.SetTOF( 1.0 );
2485    return;
2486  }
2487 
2488 G4double G4ReactionDynamics::GenerateNBodyEvent(
2489  const G4double totalEnergy,                // MeV
2490  const G4bool constantCrossSection,
2491  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2492  G4int &vecLen )
2493  {
2494      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2495    // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
2496    // Returns the weight of the event
2497    //
2498    G4int i;
2499    const G4double expxu =  82.;           // upper bound for arg. of exp
2500    const G4double expxl = -expxu;         // lower bound for arg. of exp
2501    if( vecLen < 2 )
2502    {
2503      G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2504      G4cerr << "    number of particles < 2" << G4endl;
2505      G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
2506      return -1.0;
2507    }
2508    G4double mass[18];    // mass of each particle
2509    G4double energy[18];  // total energy of each particle
2510    G4double pcm[3][18];           // pcm is an array with 3 rows and vecLen columns
2511   
2512    G4double totalMass = 0.0;
2513    G4double extraMass = 0;
2514    G4double sm[18];
2515   
2516    for( i=0; i<vecLen; ++i )
2517    {
2518      mass[i] = vec[i]->GetMass()/GeV;
2519      if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
2520      vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
2521      pcm[0][i] = 0.0;      // x-momentum of i-th particle
2522      pcm[1][i] = 0.0;      // y-momentum of i-th particle
2523      pcm[2][i] = 0.0;      // z-momentum of i-th particle
2524      energy[i] = mass[i];  // total energy of i-th particle
2525      totalMass += mass[i];
2526      sm[i] = totalMass;
2527    }
2528    G4double totalE = totalEnergy/GeV;
2529    if( totalMass > totalE )
2530    {
2531      //G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2532      //G4cerr << "    total mass (" << totalMass*GeV << "MeV) > total energy ("
2533      //     << totalEnergy << "MeV)" << G4endl;
2534      totalE = totalMass;
2535      return -1.0;
2536    }
2537    G4double kineticEnergy = totalE - totalMass;
2538    G4double emm[18];
2539    //G4double *emm = new G4double [vecLen];
2540    emm[0] = mass[0];
2541    emm[vecLen-1] = totalE;
2542    if( vecLen > 2 )          // the random numbers are sorted
2543    {
2544      G4double ran[18];
2545      for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
2546      for( i=0; i<vecLen-2; ++i )
2547      {
2548        for( G4int j=vecLen-2; j>i; --j )
2549        {
2550          if( ran[i] > ran[j] )
2551          {
2552            G4double temp = ran[i];
2553            ran[i] = ran[j];
2554            ran[j] = temp;
2555          }
2556        }
2557      }
2558      for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
2559    }
2560    //   Weight is the sum of logarithms of terms instead of the product of terms
2561    G4bool lzero = true;   
2562    G4double wtmax = 0.0;
2563    if( constantCrossSection )     // this is KGENEV=1 in PHASP
2564    {
2565      G4double emmax = kineticEnergy + mass[0];
2566      G4double emmin = 0.0;
2567      for( i=1; i<vecLen; ++i )
2568      {
2569        emmin += mass[i-1];
2570        emmax += mass[i];
2571        G4double wtfc = 0.0;
2572        if( emmax*emmax > 0.0 )
2573        {
2574          G4double arg = emmax*emmax
2575            + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
2576            - 2.0*(emmin*emmin+mass[i]*mass[i]);
2577          if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
2578        }
2579        if( wtfc == 0.0 )
2580        {
2581          lzero = false;
2582          break;
2583        }
2584        wtmax += std::log( wtfc );
2585      }
2586      if( lzero )
2587        wtmax = -wtmax;
2588      else
2589        wtmax = expxu;
2590    }
2591    else
2592    {
2593      //   ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
2594      const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
2595                                 256.3704, 268.4705, 240.9780, 189.2637,
2596                                 132.1308,  83.0202,  47.4210,  24.8295,
2597                                 12.0006,   5.3858,   2.2560,   0.8859 };
2598      wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
2599    }
2600    lzero = true;
2601    G4double pd[50];
2602    //G4double *pd = new G4double [vecLen-1];
2603    for( i=0; i<vecLen-1; ++i )
2604    {
2605      pd[i] = 0.0;
2606      if( emm[i+1]*emm[i+1] > 0.0 )
2607      {
2608        G4double arg = emm[i+1]*emm[i+1]
2609          + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
2610            /(emm[i+1]*emm[i+1])
2611          - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
2612        if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
2613      }
2614      if( pd[i] <= 0.0 )    //  changed from  ==  on 02 April 98
2615        lzero = false;
2616      else
2617        wtmax += std::log( pd[i] );
2618    }
2619    G4double weight = 0.0;           // weight is returned by GenerateNBodyEvent
2620    if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
2621   
2622    G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
2623    pcm[0][0] = 0.0;
2624    pcm[1][0] = pd[0];
2625    pcm[2][0] = 0.0;
2626    for( i=1; i<vecLen; ++i )
2627    {
2628      pcm[0][i] = 0.0;
2629      pcm[1][i] = -pd[i-1];
2630      pcm[2][i] = 0.0;
2631      bang = twopi*G4UniformRand();
2632      cb = std::cos(bang);
2633      sb = std::sin(bang);
2634      c = 2.0*G4UniformRand() - 1.0;
2635      s = std::sqrt( std::fabs( 1.0-c*c ) );
2636      if( i < vecLen-1 )
2637      {
2638        esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
2639        beta = pd[i]/esys;
2640        gama = esys/emm[i];
2641        for( G4int j=0; j<=i; ++j )
2642        {
2643          s0 = pcm[0][j];
2644          s1 = pcm[1][j];
2645          s2 = pcm[2][j];
2646          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2647          a = s0*c - s1*s;                           //  rotation
2648          pcm[1][j] = s0*s + s1*c;
2649          b = pcm[2][j];
2650          pcm[0][j] = a*cb - b*sb;
2651          pcm[2][j] = a*sb + b*cb;
2652          pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
2653        }
2654      }
2655      else
2656      {
2657        for( G4int j=0; j<=i; ++j )
2658        {
2659          s0 = pcm[0][j];
2660          s1 = pcm[1][j];
2661          s2 = pcm[2][j];
2662          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2663          a = s0*c - s1*s;                           //  rotation
2664          pcm[1][j] = s0*s + s1*c;
2665          b = pcm[2][j];
2666          pcm[0][j] = a*cb - b*sb;
2667          pcm[2][j] = a*sb + b*cb;
2668        }
2669      }
2670    }
2671    for( i=0; i<vecLen; ++i )
2672    {
2673      vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
2674      vec[i]->SetTotalEnergy( energy[i]*GeV );
2675    }
2676
2677      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2678    return weight;
2679  }
2680 
2681 G4double
2682   G4ReactionDynamics::normal()
2683   {
2684     G4double ran = -6.0;
2685     for( G4int i=0; i<12; ++i )ran += G4UniformRand();
2686     return ran;
2687   }
2688 
2689 G4int
2690   G4ReactionDynamics::Poisson( G4double x )  // generation of poisson distribution
2691   {
2692     G4int iran;
2693     G4double ran;
2694     
2695     if( x > 9.9 )    // use normal distribution with sigma^2 = <x>
2696       iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
2697     else {
2698      G4int mm = G4int(5.0*x);
2699      if( mm <= 0 )   // for very small x try iran=1,2,3
2700      {
2701        G4double p1 = x*std::exp(-x);
2702        G4double p2 = x*p1/2.0;
2703        G4double p3 = x*p2/3.0;
2704        ran = G4UniformRand();
2705        if( ran < p3 )
2706          iran = 3;
2707        else if( ran < p2 )   // this is original Geisha, it should be ran < p2+p3
2708          iran = 2;
2709        else if( ran < p1 )   // should be ran < p1+p2+p3
2710          iran = 1;
2711        else
2712          iran = 0;
2713      }
2714      else
2715      {
2716        iran = 0;
2717        G4double r = std::exp(-x);
2718        ran = G4UniformRand();
2719        if( ran > r )
2720        {
2721          G4double rrr;
2722          G4double rr = r;
2723          for( G4int i=1; i<=mm; ++i )
2724          {
2725            iran++;
2726            if( i > 5 )   // Stirling's formula for large numbers
2727              rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
2728            else
2729              rrr = std::pow(x,i)/Factorial(i);
2730            rr += r*rrr;
2731            if( ran <= rr )break;
2732          }
2733        }
2734      }
2735    }
2736    return iran;
2737  }
2738 
2739 G4int
2740   G4ReactionDynamics::Factorial( G4int n )
2741   {   // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
2742     G4int m = std::min(n,10);
2743     G4int result = 1;
2744     if( m <= 1 )return result;
2745     for( G4int i=2; i<=m; ++i )result *= i;
2746     return result;
2747   }
2748 
2749 void G4ReactionDynamics::Defs1(
2750   const G4ReactionProduct &modifiedOriginal,
2751   G4ReactionProduct &currentParticle,
2752   G4ReactionProduct &targetParticle,
2753   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2754   G4int &vecLen )
2755  {
2756    const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
2757    const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
2758    const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
2759    const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
2760    if( pjx*pjx+pjy*pjy > 0.0 )
2761    {
2762      G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
2763      cost = pjz/p;
2764      sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
2765      if( pjy < 0.0 )
2766        ph = 3*halfpi;
2767      else
2768        ph = halfpi;
2769      if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
2770      cosp = std::cos(ph);
2771      sinp = std::sin(ph);
2772      pix = currentParticle.GetMomentum().x()/MeV;
2773      piy = currentParticle.GetMomentum().y()/MeV;
2774      piz = currentParticle.GetMomentum().z()/MeV;
2775      currentParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2776                                   cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2777                                   -sint*pix*MeV     + cost*piz*MeV );
2778      pix = targetParticle.GetMomentum().x()/MeV;
2779      piy = targetParticle.GetMomentum().y()/MeV;
2780      piz = targetParticle.GetMomentum().z()/MeV;
2781      targetParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2782                                  cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2783                                  -sint*pix*MeV     + cost*piz*MeV );
2784      for( G4int i=0; i<vecLen; ++i )
2785      {
2786        pix = vec[i]->GetMomentum().x()/MeV;
2787        piy = vec[i]->GetMomentum().y()/MeV;
2788        piz = vec[i]->GetMomentum().z()/MeV;
2789        vec[i]->SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2790                             cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2791                             -sint*pix*MeV     + cost*piz*MeV );
2792      }
2793    }
2794    else
2795    {
2796      if( pjz < 0.0 )
2797      {
2798        currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
2799        targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
2800        for( G4int i=0; i<vecLen; ++i )
2801          vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
2802      }
2803    }
2804  }
2805 
2806 void G4ReactionDynamics::Rotate(
2807  const G4double numberofFinalStateNucleons,
2808  const G4ThreeVector &temp,
2809  const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
2810  const G4HadProjectile *originalIncident, // original incident particle
2811  const G4Nucleus &targetNucleus,
2812  G4ReactionProduct &currentParticle,
2813  G4ReactionProduct &targetParticle,
2814  G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2815  G4int &vecLen )
2816  {
2817    // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
2818    //
2819    //   Rotate in direction of z-axis, this does disturb in some way our
2820    //    inclusive distributions, but it is necessary for momentum conservation
2821    //
2822    const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
2823    const G4double logWeight = std::log(atomicWeight);
2824   
2825    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2826    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2827    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2828   
2829    G4int i;
2830    G4ThreeVector pseudoParticle[4];
2831    for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
2832    pseudoParticle[0] = currentParticle.GetMomentum()
2833                        + targetParticle.GetMomentum();
2834    for( i=0; i<vecLen; ++i )
2835      pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
2836    //
2837    //  Some smearing in transverse direction from Fermi motion
2838    //
2839    G4float pp, pp1;
2840    G4double alekw, p;
2841    G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
2842   
2843    r1 = twopi*G4UniformRand();
2844    r2 = G4UniformRand();
2845    a1 = std::sqrt(-2.0*std::log(r2));
2846    ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
2847    ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
2848    G4ThreeVector fermi(ran1, ran2, 0);
2849
2850    pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
2851    pseudoParticle[2] = temp; // original in cms system
2852    pseudoParticle[3] = pseudoParticle[0];
2853   
2854    pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
2855    G4double rotation = 2.*pi*G4UniformRand();
2856    pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
2857    pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);   
2858    for(G4int ii=1; ii<=3; ii++)
2859    { 
2860      p = pseudoParticle[ii].mag();
2861      if( p == 0.0 )
2862        pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
2863      else
2864        pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
2865    }
2866   
2867    pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
2868    pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
2869    pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
2870    currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2871   
2872    pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
2873    pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
2874    pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
2875    targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2876   
2877    for( i=0; i<vecLen; ++i )
2878    {
2879      pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
2880      pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
2881      pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
2882      vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
2883    }
2884    //
2885    //  Rotate in direction of primary particle, subtract binding energies
2886    //   and make some further corrections if required
2887    //
2888    Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2889    G4double ekin;
2890    G4double dekin = 0.0;
2891    G4double ek1 = 0.0;
2892    G4int npions = 0;
2893    if( atomicWeight >= 1.5 )            // self-absorption in heavy molecules
2894    {
2895      // corrections for single particle spectra (shower particles)
2896      //
2897      const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
2898      const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
2899      alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
2900      exh = 1.0;
2901      if( alekw > alem[0] )   //   get energy bin
2902      {
2903        exh = val0[6];
2904        for( G4int j=1; j<7; ++j )
2905        {
2906          if( alekw < alem[j] ) // use linear interpolation/extrapolation
2907          {
2908            G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
2909            exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
2910            break;
2911          }
2912        }
2913        exh = 1.0 - exh;
2914      }
2915      const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2916      ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2917      ekin = std::max( 1.0e-6, ekin );
2918      xxh = 1.0;
2919      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2920           modifiedOriginal.GetDefinition() == aPiMinus) &&
2921           currentParticle.GetDefinition() == aPiZero &&
2922           G4UniformRand() <= logWeight) xxh = exh;
2923      dekin += ekin*(1.0-xxh);
2924      ekin *= xxh;
2925      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
2926        ++npions;
2927        ek1 += ekin;
2928      }
2929      currentParticle.SetKineticEnergy( ekin*GeV );
2930      pp = currentParticle.GetTotalMomentum()/MeV;
2931      pp1 = currentParticle.GetMomentum().mag()/MeV;
2932      if( pp1 < 0.001*MeV )
2933      {
2934        G4double costheta = 2.*G4UniformRand() - 1.;
2935        G4double sintheta = std::sqrt(1. - costheta*costheta);
2936        G4double phi = twopi*G4UniformRand();
2937        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2938                                     pp*sintheta*std::sin(phi)*MeV,
2939                                     pp*costheta*MeV ) ;
2940      }
2941      else
2942        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2943      ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2944      ekin = std::max( 1.0e-6, ekin );
2945      xxh = 1.0;
2946      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2947           modifiedOriginal.GetDefinition() == aPiMinus) &&
2948           targetParticle.GetDefinition() == aPiZero &&
2949           G4UniformRand() < logWeight) xxh = exh;
2950      dekin += ekin*(1.0-xxh);
2951      ekin *= xxh;
2952      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2953        ++npions;
2954        ek1 += ekin;
2955      }
2956      targetParticle.SetKineticEnergy( ekin*GeV );
2957      pp = targetParticle.GetTotalMomentum()/MeV;
2958      pp1 = targetParticle.GetMomentum().mag()/MeV;
2959      if( pp1 < 0.001*MeV )
2960      {
2961        G4double costheta = 2.*G4UniformRand() - 1.;
2962        G4double sintheta = std::sqrt(1. - costheta*costheta);
2963        G4double phi = twopi*G4UniformRand();
2964        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2965                                    pp*sintheta*std::sin(phi)*MeV,
2966                                    pp*costheta*MeV ) ;
2967      }
2968      else
2969        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2970      for( i=0; i<vecLen; ++i )
2971      {
2972        ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2973        ekin = std::max( 1.0e-6, ekin );
2974        xxh = 1.0;
2975        if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2976             modifiedOriginal.GetDefinition() == aPiMinus) &&
2977             vec[i]->GetDefinition() == aPiZero &&
2978             G4UniformRand() < logWeight) xxh = exh;
2979        dekin += ekin*(1.0-xxh);
2980        ekin *= xxh;
2981        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
2982          ++npions;
2983          ek1 += ekin;
2984        }
2985        vec[i]->SetKineticEnergy( ekin*GeV );
2986        pp = vec[i]->GetTotalMomentum()/MeV;
2987        pp1 = vec[i]->GetMomentum().mag()/MeV;
2988        if( pp1 < 0.001*MeV )
2989        {
2990          G4double costheta = 2.*G4UniformRand() - 1.;
2991          G4double sintheta = std::sqrt(1. - costheta*costheta);
2992          G4double phi = twopi*G4UniformRand();
2993          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2994                               pp*sintheta*std::sin(phi)*MeV,
2995                               pp*costheta*MeV ) ;
2996        }
2997        else
2998          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2999      }
3000    }
3001    if( (ek1 != 0.0) && (npions > 0) )
3002    {
3003      dekin = 1.0 + dekin/ek1;
3004      //
3005      //  first do the incident particle
3006      //
3007      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") 
3008      {
3009        currentParticle.SetKineticEnergy(
3010         std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
3011        pp = currentParticle.GetTotalMomentum()/MeV;
3012        pp1 = currentParticle.GetMomentum().mag()/MeV;
3013        if( pp1 < 0.001 )
3014        {
3015          G4double costheta = 2.*G4UniformRand() - 1.;
3016          G4double sintheta = std::sqrt(1. - costheta*costheta);
3017          G4double phi = twopi*G4UniformRand();
3018          currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3019                                       pp*sintheta*std::sin(phi)*MeV,
3020                                       pp*costheta*MeV ) ;
3021        } else {
3022          currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3023        }
3024      }
3025
3026      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") 
3027      {
3028        targetParticle.SetKineticEnergy(
3029         std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
3030        pp = targetParticle.GetTotalMomentum()/MeV;
3031        pp1 = targetParticle.GetMomentum().mag()/MeV;
3032        if( pp1 < 0.001 )
3033        {
3034          G4double costheta = 2.*G4UniformRand() - 1.;
3035          G4double sintheta = std::sqrt(1. - costheta*costheta);
3036          G4double phi = twopi*G4UniformRand();
3037          targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3038                                      pp*sintheta*std::sin(phi)*MeV,
3039                                      pp*costheta*MeV ) ;
3040        } else {
3041          targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3042        }
3043      }
3044
3045      for( i=0; i<vecLen; ++i )
3046      {
3047        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi")
3048        {
3049          vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
3050          pp = vec[i]->GetTotalMomentum()/MeV;
3051          pp1 = vec[i]->GetMomentum().mag()/MeV;
3052          if( pp1 < 0.001 )
3053          {
3054            G4double costheta = 2.*G4UniformRand() - 1.;
3055            G4double sintheta = std::sqrt(1. - costheta*costheta);
3056            G4double phi = twopi*G4UniformRand();
3057            vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3058                                 pp*sintheta*std::sin(phi)*MeV,
3059                                 pp*costheta*MeV ) ;
3060          } else {
3061            vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3062          }
3063        }
3064      } // for i
3065    } // if (ek1 != 0)
3066  }
3067 
3068 void G4ReactionDynamics::AddBlackTrackParticles(
3069   const G4double epnb,            // GeV
3070   const G4int npnb,
3071   const G4double edta,            // GeV
3072   const G4int ndta,
3073   const G4double sprob,
3074   const G4double kineticMinimum,  // GeV
3075   const G4double kineticFactor,   // GeV
3076   const G4ReactionProduct &modifiedOriginal,
3077   G4int PinNucleus,
3078   G4int NinNucleus,
3079   const G4Nucleus &targetNucleus,
3080   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3081   G4int &vecLen )
3082  {
3083    // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
3084    //
3085    // npnb is number of proton/neutron black track particles
3086    // ndta is the number of deuterons, tritons, and alphas produced
3087    // epnb is the kinetic energy available for proton/neutron black track particles
3088    // edta is the kinetic energy available for deuteron/triton/alpha particles
3089    //
3090   
3091    G4ParticleDefinition *aProton = G4Proton::Proton();
3092    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3093    G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3094    G4ParticleDefinition *aTriton = G4Triton::Triton();
3095    G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3096   
3097    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
3098    const G4double atomicWeight = G4double(targetNucleus.GetA_asInt());
3099    const G4double atomicNumber = G4double(targetNucleus.GetZ_asInt());
3100   
3101    const G4double ika1 = 3.6;
3102    const G4double ika2 = 35.56;
3103    const G4double ika3 = 6.45;
3104   
3105    G4int i;
3106    G4double pp;
3107    G4double kinCreated = 0;
3108    G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
3109
3110    // First add protons and neutrons to final state
3111
3112    if (npnb > 0)
3113    {
3114      G4double backwardKinetic = 0.0;
3115      G4int local_npnb = npnb;
3116      for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
3117      G4double local_epnb = epnb;
3118      if (ndta == 0) local_epnb += edta;   // Retrieve unused kinetic energy
3119      G4double ekin = local_epnb/std::max(1,local_npnb);
3120     
3121      for( i=0; i<local_npnb; ++i )
3122      {
3123        G4ReactionProduct * p1 = new G4ReactionProduct();
3124        if( backwardKinetic > local_epnb )
3125        {
3126          delete p1;
3127          break;   
3128        }
3129        G4double ran = G4UniformRand();
3130        G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
3131        if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
3132        backwardKinetic += kinetic;
3133        if( backwardKinetic > local_epnb )
3134           kinetic = std::max( kineticMinimum, local_epnb-(backwardKinetic-kinetic) );
3135
3136        if (G4UniformRand() > (1.0-atomicNumber/atomicWeight)) {
3137
3138          // Boil off a proton if there are any left, otherwise a neutron
3139
3140          if (PinNucleus > 0) {
3141            p1->SetDefinition( aProton );
3142            PinNucleus--;
3143          } else if (NinNucleus > 0) {
3144            p1->SetDefinition( aNeutron );
3145            NinNucleus--;
3146          } else {
3147            delete p1;
3148            break;     // no nucleons left in nucleus
3149          }
3150        } else {
3151
3152          // Boil off a neutron if there are any left, otherwise a proton
3153
3154          if (NinNucleus > 0) {
3155            p1->SetDefinition( aNeutron );
3156            NinNucleus--;
3157          } else if (PinNucleus > 0) {
3158            p1->SetDefinition( aProton );
3159            PinNucleus--;
3160          } else {
3161            delete p1;
3162            break;     // no nucleons left in nucleus
3163          }
3164        }
3165
3166        vec.SetElement( vecLen, p1 );
3167        G4double cost = G4UniformRand() * 2.0 - 1.0;
3168        G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
3169        G4double phi = twopi * G4UniformRand();
3170        vec[vecLen]->SetNewlyAdded( true );
3171        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3172        kinCreated+=kinetic;
3173        pp = vec[vecLen]->GetTotalMomentum()/MeV;
3174        vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3175                                    pp*sint*std::cos(phi)*MeV,
3176                                    pp*cost*MeV );
3177        vecLen++;
3178        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3179      }
3180
3181      if (NinNucleus > 0) {
3182        if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
3183        {
3184          G4double ekw = ekOriginal/GeV;
3185          G4int ika, kk = 0;
3186          if( ekw > 1.0 )ekw *= ekw;
3187          ekw = std::max( 0.1, ekw );
3188          ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/
3189                                             atomicWeight-ika2)/ika3)/ekw);
3190          if( ika > 0 )
3191          {
3192            for( i=(vecLen-1); i>=0; --i )
3193            {
3194              if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
3195              {
3196                vec[i]->SetDefinitionAndUpdateE( aNeutron );  // modified 22-Oct-97
3197                PinNucleus++;
3198                NinNucleus--;
3199                if( ++kk > ika )break;
3200              }
3201            }
3202          }
3203        }
3204      } // if (NinNucleus >0)
3205    } // if (npnb > 0)
3206
3207    //  Next try to add deuterons, tritons and alphas to final state
3208
3209    if (ndta > 0)
3210    {
3211      G4double backwardKinetic = 0.0;
3212      G4int local_ndta=ndta;
3213      for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
3214      G4double local_edta = edta;
3215      if (npnb == 0) local_edta += epnb;  // Retrieve unused kinetic energy
3216      G4double ekin = local_edta/std::max(1,local_ndta);
3217
3218      for( i=0; i<local_ndta; ++i )
3219      {
3220        G4ReactionProduct *p2 = new G4ReactionProduct();
3221        if( backwardKinetic > local_edta )
3222        {
3223          delete p2;
3224          break;
3225        }
3226        G4double ran = G4UniformRand();
3227        G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
3228        if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
3229        backwardKinetic += kinetic;
3230        if( backwardKinetic > local_edta )kinetic = local_edta-(backwardKinetic-kinetic);
3231        if( kinetic < 0.0 )kinetic = kineticMinimum;
3232        G4double cost = 2.0*G4UniformRand() - 1.0;
3233        G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
3234        G4double phi = twopi*G4UniformRand();
3235        ran = G4UniformRand();
3236        if (ran < 0.60) {
3237          if (PinNucleus > 0 && NinNucleus > 0) {
3238            p2->SetDefinition( aDeuteron );
3239            PinNucleus--;
3240            NinNucleus--;
3241          } else if (NinNucleus > 0) {
3242            p2->SetDefinition( aNeutron );
3243            NinNucleus--;
3244          } else if (PinNucleus > 0) {
3245            p2->SetDefinition( aProton );
3246            PinNucleus--;
3247          } else {
3248            delete p2;
3249            break;
3250          }
3251        } else if (ran < 0.90) {
3252          if (PinNucleus > 0 && NinNucleus > 1) {
3253            p2->SetDefinition( aTriton );
3254            PinNucleus--;
3255            NinNucleus -= 2;
3256          } else if (PinNucleus > 0 && NinNucleus > 0) {
3257            p2->SetDefinition( aDeuteron );
3258            PinNucleus--;
3259            NinNucleus--;
3260          } else if (NinNucleus > 0) {
3261            p2->SetDefinition( aNeutron );
3262            NinNucleus--;
3263          } else if (PinNucleus > 0) {
3264            p2->SetDefinition( aProton );
3265            PinNucleus--;
3266          } else {
3267            delete p2;
3268            break;
3269          }
3270        } else {
3271          if (PinNucleus > 1 && NinNucleus > 1) {
3272            p2->SetDefinition( anAlpha );
3273            PinNucleus -= 2;
3274            NinNucleus -= 2;
3275          } else if (PinNucleus > 0 && NinNucleus > 1) {
3276            p2->SetDefinition( aTriton );
3277            PinNucleus--;
3278            NinNucleus -= 2;
3279          } else if (PinNucleus > 0 && NinNucleus > 0) {
3280            p2->SetDefinition( aDeuteron );
3281            PinNucleus--;
3282            NinNucleus--;
3283          } else if (NinNucleus > 0) {
3284            p2->SetDefinition( aNeutron );
3285            NinNucleus--;
3286          } else if (PinNucleus > 0) {
3287            p2->SetDefinition( aProton );
3288            PinNucleus--;
3289          } else {
3290            delete p2;
3291            break;
3292          }
3293        }
3294
3295        vec.SetElement( vecLen, p2 );
3296        vec[vecLen]->SetNewlyAdded( true );
3297        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3298        kinCreated+=kinetic;
3299        pp = vec[vecLen]->GetTotalMomentum()/MeV;
3300        vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3301                                    pp*sint*std::cos(phi)*MeV,
3302                                    pp*cost*MeV );
3303      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3304      }
3305    } // if (ndta > 0)
3306
3307    //    G4double delta = epnb+edta - kinCreated;
3308  }
3309
3310
3311 std::pair<G4int, G4int> G4ReactionDynamics::GetFinalStateNucleons(
3312   const G4DynamicParticle* originalTarget,
3313   const G4FastVector<G4ReactionProduct,GHADLISTSIZE>& vec, 
3314   const G4int& vecLen)
3315  {
3316    // Get number of protons and neutrons removed from the target nucleus
3317 
3318    G4int protonsRemoved = 0;
3319    G4int neutronsRemoved = 0;
3320    if (originalTarget->GetDefinition()->GetParticleName() == "proton")
3321      protonsRemoved++;
3322    else
3323      neutronsRemoved++;
3324 
3325    G4String secName;
3326    for (G4int i = 0; i < vecLen; i++) {
3327      secName = vec[i]->GetDefinition()->GetParticleName();
3328      if (secName == "proton") {
3329        protonsRemoved++;
3330      } else if (secName == "neutron") {
3331        neutronsRemoved++;
3332      } else if (secName == "anti_proton") {
3333        protonsRemoved--;
3334      } else if (secName == "anti_neutron") {
3335        neutronsRemoved--;
3336      }
3337    }
3338
3339    return std::pair<G4int, G4int>(protonsRemoved, neutronsRemoved);
3340  }
3341
3342
3343 void G4ReactionDynamics::MomentumCheck(
3344   const G4ReactionProduct &modifiedOriginal,
3345   G4ReactionProduct &currentParticle,
3346   G4ReactionProduct &targetParticle,
3347   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3348   G4int &vecLen )
3349  {
3350    const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
3351    G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
3352    G4double pMass;
3353    if( testMomentum >= pOriginal )
3354    {
3355      pMass = currentParticle.GetMass()/MeV;
3356      currentParticle.SetTotalEnergy(
3357       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3358      currentParticle.SetMomentum(
3359       currentParticle.GetMomentum() * (pOriginal/testMomentum) );
3360    }
3361    testMomentum = targetParticle.GetMomentum().mag()/MeV;
3362    if( testMomentum >= pOriginal )
3363    {
3364      pMass = targetParticle.GetMass()/MeV;
3365      targetParticle.SetTotalEnergy(
3366       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3367      targetParticle.SetMomentum(
3368       targetParticle.GetMomentum() * (pOriginal/testMomentum) );
3369    }
3370    for( G4int i=0; i<vecLen; ++i )
3371    {
3372      testMomentum = vec[i]->GetMomentum().mag()/MeV;
3373      if( testMomentum >= pOriginal )
3374      {
3375        pMass = vec[i]->GetMass()/MeV;
3376        vec[i]->SetTotalEnergy(
3377         std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3378        vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
3379      }
3380    }
3381  }
3382
3383 void G4ReactionDynamics::ProduceStrangeParticlePairs(
3384   G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3385   G4int &vecLen,
3386   const G4ReactionProduct &modifiedOriginal,
3387   const G4DynamicParticle *originalTarget, 
3388   G4ReactionProduct &currentParticle,
3389   G4ReactionProduct &targetParticle,
3390   G4bool &incidentHasChanged,
3391   G4bool &targetHasChanged )
3392  {
3393    // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
3394    //
3395    // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
3396    //                            K+ Y0, K0 Y+,  K0 Y-
3397    // For antibaryon induced reactions half of the cross sections KB YB
3398    // pairs are produced.  Charge is not conserved, no experimental data available
3399    // for exclusive reactions, therefore some average behaviour assumed.
3400    // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
3401    //
3402    if( vecLen == 0 )return;
3403    //
3404    // the following protects against annihilation processes
3405    //
3406    if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
3407   
3408    const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
3409    const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
3410    G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
3411    G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
3412                                        targetMass*targetMass +
3413                                        2.0*targetMass*etOriginal );  // GeV
3414    G4double currentMass = currentParticle.GetMass()/GeV;
3415    G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
3416    if( availableEnergy <= 1.0 )return;
3417   
3418    G4ParticleDefinition *aProton = G4Proton::Proton();
3419    G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
3420    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3421    G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
3422    G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
3423    G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
3424    G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
3425    G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
3426    G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
3427    G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
3428    G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
3429    G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
3430    G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
3431    G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
3432    G4ParticleDefinition *aLambda = G4Lambda::Lambda();
3433    G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
3434   
3435    const G4double protonMass = aProton->GetPDGMass()/GeV;
3436    const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
3437    //
3438    // determine the center of mass energy bin
3439    //
3440    const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
3441
3442    G4int ibin, i3, i4;
3443    G4double avk, avy, avn, ran;
3444    G4int i = 1;
3445    while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
3446    if( i == 12 )
3447      ibin = 11;
3448    else
3449      ibin = i;
3450    //
3451    // the fortran code chooses a random replacement of produced kaons
3452    //  but does not take into account charge conservation
3453    //
3454    if( vecLen == 1 )  // we know that vecLen > 0
3455    {
3456      i3 = 0;
3457      i4 = 1;   // note that we will be adding a new secondary particle in this case only
3458    }
3459    else               // otherwise  0 <= i3,i4 < vecLen
3460    {
3461      G4double ran = G4UniformRand();
3462      while( ran == 1.0 )ran = G4UniformRand();
3463      i4 = i3 = G4int( vecLen*ran );
3464      while( i3 == i4 )
3465      {
3466        ran = G4UniformRand();
3467        while( ran == 1.0 )ran = G4UniformRand();
3468        i4 = G4int( vecLen*ran );
3469      }
3470    }
3471    //
3472    // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
3473    //
3474    const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
3475                               0.0975, 0.123, 0.28,  0.398,  0.495,  0.573 };
3476    const G4double avky[] = { 0.005, 0.03,  0.064, 0.095, 0.115, 0.13,
3477                              0.145, 0.155, 0.20,  0.205, 0.210, 0.212 };
3478    const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
3479                               0.04,    0.05,   0.12,   0.15,   0.18, 0.20 };
3480   
3481    avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3482      /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
3483    avk = std::exp(avk);
3484   
3485    avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3486      /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
3487    avy = std::exp(avy);
3488   
3489    avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3490      /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
3491    avn = std::exp(avn);
3492   
3493    if( avk+avy+avn <= 0.0 )return;
3494   
3495    if( currentMass < protonMass )avy /= 2.0;
3496    if( targetMass < protonMass )avy = 0.0;
3497    avy += avk+avn;
3498    avk += avn;
3499    ran = G4UniformRand();
3500    if(  ran < avn )
3501    {
3502      if( availableEnergy < 2.0 )return;
3503      if( vecLen == 1 )                              // add a new secondary
3504      {
3505        G4ReactionProduct *p1 = new G4ReactionProduct;
3506        if( G4UniformRand() < 0.5 )
3507        {
3508          vec[0]->SetDefinition( aNeutron );
3509          p1->SetDefinition( anAntiNeutron );
3510          (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3511          vec[0]->SetMayBeKilled(false);
3512          p1->SetMayBeKilled(false);
3513        }
3514        else
3515        {
3516          vec[0]->SetDefinition( aProton );
3517          p1->SetDefinition( anAntiProton );
3518          (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3519          vec[0]->SetMayBeKilled(false);
3520          p1->SetMayBeKilled(false);
3521        }
3522        vec.SetElement( vecLen++, p1 );
3523      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3524      }
3525      else
3526      {                                             // replace two secondaries
3527        if( G4UniformRand() < 0.5 )
3528        {
3529          vec[i3]->SetDefinition( aNeutron );
3530          vec[i4]->SetDefinition( anAntiNeutron );
3531          vec[i3]->SetMayBeKilled(false);
3532          vec[i4]->SetMayBeKilled(false);
3533        }
3534        else
3535        {
3536          vec[i3]->SetDefinition( aProton );
3537          vec[i4]->SetDefinition( anAntiProton );
3538          vec[i3]->SetMayBeKilled(false);
3539          vec[i4]->SetMayBeKilled(false);
3540        }
3541      }
3542    }
3543    else if( ran < avk )
3544    {
3545      if( availableEnergy < 1.0 )return;
3546     
3547      const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
3548                               0.6875, 0.7500, 0.8750, 1.000 };
3549      const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
3550      const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
3551      ran = G4UniformRand();
3552      i = 0;
3553      while( (i<9) && (ran>=kkb[i]) )++i;
3554      if( i == 9 )return;
3555      //
3556      // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
3557      // charge       +  -   +  0   +  0   0  0   0  0   0  0   0  0   0  -   0  -
3558      //
3559      switch( ipakkb1[i] )
3560      {
3561       case 10:
3562         vec[i3]->SetDefinition( aKaonPlus );
3563         vec[i3]->SetMayBeKilled(false);
3564         break;
3565       case 11:
3566         vec[i3]->SetDefinition( aKaonZS );
3567         vec[i3]->SetMayBeKilled(false);
3568         break;
3569       case 12:
3570         vec[i3]->SetDefinition( aKaonZL );
3571         vec[i3]->SetMayBeKilled(false);
3572         break;
3573      }
3574      if( vecLen == 1 )                          // add a secondary
3575      {
3576        G4ReactionProduct *p1 = new G4ReactionProduct;
3577        switch( ipakkb2[i] )
3578        {
3579         case 11:
3580           p1->SetDefinition( aKaonZS );
3581           p1->SetMayBeKilled(false);
3582           break;
3583         case 12:
3584           p1->SetDefinition( aKaonZL );
3585           p1->SetMayBeKilled(false);
3586           break;
3587         case 13:
3588           p1->SetDefinition( aKaonMinus );
3589           p1->SetMayBeKilled(false);
3590           break;
3591        }
3592        (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3593        vec.SetElement( vecLen++, p1 );
3594      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3595      }
3596      else                                        // replace
3597      {
3598        switch( ipakkb2[i] )
3599        {
3600         case 11:
3601           vec[i4]->SetDefinition( aKaonZS );
3602           vec[i4]->SetMayBeKilled(false);
3603           break;
3604         case 12:
3605           vec[i4]->SetDefinition( aKaonZL );
3606           vec[i4]->SetMayBeKilled(false);
3607           break;
3608         case 13:
3609           vec[i4]->SetDefinition( aKaonMinus );
3610           vec[i4]->SetMayBeKilled(false);
3611           break;
3612        }
3613      }
3614    }
3615    else if( ran < avy )
3616    {
3617      if( availableEnergy < 1.6 )return;
3618     
3619      const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
3620                              0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
3621      const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
3622      const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
3623      const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
3624      const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
3625      ran = G4UniformRand();
3626      i = 0;
3627      while( (i<12) && (ran>ky[i]) )++i;
3628      if( i == 12 )return;
3629      if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
3630      {
3631        // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
3632        //             0  +   0  0   0  0   +  +   +  0   +  0
3633        //
3634        //             21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
3635        //             0  +   0  0   0  0   -  +   -  0   -  0
3636        switch( ipaky1[i] )
3637        {
3638         case 18:
3639           targetParticle.SetDefinition( aLambda );
3640           break;
3641         case 20:
3642           targetParticle.SetDefinition( aSigmaPlus );
3643           break;
3644         case 21:
3645           targetParticle.SetDefinition( aSigmaZero );
3646           break;
3647         case 22:
3648           targetParticle.SetDefinition( aSigmaMinus );
3649           break;
3650        }
3651        targetHasChanged = true;
3652        switch( ipaky2[i] )
3653        {
3654         case 10:
3655           vec[i3]->SetDefinition( aKaonPlus ); 
3656           vec[i3]->SetMayBeKilled(false);
3657           break;
3658         case 11:
3659           vec[i3]->SetDefinition( aKaonZS );
3660           vec[i3]->SetMayBeKilled(false);
3661           break;
3662         case 12:
3663           vec[i3]->SetDefinition( aKaonZL );
3664           vec[i3]->SetMayBeKilled(false);
3665           break;
3666        }
3667      }
3668      else  // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
3669      {
3670        // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
3671        //              24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
3672        if( (currentParticle.GetDefinition() == anAntiProton) ||
3673            (currentParticle.GetDefinition() == anAntiNeutron) ||
3674            (currentParticle.GetDefinition() == anAntiLambda) ||
3675            (currentMass > sigmaMinusMass) )
3676        {
3677          switch( ipakyb1[i] )
3678          {
3679           case 19:
3680             currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
3681             break;
3682           case 23:
3683             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
3684             break;
3685           case 24:
3686             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
3687             break;
3688           case 25:
3689             currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
3690             break;
3691          }
3692          incidentHasChanged = true;
3693          switch( ipakyb2[i] )
3694          {
3695           case 11:
3696             vec[i3]->SetDefinition( aKaonZS ); 
3697             vec[i3]->SetMayBeKilled(false);
3698             break;
3699           case 12:
3700             vec[i3]->SetDefinition( aKaonZL );
3701             vec[i3]->SetMayBeKilled(false);
3702             break;
3703           case 13:
3704             vec[i3]->SetDefinition( aKaonMinus );
3705             vec[i3]->SetMayBeKilled(false);
3706             break;
3707          }
3708        }
3709        else
3710        {
3711          switch( ipaky1[i] )
3712          {
3713           case 18:
3714             currentParticle.SetDefinitionAndUpdateE( aLambda );
3715             break;
3716           case 20:
3717             currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
3718             break;
3719           case 21:
3720             currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
3721             break;
3722           case 22:
3723             currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
3724             break;
3725          }
3726          incidentHasChanged = true;
3727          switch( ipaky2[i] )
3728          {
3729           case 10:
3730             vec[i3]->SetDefinition( aKaonPlus ); 
3731             vec[i3]->SetMayBeKilled(false);
3732             break;
3733           case 11:
3734             vec[i3]->SetDefinition( aKaonZS );
3735             vec[i3]->SetMayBeKilled(false);
3736             break;
3737           case 12:
3738             vec[i3]->SetDefinition( aKaonZL );
3739             vec[i3]->SetMayBeKilled(false);
3740             break;
3741          }
3742        }
3743      }
3744    }
3745    else return;
3746    //
3747    //  check the available energy
3748    //   if there is not enough energy for kkb/ky pair production
3749    //   then reduce the number of secondary particles
3750    //  NOTE:
3751    //        the number of secondaries may have been changed
3752    //        the incident and/or target particles may have changed
3753    //        charge conservation is ignored (as well as strangness conservation)
3754    //
3755    currentMass = currentParticle.GetMass()/GeV;
3756    targetMass = targetParticle.GetMass()/GeV;
3757   
3758    G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
3759    for( i=0; i<vecLen; ++i )
3760    {
3761      energyCheck -= vec[i]->GetMass()/GeV;
3762      if( energyCheck < 0.0 )      // chop off the secondary List
3763      {
3764        vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
3765        G4int j;
3766        for(j=i; j<vecLen; j++) delete vec[j];
3767        break;
3768      }
3769    }
3770    return;
3771  }
3772
3773 void
3774  G4ReactionDynamics::NuclearReaction(
3775   G4FastVector<G4ReactionProduct,4> &vec,
3776   G4int &vecLen,
3777   const G4HadProjectile *originalIncident,
3778   const G4Nucleus &targetNucleus,
3779   const G4double theAtomicMass,
3780   const G4double *mass )
3781  {
3782    // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
3783    //
3784    // Nuclear reaction kinematics at low energies
3785    //
3786    G4ParticleDefinition *aGamma = G4Gamma::Gamma();
3787    G4ParticleDefinition *aProton = G4Proton::Proton();
3788    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3789    G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3790    G4ParticleDefinition *aTriton = G4Triton::Triton();
3791    G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3792   
3793    const G4double aProtonMass = aProton->GetPDGMass()/MeV;
3794    const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
3795    const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
3796    const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
3797    const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
3798
3799    G4ReactionProduct currentParticle;
3800    currentParticle = *originalIncident;
3801    //
3802    // Set beam particle, take kinetic energy of current particle as the
3803    // fundamental quantity.  Due to the difficult kinematic, all masses have to
3804    // be assigned the best measured values
3805    //
3806    G4double p = currentParticle.GetTotalMomentum();
3807    G4double pp = currentParticle.GetMomentum().mag();
3808    if( pp <= 0.001*MeV )
3809    {
3810      G4double phinve = twopi*G4UniformRand();
3811      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3812      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3813                                   p*std::sin(rthnve)*std::sin(phinve),
3814                                   p*std::cos(rthnve) );
3815    }
3816    else
3817      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3818    //
3819    // calculate Q-value of reactions
3820    //
3821    G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
3822    G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
3823    G4double qv = currentKinetic + theAtomicMass + currentMass;
3824   
3825    G4double qval[9];
3826    qval[0] = qv - mass[0];
3827    qval[1] = qv - mass[1] - aNeutronMass;
3828    qval[2] = qv - mass[2] - aProtonMass;
3829    qval[3] = qv - mass[3] - aDeuteronMass;
3830    qval[4] = qv - mass[4] - aTritonMass;
3831    qval[5] = qv - mass[5] - anAlphaMass;
3832    qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
3833    qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
3834    qval[8] = qv - mass[8] - aProtonMass  - aProtonMass;
3835   
3836    if( currentParticle.GetDefinition() == aNeutron )
3837    {
3838      const G4double A = G4double(targetNucleus.GetA_asInt());    // atomic weight
3839      if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
3840        qval[0] = 0.0;
3841      if( G4UniformRand() >= currentKinetic/7.9254*A )
3842        qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
3843    }
3844    else
3845      qval[0] = 0.0;
3846   
3847    G4int i;
3848    qv = 0.0;
3849    for( i=0; i<9; ++i )
3850    {
3851      if( mass[i] < 500.0*MeV )qval[i] = 0.0;
3852      if( qval[i] < 0.0 )qval[i] = 0.0;
3853      qv += qval[i];
3854    }
3855    G4double qv1 = 0.0;
3856    G4double ran = G4UniformRand();
3857    G4int index;
3858    for( index=0; index<9; ++index )
3859    {
3860      if( qval[index] > 0.0 )
3861      {
3862        qv1 += qval[index]/qv;
3863        if( ran <= qv1 )break;
3864      }
3865    }
3866    if( index == 9 )  // loop continued to the end
3867    {
3868      throw G4HadronicException(__FILE__, __LINE__,
3869           "G4ReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
3870    }
3871    G4double ke = currentParticle.GetKineticEnergy()/GeV;
3872    G4int nt = 2;
3873    if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
3874   
3875    G4ReactionProduct **v = new G4ReactionProduct * [3];
3876    v[0] =  new G4ReactionProduct;
3877    v[1] =  new G4ReactionProduct;
3878    v[2] =  new G4ReactionProduct;
3879   
3880    v[0]->SetMass( mass[index]*MeV );
3881    switch( index )
3882    {
3883     case 0:
3884       v[1]->SetDefinition( aGamma );
3885       v[2]->SetDefinition( aGamma );
3886       break;
3887     case 1:
3888       v[1]->SetDefinition( aNeutron );
3889       v[2]->SetDefinition( aGamma );
3890       break;
3891     case 2:
3892       v[1]->SetDefinition( aProton );
3893       v[2]->SetDefinition( aGamma );
3894       break;
3895     case 3:
3896       v[1]->SetDefinition( aDeuteron );
3897       v[2]->SetDefinition( aGamma );
3898       break;
3899     case 4:
3900       v[1]->SetDefinition( aTriton );
3901       v[2]->SetDefinition( aGamma );
3902       break;
3903     case 5:
3904       v[1]->SetDefinition( anAlpha );
3905       v[2]->SetDefinition( aGamma );
3906       break;
3907     case 6:
3908       v[1]->SetDefinition( aNeutron );
3909       v[2]->SetDefinition( aNeutron );
3910       break;
3911     case 7:
3912       v[1]->SetDefinition( aNeutron );
3913       v[2]->SetDefinition( aProton );
3914       break;
3915     case 8:
3916       v[1]->SetDefinition( aProton );
3917       v[2]->SetDefinition( aProton );
3918       break;
3919    }
3920    //
3921    // calculate centre of mass energy
3922    //
3923    G4ReactionProduct pseudo1;
3924    pseudo1.SetMass( theAtomicMass*MeV );
3925    pseudo1.SetTotalEnergy( theAtomicMass*MeV );
3926    G4ReactionProduct pseudo2 = currentParticle + pseudo1;
3927    pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
3928    //
3929    // use phase space routine in centre of mass system
3930    //
3931    G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
3932    tempV.Initialize( nt );
3933    G4int tempLen = 0;
3934    tempV.SetElement( tempLen++, v[0] );
3935    tempV.SetElement( tempLen++, v[1] );
3936    if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
3937    G4bool constantCrossSection = true;
3938    GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
3939    v[0]->Lorentz( *v[0], pseudo2 );
3940    v[1]->Lorentz( *v[1], pseudo2 );
3941    if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
3942   
3943    G4bool particleIsDefined = false;
3944    if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
3945    {
3946      v[0]->SetDefinition( aProton );
3947      particleIsDefined = true;
3948    }
3949    else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
3950    {
3951      v[0]->SetDefinition( aNeutron );
3952      particleIsDefined = true;
3953    }
3954    else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
3955    {
3956      v[0]->SetDefinition( aDeuteron );
3957      particleIsDefined = true;
3958    }
3959    else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
3960    {
3961      v[0]->SetDefinition( aTriton );
3962      particleIsDefined = true;
3963    }
3964    else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
3965    {
3966      v[0]->SetDefinition( anAlpha );
3967      particleIsDefined = true;
3968    }
3969    currentParticle.SetKineticEnergy(
3970     std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
3971    p = currentParticle.GetTotalMomentum();
3972    pp = currentParticle.GetMomentum().mag();
3973    if( pp <= 0.001*MeV )
3974    {
3975      G4double phinve = twopi*G4UniformRand();
3976      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3977      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3978                                   p*std::sin(rthnve)*std::sin(phinve),
3979                                   p*std::cos(rthnve) );
3980    }
3981    else
3982      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3983   
3984    if( particleIsDefined )
3985    {
3986      v[0]->SetKineticEnergy(
3987       std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
3988      p = v[0]->GetTotalMomentum();
3989      pp = v[0]->GetMomentum().mag();
3990      if( pp <= 0.001*MeV )
3991      {
3992        G4double phinve = twopi*G4UniformRand();
3993        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
3994        v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3995                          p*std::sin(rthnve)*std::sin(phinve),
3996                          p*std::cos(rthnve) );
3997      }
3998      else
3999        v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
4000    }
4001    if( (v[1]->GetDefinition() == aDeuteron) ||
4002        (v[1]->GetDefinition() == aTriton)   ||
4003        (v[1]->GetDefinition() == anAlpha) ) 
4004      v[1]->SetKineticEnergy(
4005       std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
4006    else
4007      v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
4008   
4009    p = v[1]->GetTotalMomentum();
4010    pp = v[1]->GetMomentum().mag();
4011    if( pp <= 0.001*MeV )
4012    {
4013      G4double phinve = twopi*G4UniformRand();
4014      G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4015      v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4016                        p*std::sin(rthnve)*std::sin(phinve),
4017                        p*std::cos(rthnve) );
4018    }
4019    else
4020      v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
4021   
4022    if( nt == 3 )
4023    {
4024      if( (v[2]->GetDefinition() == aDeuteron) ||
4025          (v[2]->GetDefinition() == aTriton)   ||
4026          (v[2]->GetDefinition() == anAlpha) ) 
4027        v[2]->SetKineticEnergy(
4028         std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
4029      else
4030        v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
4031     
4032      p = v[2]->GetTotalMomentum();
4033      pp = v[2]->GetMomentum().mag();
4034      if( pp <= 0.001*MeV )
4035      {
4036        G4double phinve = twopi*G4UniformRand();
4037        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4038        v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4039                          p*std::sin(rthnve)*std::sin(phinve),
4040                          p*std::cos(rthnve) );
4041      }
4042      else
4043        v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
4044    }
4045    G4int del;
4046    for(del=0; del<vecLen; del++) delete vec[del];
4047    vecLen = 0;
4048    if( particleIsDefined )
4049    {
4050      vec.SetElement( vecLen++, v[0] );
4051    }
4052    else
4053    {
4054      delete v[0];
4055    }
4056    vec.SetElement( vecLen++, v[1] );
4057    if( nt == 3 )
4058    {
4059      vec.SetElement( vecLen++, v[2] );
4060    }
4061    else
4062    {
4063      delete v[2];
4064    }
4065    delete [] v;
4066    return;
4067  }
4068 
4069 /* end of file */
4070 
Note: See TracBrowser for help on using the repository browser.