source: trunk/source/processes/hadronic/models/rpg/src/G4RPGReaction.cc @ 910

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

import all except CVS

File size: 43.5 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// $Id: G4RPGReaction.cc,v 1.1 2007/07/18 21:04:21 dennis Exp $
27// GEANT4 tag $Name: geant4-09-01-patch-02 $
28//
29
30#include "G4RPGReaction.hh"
31#include "Randomize.hh"
32#include <iostream>
33
34
35G4bool G4RPGReaction::
36ReactionStage(const G4HadProjectile* /*originalIncident*/,
37              G4ReactionProduct& /*modifiedOriginal*/,
38              G4bool& /*incidentHasChanged*/,
39              const G4DynamicParticle* /*originalTarget*/,
40              G4ReactionProduct& /*targetParticle*/,
41              G4bool& /*targetHasChanged*/,
42              const G4Nucleus& /*targetNucleus*/,
43              G4ReactionProduct& /*currentParticle*/,
44              G4FastVector<G4ReactionProduct,256>& /*vec*/,
45              G4int& /*vecLen*/,
46              G4bool /*leadFlag*/,
47              G4ReactionProduct& /*leadingStrangeParticle*/)
48{
49  G4cout << " G4RPGReactionStage must be overridden in a derived class " 
50         << G4endl;
51  return false;
52}
53
54
55void G4RPGReaction::
56AddBlackTrackParticles(const G4double epnb,            // GeV
57                       const G4int npnb,
58                       const G4double edta,            // GeV
59                       const G4int ndta,
60                       const G4double sprob,
61                       const G4double kineticMinimum,  // GeV
62                       const G4double kineticFactor,   // GeV
63                       const G4ReactionProduct &modifiedOriginal,
64                       G4int PinNucleus,
65                       G4int NinNucleus,
66                       const G4Nucleus &targetNucleus,
67                       G4FastVector<G4ReactionProduct,256> &vec,
68                       G4int &vecLen )
69{
70  // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
71  //
72  // npnb is number of proton/neutron black track particles
73  // ndta is the number of deuterons, tritons, and alphas produced
74  // epnb is the kinetic energy available for proton/neutron black track particles
75  // edta is the kinetic energy available for deuteron/triton/alpha particles
76  //
77   
78  G4ParticleDefinition *aProton = G4Proton::Proton();
79  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
80  G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
81  G4ParticleDefinition *aTriton = G4Triton::Triton();
82  G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
83   
84    const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
85    const G4double atomicWeight = targetNucleus.GetN();
86    const G4double atomicNumber = targetNucleus.GetZ();
87   
88    const G4double ika1 = 3.6;
89    const G4double ika2 = 35.56;
90    const G4double ika3 = 6.45;
91   
92    G4int i;
93    G4double pp;
94    G4double kinCreated = 0;
95    G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
96
97    // First add protons and neutrons to final state
98
99    if (npnb > 0)
100    {
101      G4double backwardKinetic = 0.0;
102      G4int local_npnb = npnb;
103      for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
104      G4double local_epnb = epnb;
105      if (ndta == 0) local_epnb += edta;   // Retrieve unused kinetic energy
106      G4double ekin = local_epnb/std::max(1,local_npnb);
107     
108      for( i=0; i<local_npnb; ++i )
109      {
110        G4ReactionProduct * p1 = new G4ReactionProduct();
111        if( backwardKinetic > local_epnb )
112        {
113          delete p1;
114          break;   
115        }
116        G4double ran = G4UniformRand();
117        G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
118        if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
119        backwardKinetic += kinetic;
120        if( backwardKinetic > local_epnb )
121           kinetic = std::max( kineticMinimum, local_epnb-(backwardKinetic-kinetic) );
122
123        if (G4UniformRand() > (1.0-atomicNumber/atomicWeight)) {
124
125          // Boil off a proton if there are any left, otherwise a neutron
126
127          if (PinNucleus > 0) {
128            p1->SetDefinition( aProton );
129            PinNucleus--;
130          } else if (NinNucleus > 0) {
131            p1->SetDefinition( aNeutron );
132            NinNucleus--;
133          } else {
134            delete p1;
135            break;     // no nucleons left in nucleus
136          }
137        } else {
138
139          // Boil off a neutron if there are any left, otherwise a proton
140
141          if (NinNucleus > 0) {
142            p1->SetDefinition( aNeutron );
143            NinNucleus--;
144          } else if (PinNucleus > 0) {
145            p1->SetDefinition( aProton );
146            PinNucleus--;
147          } else {
148            delete p1;
149            break;     // no nucleons left in nucleus
150          }
151        }
152
153        vec.SetElement( vecLen, p1 );
154        G4double cost = G4UniformRand() * 2.0 - 1.0;
155        G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
156        G4double phi = twopi * G4UniformRand();
157        vec[vecLen]->SetNewlyAdded( true );
158        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
159        kinCreated+=kinetic;
160        pp = vec[vecLen]->GetTotalMomentum()/MeV;
161        vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
162                                    pp*sint*std::cos(phi)*MeV,
163                                    pp*cost*MeV );
164        vecLen++;
165        // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
166      }
167
168      if (NinNucleus > 0) {
169        if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
170        {
171          G4double ekw = ekOriginal/GeV;
172          G4int ika, kk = 0;
173          if( ekw > 1.0 )ekw *= ekw;
174          ekw = std::max( 0.1, ekw );
175          ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/
176                                             atomicWeight-ika2)/ika3)/ekw);
177          if( ika > 0 )
178          {
179            for( i=(vecLen-1); i>=0; --i )
180            {
181              if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
182              {
183                vec[i]->SetDefinitionAndUpdateE( aNeutron );  // modified 22-Oct-97
184                PinNucleus++;
185                NinNucleus--;
186                if( ++kk > ika )break;
187              }
188            }
189          }
190        }
191      } // if (NinNucleus >0)
192    } // if (npnb > 0)
193
194    //  Next try to add deuterons, tritons and alphas to final state
195
196    if (ndta > 0)
197    {
198      G4double backwardKinetic = 0.0;
199      G4int local_ndta=ndta;
200      // DHW      for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
201      G4double local_edta = edta;
202      if (npnb == 0) local_edta += epnb;  // Retrieve unused kinetic energy
203      G4double ekin = local_edta/std::max(1,local_ndta);
204
205      for( i=0; i<local_ndta; ++i )
206      {
207        G4ReactionProduct *p2 = new G4ReactionProduct();
208        if( backwardKinetic > local_edta )
209        {
210          delete p2;
211          break;
212        }
213        G4double ran = G4UniformRand();
214        G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
215        if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
216        backwardKinetic += kinetic;
217        if( backwardKinetic > local_edta )kinetic = local_edta-(backwardKinetic-kinetic);
218        if( kinetic < 0.0 )kinetic = kineticMinimum;
219        G4double cost = 2.0*G4UniformRand() - 1.0;
220        G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
221        G4double phi = twopi*G4UniformRand();
222        ran = G4UniformRand();
223        if (ran < 0.60) {
224          if (PinNucleus > 0 && NinNucleus > 0) {
225            p2->SetDefinition( aDeuteron );
226            PinNucleus--;
227            NinNucleus--;
228          } else if (NinNucleus > 0) {
229            p2->SetDefinition( aNeutron );
230            NinNucleus--;
231          } else if (PinNucleus > 0) {
232            p2->SetDefinition( aProton );
233            PinNucleus--;
234          } else {
235            delete p2;
236            break;
237          }
238        } else if (ran < 0.90) {
239          if (PinNucleus > 0 && NinNucleus > 1) {
240            p2->SetDefinition( aTriton );
241            PinNucleus--;
242            NinNucleus -= 2;
243          } else if (PinNucleus > 0 && NinNucleus > 0) {
244            p2->SetDefinition( aDeuteron );
245            PinNucleus--;
246            NinNucleus--;
247          } else if (NinNucleus > 0) {
248            p2->SetDefinition( aNeutron );
249            NinNucleus--;
250          } else if (PinNucleus > 0) {
251            p2->SetDefinition( aProton );
252            PinNucleus--;
253          } else {
254            delete p2;
255            break;
256          }
257        } else {
258          if (PinNucleus > 1 && NinNucleus > 1) {
259            p2->SetDefinition( anAlpha );
260            PinNucleus -= 2;
261            NinNucleus -= 2;
262          } else if (PinNucleus > 0 && NinNucleus > 1) {
263            p2->SetDefinition( aTriton );
264            PinNucleus--;
265            NinNucleus -= 2;
266          } else if (PinNucleus > 0 && NinNucleus > 0) {
267            p2->SetDefinition( aDeuteron );
268            PinNucleus--;
269            NinNucleus--;
270          } else if (NinNucleus > 0) {
271            p2->SetDefinition( aNeutron );
272            NinNucleus--;
273          } else if (PinNucleus > 0) {
274            p2->SetDefinition( aProton );
275            PinNucleus--;
276          } else {
277            delete p2;
278            break;
279          }
280        }
281
282        vec.SetElement( vecLen, p2 );
283        vec[vecLen]->SetNewlyAdded( true );
284        vec[vecLen]->SetKineticEnergy( kinetic*GeV );
285        kinCreated+=kinetic;
286        pp = vec[vecLen]->GetTotalMomentum()/MeV;
287        vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
288                                    pp*sint*std::cos(phi)*MeV,
289                                    pp*cost*MeV );
290      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
291      }
292    } // if (ndta > 0)
293
294  //    G4double delta = epnb+edta - kinCreated;
295}
296
297 
298G4double G4RPGReaction::GenerateNBodyEvent(
299  const G4double totalEnergy,                // MeV
300  const G4bool constantCrossSection,
301  G4FastVector<G4ReactionProduct,256> &vec,
302  G4int &vecLen )
303{
304    G4int i;
305    const G4double expxu =  82.;           // upper bound for arg. of exp
306    const G4double expxl = -expxu;         // lower bound for arg. of exp
307    if( vecLen < 2 )
308    {
309      G4cerr << "*** Error in G4RPGReaction::GenerateNBodyEvent" << G4endl;
310      G4cerr << "    number of particles < 2" << G4endl;
311      G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
312      return -1.0;
313    }
314    G4double mass[18];    // mass of each particle
315    G4double energy[18];  // total energy of each particle
316    G4double pcm[3][18];           // pcm is an array with 3 rows and vecLen columns
317   
318    G4double totalMass = 0.0;
319    G4double extraMass = 0;
320    G4double sm[18];
321   
322    for( i=0; i<vecLen; ++i )
323    {
324      mass[i] = vec[i]->GetMass()/GeV;
325      if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
326      vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
327      pcm[0][i] = 0.0;      // x-momentum of i-th particle
328      pcm[1][i] = 0.0;      // y-momentum of i-th particle
329      pcm[2][i] = 0.0;      // z-momentum of i-th particle
330      energy[i] = mass[i];  // total energy of i-th particle
331      totalMass += mass[i];
332      sm[i] = totalMass;
333    }
334    G4double totalE = totalEnergy/GeV;
335    if( totalMass > totalE )
336    {
337      //G4cerr << "*** Error in G4RPGReaction::GenerateNBodyEvent" << G4endl;
338      //G4cerr << "    total mass (" << totalMass*GeV << "MeV) > total energy ("
339      //     << totalEnergy << "MeV)" << G4endl;
340      totalE = totalMass;
341      return -1.0;
342    }
343    G4double kineticEnergy = totalE - totalMass;
344    G4double emm[18];
345    //G4double *emm = new G4double [vecLen];
346    emm[0] = mass[0];
347    emm[vecLen-1] = totalE;
348    if( vecLen > 2 )          // the random numbers are sorted
349    {
350      G4double ran[18];
351      for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
352      for( i=0; i<vecLen-2; ++i )
353      {
354        for( G4int j=vecLen-2; j>i; --j )
355        {
356          if( ran[i] > ran[j] )
357          {
358            G4double temp = ran[i];
359            ran[i] = ran[j];
360            ran[j] = temp;
361          }
362        }
363      }
364      for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
365    }
366    //   Weight is the sum of logarithms of terms instead of the product of terms
367    G4bool lzero = true;   
368    G4double wtmax = 0.0;
369    if( constantCrossSection )     // this is KGENEV=1 in PHASP
370    {
371      G4double emmax = kineticEnergy + mass[0];
372      G4double emmin = 0.0;
373      for( i=1; i<vecLen; ++i )
374      {
375        emmin += mass[i-1];
376        emmax += mass[i];
377        G4double wtfc = 0.0;
378        if( emmax*emmax > 0.0 )
379        {
380          G4double arg = emmax*emmax
381            + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
382            - 2.0*(emmin*emmin+mass[i]*mass[i]);
383          if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
384        }
385        if( wtfc == 0.0 )
386        {
387          lzero = false;
388          break;
389        }
390        wtmax += std::log( wtfc );
391      }
392      if( lzero )
393        wtmax = -wtmax;
394      else
395        wtmax = expxu;
396    }
397    else
398    {
399      //   ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
400      const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
401                                 256.3704, 268.4705, 240.9780, 189.2637,
402                                 132.1308,  83.0202,  47.4210,  24.8295,
403                                 12.0006,   5.3858,   2.2560,   0.8859 };
404      wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
405    }
406    lzero = true;
407    G4double pd[50];
408    //G4double *pd = new G4double [vecLen-1];
409    for( i=0; i<vecLen-1; ++i )
410    {
411      pd[i] = 0.0;
412      if( emm[i+1]*emm[i+1] > 0.0 )
413      {
414        G4double arg = emm[i+1]*emm[i+1]
415          + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
416            /(emm[i+1]*emm[i+1])
417          - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
418        if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
419      }
420      if( pd[i] <= 0.0 )    //  changed from  ==  on 02 April 98
421        lzero = false;
422      else
423        wtmax += std::log( pd[i] );
424    }
425    G4double weight = 0.0;           // weight is returned by GenerateNBodyEvent
426    if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
427   
428    G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
429    pcm[0][0] = 0.0;
430    pcm[1][0] = pd[0];
431    pcm[2][0] = 0.0;
432    for( i=1; i<vecLen; ++i )
433    {
434      pcm[0][i] = 0.0;
435      pcm[1][i] = -pd[i-1];
436      pcm[2][i] = 0.0;
437      bang = twopi*G4UniformRand();
438      cb = std::cos(bang);
439      sb = std::sin(bang);
440      c = 2.0*G4UniformRand() - 1.0;
441      s = std::sqrt( std::fabs( 1.0-c*c ) );
442      if( i < vecLen-1 )
443      {
444        esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
445        beta = pd[i]/esys;
446        gama = esys/emm[i];
447        for( G4int j=0; j<=i; ++j )
448        {
449          s0 = pcm[0][j];
450          s1 = pcm[1][j];
451          s2 = pcm[2][j];
452          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
453          a = s0*c - s1*s;                           //  rotation
454          pcm[1][j] = s0*s + s1*c;
455          b = pcm[2][j];
456          pcm[0][j] = a*cb - b*sb;
457          pcm[2][j] = a*sb + b*cb;
458          pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
459        }
460      }
461      else
462      {
463        for( G4int j=0; j<=i; ++j )
464        {
465          s0 = pcm[0][j];
466          s1 = pcm[1][j];
467          s2 = pcm[2][j];
468          energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
469          a = s0*c - s1*s;                           //  rotation
470          pcm[1][j] = s0*s + s1*c;
471          b = pcm[2][j];
472          pcm[0][j] = a*cb - b*sb;
473          pcm[2][j] = a*sb + b*cb;
474        }
475      }
476    }
477    for( i=0; i<vecLen; ++i )
478    {
479      vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
480      vec[i]->SetTotalEnergy( energy[i]*GeV );
481    }
482
483      // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
484    return weight;
485  }
486 
487G4double G4RPGReaction::normal()
488{
489  G4double ran = -6.0;
490  for( G4int i=0; i<12; ++i )ran += G4UniformRand();
491  return ran;
492}
493
494 
495/*
496G4int G4RPGReaction::Poisson( G4double x )
497{
498  G4int iran;
499  G4double ran;
500     
501  if( x > 9.9 )    // use normal distribution with sigma^2 = <x>
502    iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
503  else {
504    G4int mm = G4int(5.0*x);
505    if( mm <= 0 )   // for very small x try iran=1,2,3
506    {
507      G4double p1 = x*std::exp(-x);
508      G4double p2 = x*p1/2.0;
509      G4double p3 = x*p2/3.0;
510      ran = G4UniformRand();
511      if( ran < p3 )
512        iran = 3;
513      else if( ran < p2 )  // this is original Geisha, it should be ran < p2+p3
514        iran = 2;
515      else if( ran < p1 )  // should be ran < p1+p2+p3
516        iran = 1;
517      else
518        iran = 0;
519    }
520    else
521    {
522      iran = 0;
523      G4double r = std::exp(-x);
524      ran = G4UniformRand();
525      if( ran > r )
526      {
527        G4double rrr;
528        G4double rr = r;
529        for( G4int i=1; i<=mm; ++i )
530        {
531          iran++;
532          if( i > 5 )   // Stirling's formula for large numbers
533            rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
534          else
535            rrr = std::pow(x,i)/Factorial(i);
536          rr += r*rrr;
537          if( ran <= rr )break;
538        }
539      }
540    }
541  }
542  return iran;
543}
544*/
545 
546// G4int G4RPGReaction::Factorial( G4int n )
547// {
548//  G4int m = std::min(n,10);
549//  G4int result = 1;
550//  if( m <= 1 )return result;
551//  for( G4int i=2; i<=m; ++i )result *= i;
552//  return result;
553// }
554
555 
556 void G4RPGReaction::Defs1(
557   const G4ReactionProduct &modifiedOriginal,
558   G4ReactionProduct &currentParticle,
559   G4ReactionProduct &targetParticle,
560   G4FastVector<G4ReactionProduct,256> &vec,
561   G4int &vecLen )
562  {
563    // Rotate final state particle momenta by initial particle direction
564
565    const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
566    const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
567    const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
568    const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
569    if( pjx*pjx+pjy*pjy > 0.0 )
570    {
571      G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
572      cost = pjz/p;
573      sint = std::sqrt(std::abs((1.0-cost)*(1.0+cost)));
574      if( pjy < 0.0 )
575        ph = 3*halfpi;
576      else
577        ph = halfpi;
578      if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
579      cosp = std::cos(ph);
580      sinp = std::sin(ph);
581      pix = currentParticle.GetMomentum().x()/MeV;
582      piy = currentParticle.GetMomentum().y()/MeV;
583      piz = currentParticle.GetMomentum().z()/MeV;
584      currentParticle.SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
585                                  (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
586                                  (-sint*pix + cost*piz)*MeV);
587      pix = targetParticle.GetMomentum().x()/MeV;
588      piy = targetParticle.GetMomentum().y()/MeV;
589      piz = targetParticle.GetMomentum().z()/MeV;
590      targetParticle.SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
591                                 (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
592                                 (-sint*pix + cost*piz)*MeV);
593      for( G4int i=0; i<vecLen; ++i )
594      {
595        pix = vec[i]->GetMomentum().x()/MeV;
596        piy = vec[i]->GetMomentum().y()/MeV;
597        piz = vec[i]->GetMomentum().z()/MeV;
598        vec[i]->SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
599                            (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
600                            (-sint*pix + cost*piz)*MeV);
601      }
602    }
603    else
604    {
605      if( pjz < 0.0 )
606      {
607        currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
608        targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
609        for( G4int i=0; i<vecLen; ++i )
610          vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
611      }
612    }
613  }
614 
615 void G4RPGReaction::Rotate(
616  const G4double numberofFinalStateNucleons,
617  const G4ThreeVector &temp,
618  const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
619  const G4HadProjectile *originalIncident, // original incident particle
620  const G4Nucleus &targetNucleus,
621  G4ReactionProduct &currentParticle,
622  G4ReactionProduct &targetParticle,
623  G4FastVector<G4ReactionProduct,256> &vec,
624  G4int &vecLen )
625  {
626    // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
627    //
628    //   Rotate in direction of z-axis, this does disturb in some way our
629    //    inclusive distributions, but it is necessary for momentum conservation
630    //
631    const G4double atomicWeight = targetNucleus.GetN();
632    const G4double logWeight = std::log(atomicWeight);
633   
634    G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
635    G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
636    G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
637   
638    G4int i;
639    G4ThreeVector pseudoParticle[4];
640    for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
641    pseudoParticle[0] = currentParticle.GetMomentum()
642                        + targetParticle.GetMomentum();
643    for( i=0; i<vecLen; ++i )
644      pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
645    //
646    //  Some smearing in transverse direction from Fermi motion
647    //
648    G4float pp, pp1;
649    G4double alekw, p;
650    G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
651   
652    r1 = twopi*G4UniformRand();
653    r2 = G4UniformRand();
654    a1 = std::sqrt(-2.0*std::log(r2));
655    ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
656    ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
657    G4ThreeVector fermi(ran1, ran2, 0);
658
659    pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
660    pseudoParticle[2] = temp; // original in cms system
661    pseudoParticle[3] = pseudoParticle[0];
662   
663    pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
664    G4double rotation = 2.*pi*G4UniformRand();
665    pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
666    pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);   
667    for(G4int ii=1; ii<=3; ii++)
668    { 
669      p = pseudoParticle[ii].mag();
670      if( p == 0.0 )
671        pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
672      else
673        pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
674    }
675   
676    pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
677    pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
678    pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
679    currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
680   
681    pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
682    pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
683    pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
684    targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
685   
686    for( i=0; i<vecLen; ++i )
687    {
688      pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
689      pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
690      pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
691      vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
692    }
693    //
694    //  Rotate in direction of primary particle, subtract binding energies
695    //   and make some further corrections if required
696    //
697    Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
698    G4double ekin;
699    G4double dekin = 0.0;
700    G4double ek1 = 0.0;
701    G4int npions = 0;
702    if( atomicWeight >= 1.5 )            // self-absorption in heavy molecules
703    {
704      // corrections for single particle spectra (shower particles)
705      //
706      const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
707      const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
708      alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
709      exh = 1.0;
710      if( alekw > alem[0] )   //   get energy bin
711      {
712        exh = val0[6];
713        for( G4int j=1; j<7; ++j )
714        {
715          if( alekw < alem[j] ) // use linear interpolation/extrapolation
716          {
717            G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
718            exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
719            break;
720          }
721        }
722        exh = 1.0 - exh;
723      }
724      const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
725      ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
726      ekin = std::max( 1.0e-6, ekin );
727      xxh = 1.0;
728      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
729           modifiedOriginal.GetDefinition() == aPiMinus) &&
730           currentParticle.GetDefinition() == aPiZero &&
731           G4UniformRand() <= logWeight) xxh = exh;
732      dekin += ekin*(1.0-xxh);
733      ekin *= xxh;
734      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
735        ++npions;
736        ek1 += ekin;
737      }
738      currentParticle.SetKineticEnergy( ekin*GeV );
739      pp = currentParticle.GetTotalMomentum()/MeV;
740      pp1 = currentParticle.GetMomentum().mag()/MeV;
741      if( pp1 < 0.001*MeV )
742      {
743        G4double costheta = 2.*G4UniformRand() - 1.;
744        G4double sintheta = std::sqrt(1. - costheta*costheta);
745        G4double phi = twopi*G4UniformRand();
746        currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
747                                     pp*sintheta*std::sin(phi)*MeV,
748                                     pp*costheta*MeV ) ;
749      }
750      else
751        currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
752      ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
753      ekin = std::max( 1.0e-6, ekin );
754      xxh = 1.0;
755      if( (modifiedOriginal.GetDefinition() == aPiPlus ||
756           modifiedOriginal.GetDefinition() == aPiMinus) &&
757           targetParticle.GetDefinition() == aPiZero &&
758           G4UniformRand() < logWeight) xxh = exh;
759      dekin += ekin*(1.0-xxh);
760      ekin *= xxh;
761      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
762        ++npions;
763        ek1 += ekin;
764      }
765      targetParticle.SetKineticEnergy( ekin*GeV );
766      pp = targetParticle.GetTotalMomentum()/MeV;
767      pp1 = targetParticle.GetMomentum().mag()/MeV;
768      if( pp1 < 0.001*MeV )
769      {
770        G4double costheta = 2.*G4UniformRand() - 1.;
771        G4double sintheta = std::sqrt(1. - costheta*costheta);
772        G4double phi = twopi*G4UniformRand();
773        targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
774                                    pp*sintheta*std::sin(phi)*MeV,
775                                    pp*costheta*MeV ) ;
776      }
777      else
778        targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
779      for( i=0; i<vecLen; ++i )
780      {
781        ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
782        ekin = std::max( 1.0e-6, ekin );
783        xxh = 1.0;
784        if( (modifiedOriginal.GetDefinition() == aPiPlus ||
785             modifiedOriginal.GetDefinition() == aPiMinus) &&
786             vec[i]->GetDefinition() == aPiZero &&
787             G4UniformRand() < logWeight) xxh = exh;
788        dekin += ekin*(1.0-xxh);
789        ekin *= xxh;
790        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
791          ++npions;
792          ek1 += ekin;
793        }
794        vec[i]->SetKineticEnergy( ekin*GeV );
795        pp = vec[i]->GetTotalMomentum()/MeV;
796        pp1 = vec[i]->GetMomentum().mag()/MeV;
797        if( pp1 < 0.001*MeV )
798        {
799          G4double costheta = 2.*G4UniformRand() - 1.;
800          G4double sintheta = std::sqrt(1. - costheta*costheta);
801          G4double phi = twopi*G4UniformRand();
802          vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
803                               pp*sintheta*std::sin(phi)*MeV,
804                               pp*costheta*MeV ) ;
805        }
806        else
807          vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
808      }
809    }
810    if( (ek1 != 0.0) && (npions > 0) )
811    {
812      dekin = 1.0 + dekin/ek1;
813      //
814      //  first do the incident particle
815      //
816      if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") 
817      {
818        currentParticle.SetKineticEnergy(
819         std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
820        pp = currentParticle.GetTotalMomentum()/MeV;
821        pp1 = currentParticle.GetMomentum().mag()/MeV;
822        if( pp1 < 0.001 )
823        {
824          G4double costheta = 2.*G4UniformRand() - 1.;
825          G4double sintheta = std::sqrt(1. - costheta*costheta);
826          G4double phi = twopi*G4UniformRand();
827          currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
828                                       pp*sintheta*std::sin(phi)*MeV,
829                                       pp*costheta*MeV ) ;
830        } else {
831          currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
832        }
833      }
834
835      if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") 
836      {
837        targetParticle.SetKineticEnergy(
838         std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
839        pp = targetParticle.GetTotalMomentum()/MeV;
840        pp1 = targetParticle.GetMomentum().mag()/MeV;
841        if( pp1 < 0.001 )
842        {
843          G4double costheta = 2.*G4UniformRand() - 1.;
844          G4double sintheta = std::sqrt(1. - costheta*costheta);
845          G4double phi = twopi*G4UniformRand();
846          targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
847                                      pp*sintheta*std::sin(phi)*MeV,
848                                      pp*costheta*MeV ) ;
849        } else {
850          targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
851        }
852      }
853
854      for( i=0; i<vecLen; ++i )
855      {
856        if (vec[i]->GetDefinition()->GetParticleSubType() == "pi")
857        {
858          vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
859          pp = vec[i]->GetTotalMomentum()/MeV;
860          pp1 = vec[i]->GetMomentum().mag()/MeV;
861          if( pp1 < 0.001 )
862          {
863            G4double costheta = 2.*G4UniformRand() - 1.;
864            G4double sintheta = std::sqrt(1. - costheta*costheta);
865            G4double phi = twopi*G4UniformRand();
866            vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
867                                 pp*sintheta*std::sin(phi)*MeV,
868                                 pp*costheta*MeV ) ;
869          } else {
870            vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
871          }
872        }
873      } // for i
874    } // if (ek1 != 0)
875  }
876 
877  std::pair<G4int, G4int> G4RPGReaction::GetFinalStateNucleons(
878   const G4DynamicParticle* originalTarget,
879   const G4FastVector<G4ReactionProduct,256>& vec, 
880   const G4int& vecLen)
881  {
882    // Get number of protons and neutrons removed from the target nucleus
883 
884    G4int protonsRemoved = 0;
885    G4int neutronsRemoved = 0;
886    if (originalTarget->GetDefinition()->GetParticleName() == "proton")
887      protonsRemoved++;
888    else
889      neutronsRemoved++;
890 
891    G4String secName;
892    for (G4int i = 0; i < vecLen; i++) {
893      secName = vec[i]->GetDefinition()->GetParticleName();
894      if (secName == "proton") {
895        protonsRemoved++;
896      } else if (secName == "neutron") {
897        neutronsRemoved++;
898      } else if (secName == "anti_proton") {
899        protonsRemoved--;
900      } else if (secName == "anti_neutron") {
901        neutronsRemoved--;
902      }
903    }
904
905    return std::pair<G4int, G4int>(protonsRemoved, neutronsRemoved);
906  }
907
908
909 G4ThreeVector G4RPGReaction::Isotropic(const G4double& pp)
910  {
911    G4double costheta = 2.*G4UniformRand() - 1.;
912    G4double sintheta = std::sqrt(1. - costheta*costheta);
913    G4double phi = twopi*G4UniformRand();
914    return G4ThreeVector(pp*sintheta*std::cos(phi),
915                         pp*sintheta*std::sin(phi),
916                         pp*costheta);
917  }
918
919
920 void G4RPGReaction::MomentumCheck(
921   const G4ReactionProduct &modifiedOriginal,
922   G4ReactionProduct &currentParticle,
923   G4ReactionProduct &targetParticle,
924   G4FastVector<G4ReactionProduct,256> &vec,
925   G4int &vecLen )
926  {
927    const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
928    G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
929    G4double pMass;
930    if( testMomentum >= pOriginal )
931    {
932      pMass = currentParticle.GetMass()/MeV;
933      currentParticle.SetTotalEnergy(
934       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
935      currentParticle.SetMomentum(
936       currentParticle.GetMomentum() * (pOriginal/testMomentum) );
937    }
938    testMomentum = targetParticle.GetMomentum().mag()/MeV;
939    if( testMomentum >= pOriginal )
940    {
941      pMass = targetParticle.GetMass()/MeV;
942      targetParticle.SetTotalEnergy(
943       std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
944      targetParticle.SetMomentum(
945       targetParticle.GetMomentum() * (pOriginal/testMomentum) );
946    }
947    for( G4int i=0; i<vecLen; ++i )
948    {
949      testMomentum = vec[i]->GetMomentum().mag()/MeV;
950      if( testMomentum >= pOriginal )
951      {
952        pMass = vec[i]->GetMass()/MeV;
953        vec[i]->SetTotalEnergy(
954         std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
955        vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
956      }
957    }
958  }
959
960 void G4RPGReaction::NuclearReaction(
961   G4FastVector<G4ReactionProduct,4> &vec,
962   G4int &vecLen,
963   const G4HadProjectile *originalIncident,
964   const G4Nucleus &targetNucleus,
965   const G4double theAtomicMass,
966   const G4double *mass )
967  {
968    // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
969    //
970    // Nuclear reaction kinematics at low energies
971    //
972    G4ParticleDefinition *aGamma = G4Gamma::Gamma();
973    G4ParticleDefinition *aProton = G4Proton::Proton();
974    G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
975    G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
976    G4ParticleDefinition *aTriton = G4Triton::Triton();
977    G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
978   
979    const G4double aProtonMass = aProton->GetPDGMass()/MeV;
980    const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
981    const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
982    const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
983    const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
984
985    G4ReactionProduct currentParticle;
986    currentParticle = *originalIncident;
987    //
988    // Set beam particle, take kinetic energy of current particle as the
989    // fundamental quantity.  Due to the difficult kinematic, all masses have to
990    // be assigned the best measured values
991    //
992    G4double p = currentParticle.GetTotalMomentum();
993    G4double pp = currentParticle.GetMomentum().mag();
994    if( pp <= 0.001*MeV )
995    {
996      G4double phinve = twopi*G4UniformRand();
997      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
998      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
999                                   p*std::sin(rthnve)*std::sin(phinve),
1000                                   p*std::cos(rthnve) );
1001    }
1002    else
1003      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
1004    //
1005    // calculate Q-value of reactions
1006    //
1007    G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
1008    G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
1009    G4double qv = currentKinetic + theAtomicMass + currentMass;
1010   
1011    G4double qval[9];
1012    qval[0] = qv - mass[0];
1013    qval[1] = qv - mass[1] - aNeutronMass;
1014    qval[2] = qv - mass[2] - aProtonMass;
1015    qval[3] = qv - mass[3] - aDeuteronMass;
1016    qval[4] = qv - mass[4] - aTritonMass;
1017    qval[5] = qv - mass[5] - anAlphaMass;
1018    qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
1019    qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
1020    qval[8] = qv - mass[8] - aProtonMass  - aProtonMass;
1021   
1022    if( currentParticle.GetDefinition() == aNeutron )
1023    {
1024      const G4double A = targetNucleus.GetN();    // atomic weight
1025      if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
1026        qval[0] = 0.0;
1027      if( G4UniformRand() >= currentKinetic/7.9254*A )
1028        qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
1029    }
1030    else
1031      qval[0] = 0.0;
1032   
1033    G4int i;
1034    qv = 0.0;
1035    for( i=0; i<9; ++i )
1036    {
1037      if( mass[i] < 500.0*MeV )qval[i] = 0.0;
1038      if( qval[i] < 0.0 )qval[i] = 0.0;
1039      qv += qval[i];
1040    }
1041    G4double qv1 = 0.0;
1042    G4double ran = G4UniformRand();
1043    G4int index;
1044    for( index=0; index<9; ++index )
1045    {
1046      if( qval[index] > 0.0 )
1047      {
1048        qv1 += qval[index]/qv;
1049        if( ran <= qv1 )break;
1050      }
1051    }
1052    if( index == 9 )  // loop continued to the end
1053    {
1054      throw G4HadronicException(__FILE__, __LINE__,
1055           "G4RPGReaction::NuclearReaction: inelastic reaction kinematically not possible");
1056    }
1057    G4double ke = currentParticle.GetKineticEnergy()/GeV;
1058    G4int nt = 2;
1059    if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
1060   
1061    G4ReactionProduct **v = new G4ReactionProduct * [3];
1062    v[0] =  new G4ReactionProduct;
1063    v[1] =  new G4ReactionProduct;
1064    v[2] =  new G4ReactionProduct;
1065   
1066    v[0]->SetMass( mass[index]*MeV );
1067    switch( index )
1068    {
1069     case 0:
1070       v[1]->SetDefinition( aGamma );
1071       v[2]->SetDefinition( aGamma );
1072       break;
1073     case 1:
1074       v[1]->SetDefinition( aNeutron );
1075       v[2]->SetDefinition( aGamma );
1076       break;
1077     case 2:
1078       v[1]->SetDefinition( aProton );
1079       v[2]->SetDefinition( aGamma );
1080       break;
1081     case 3:
1082       v[1]->SetDefinition( aDeuteron );
1083       v[2]->SetDefinition( aGamma );
1084       break;
1085     case 4:
1086       v[1]->SetDefinition( aTriton );
1087       v[2]->SetDefinition( aGamma );
1088       break;
1089     case 5:
1090       v[1]->SetDefinition( anAlpha );
1091       v[2]->SetDefinition( aGamma );
1092       break;
1093     case 6:
1094       v[1]->SetDefinition( aNeutron );
1095       v[2]->SetDefinition( aNeutron );
1096       break;
1097     case 7:
1098       v[1]->SetDefinition( aNeutron );
1099       v[2]->SetDefinition( aProton );
1100       break;
1101     case 8:
1102       v[1]->SetDefinition( aProton );
1103       v[2]->SetDefinition( aProton );
1104       break;
1105    }
1106    //
1107    // calculate centre of mass energy
1108    //
1109    G4ReactionProduct pseudo1;
1110    pseudo1.SetMass( theAtomicMass*MeV );
1111    pseudo1.SetTotalEnergy( theAtomicMass*MeV );
1112    G4ReactionProduct pseudo2 = currentParticle + pseudo1;
1113    pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
1114    //
1115    // use phase space routine in centre of mass system
1116    //
1117    G4FastVector<G4ReactionProduct,256> tempV;
1118    tempV.Initialize( nt );
1119    G4int tempLen = 0;
1120    tempV.SetElement( tempLen++, v[0] );
1121    tempV.SetElement( tempLen++, v[1] );
1122    if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
1123    G4bool constantCrossSection = true;
1124    GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
1125    v[0]->Lorentz( *v[0], pseudo2 );
1126    v[1]->Lorentz( *v[1], pseudo2 );
1127    if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
1128   
1129    G4bool particleIsDefined = false;
1130    if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
1131    {
1132      v[0]->SetDefinition( aProton );
1133      particleIsDefined = true;
1134    }
1135    else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
1136    {
1137      v[0]->SetDefinition( aNeutron );
1138      particleIsDefined = true;
1139    }
1140    else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
1141    {
1142      v[0]->SetDefinition( aDeuteron );
1143      particleIsDefined = true;
1144    }
1145    else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
1146    {
1147      v[0]->SetDefinition( aTriton );
1148      particleIsDefined = true;
1149    }
1150    else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
1151    {
1152      v[0]->SetDefinition( anAlpha );
1153      particleIsDefined = true;
1154    }
1155    currentParticle.SetKineticEnergy(
1156     std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
1157    p = currentParticle.GetTotalMomentum();
1158    pp = currentParticle.GetMomentum().mag();
1159    if( pp <= 0.001*MeV )
1160    {
1161      G4double phinve = twopi*G4UniformRand();
1162      G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
1163      currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1164                                   p*std::sin(rthnve)*std::sin(phinve),
1165                                   p*std::cos(rthnve) );
1166    }
1167    else
1168      currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
1169   
1170    if( particleIsDefined )
1171    {
1172      v[0]->SetKineticEnergy(
1173       std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
1174      p = v[0]->GetTotalMomentum();
1175      pp = v[0]->GetMomentum().mag();
1176      if( pp <= 0.001*MeV )
1177      {
1178        G4double phinve = twopi*G4UniformRand();
1179        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1180        v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1181                          p*std::sin(rthnve)*std::sin(phinve),
1182                          p*std::cos(rthnve) );
1183      }
1184      else
1185        v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
1186    }
1187    if( (v[1]->GetDefinition() == aDeuteron) ||
1188        (v[1]->GetDefinition() == aTriton)   ||
1189        (v[1]->GetDefinition() == anAlpha) ) 
1190      v[1]->SetKineticEnergy(
1191       std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
1192    else
1193      v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
1194   
1195    p = v[1]->GetTotalMomentum();
1196    pp = v[1]->GetMomentum().mag();
1197    if( pp <= 0.001*MeV )
1198    {
1199      G4double phinve = twopi*G4UniformRand();
1200      G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1201      v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1202                        p*std::sin(rthnve)*std::sin(phinve),
1203                        p*std::cos(rthnve) );
1204    }
1205    else
1206      v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
1207   
1208    if( nt == 3 )
1209    {
1210      if( (v[2]->GetDefinition() == aDeuteron) ||
1211          (v[2]->GetDefinition() == aTriton)   ||
1212          (v[2]->GetDefinition() == anAlpha) ) 
1213        v[2]->SetKineticEnergy(
1214         std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
1215      else
1216        v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
1217     
1218      p = v[2]->GetTotalMomentum();
1219      pp = v[2]->GetMomentum().mag();
1220      if( pp <= 0.001*MeV )
1221      {
1222        G4double phinve = twopi*G4UniformRand();
1223        G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1224        v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1225                          p*std::sin(rthnve)*std::sin(phinve),
1226                          p*std::cos(rthnve) );
1227      }
1228      else
1229        v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
1230    }
1231    G4int del;
1232    for(del=0; del<vecLen; del++) delete vec[del];
1233    vecLen = 0;
1234    if( particleIsDefined )
1235    {
1236      vec.SetElement( vecLen++, v[0] );
1237    }
1238    else
1239    {
1240      delete v[0];
1241    }
1242    vec.SetElement( vecLen++, v[1] );
1243    if( nt == 3 )
1244    {
1245      vec.SetElement( vecLen++, v[2] );
1246    }
1247    else
1248    {
1249      delete v[2];
1250    }
1251    delete [] v;
1252    return;
1253  }
1254 
1255 /* end of file */
1256 
Note: See TracBrowser for help on using the repository browser.