Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/lepto_nuclear/src/G4NeutrinoNucleusModel.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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: G4NeutrinoNucleusModel.cc 91806 2015-08-06 12:20:45Z gcosmo $
 27 //
 28 // Geant4 Header : G4NeutrinoNucleusModel
 29 //
 30 // Author : V.Grichine 12.2.19
 31 //  
 32 
 33 #include "G4NeutrinoNucleusModel.hh"
 34 
 35 #include "G4SystemOfUnits.hh"
 36 #include "G4ParticleTable.hh"
 37 #include "G4ParticleDefinition.hh"
 38 #include "G4IonTable.hh"
 39 #include "Randomize.hh"
 40 #include "G4RandomDirection.hh"
 41 
 42 //#include "G4Integrator.hh"
 43 #include "G4DataVector.hh"
 44 #include "G4PhysicsTable.hh"
 45 
 46 #include "G4CascadeInterface.hh"
 47 // #include "G4BinaryCascade.hh"
 48 #include "G4TheoFSGenerator.hh"
 49 #include "G4GeneratorPrecompoundInterface.hh"
 50 #include "G4ExcitationHandler.hh"
 51 #include "G4PreCompoundModel.hh"
 52 #include "G4LundStringFragmentation.hh"
 53 #include "G4ExcitedStringDecay.hh"
 54 #include "G4FTFModel.hh"
 55 // #include "G4BinaryCascade.hh"
 56 #include "G4HadFinalState.hh"
 57 #include "G4HadSecondary.hh"
 58 #include "G4HadronicInteractionRegistry.hh"
 59 // #include "G4INCLXXInterface.hh"
 60 #include "G4KineticTrack.hh"
 61 #include "G4DecayKineticTracks.hh"
 62 #include "G4KineticTrackVector.hh"
 63 #include "G4Fragment.hh"
 64 #include "G4ReactionProductVector.hh"
 65 
 66 // #include "G4QGSModel.hh"
 67 // #include "G4QGSMFragmentation.hh"
 68 // #include "G4QGSParticipants.hh"
 69 
 70 #include "G4MuonMinus.hh"
 71 #include "G4MuonPlus.hh"
 72 #include "G4Nucleus.hh"
 73 #include "G4LorentzVector.hh"
 74 #include "G4PhysicsModelCatalog.hh"
 75 
 76 using namespace std;
 77 using namespace CLHEP;
 78 
 79 const G4int G4NeutrinoNucleusModel::fResNumber = 6;
 80 
 81 const G4double G4NeutrinoNucleusModel::fResMass[6] = // [fResNumber] = 
 82   {2190., 1920., 1700., 1600., 1440., 1232. };
 83 
 84 const G4int G4NeutrinoNucleusModel::fClustNumber = 4;
 85 
 86 const G4double G4NeutrinoNucleusModel::fMesMass[4] = {1260., 980., 770., 139.57};
 87 const G4int    G4NeutrinoNucleusModel::fMesPDG[4]  = {20213, 9000211, 213, 211};
 88 
 89 // const G4double G4NeutrinoNucleusModel::fBarMass[4] = {1905., 1600., 1232., 939.57};
 90 // const G4int    G4NeutrinoNucleusModel::fBarPDG[4]  = {2226, 32224, 2224, 2212};
 91 
 92 const G4double G4NeutrinoNucleusModel::fBarMass[4] = {1700., 1600., 1232., 939.57};
 93 const G4int    G4NeutrinoNucleusModel::fBarPDG[4]  = {12224, 32224, 2224, 2212};
 94 
 95 const G4double  G4NeutrinoNucleusModel::fNuMuEnergyLogVector[50] = {
 96 115.603, 133.424, 153.991, 177.729, 205.126, 236.746, 273.24, 315.361, 363.973, 420.08, 484.836, 559.573, 645.832, 
 97 745.387, 860.289, 992.903, 1145.96, 1322.61, 1526.49, 1761.8, 2033.38, 2346.83, 2708.59, 3126.12, 3608.02, 4164.19, 
 98 4806.1, 5546.97, 6402.04, 7388.91, 8527.92, 9842.5, 11359.7, 13110.8, 15131.9, 17464.5, 20156.6, 23263.8, 26849.9, 
 99 30988.8, 35765.7, 41279, 47642.2, 54986.3, 63462.4, 73245.2, 84536, 97567.2, 112607, 129966 };
100 
101 
102 G4double G4NeutrinoNucleusModel::fNuMuXarrayKR[50][51] = {{1.0}};
103 G4double G4NeutrinoNucleusModel::fNuMuXdistrKR[50][50] = {{1.0}};
104 G4double G4NeutrinoNucleusModel::fNuMuQarrayKR[50][51][51] = {{{1.0}}};
105 G4double G4NeutrinoNucleusModel::fNuMuQdistrKR[50][51][50] = {{{1.0}}};
106 
107 ///////////////////////////////////////////
108 
109 G4NeutrinoNucleusModel::G4NeutrinoNucleusModel(const G4String& name) 
110   : G4HadronicInteraction(name), fSecID(-1)
111 {
112   SetMinEnergy( 0.0*GeV );
113   SetMaxEnergy( 100.*TeV );
114   SetMinEnergy(1.e-6*eV); 
115 
116   fNbin = 50;
117   fEindex = fXindex = fQindex = 0;
118   fOnePionIndex = 58;
119   fIndex = 50;
120   fCascade = fString = fProton = f2p2h = fBreak = false;
121 
122   fNuEnergy  = fQ2  = fQtransfer = fXsample = fDp = fTr = 0.;
123   fCosTheta = fCosThetaPi = 1.;
124   fEmuPi = fW2 = fW2pi = 0.;
125 
126   fMu = 105.6583745*MeV;
127   fMpi = 139.57018*MeV;
128   fM1 = 939.5654133*MeV;  // for nu_mu -> mu-,  and n -> p
129   fM2 = 938.2720813*MeV;
130 
131   fEmu = fMu;
132   fEx = fM1;
133   fMr = 1232.*MeV;
134   fMt = fM2; // threshold for N*-diffraction
135 
136   fMinNuEnergy = GetMinNuMuEnergy();
137   
138   fLVh = G4LorentzVector(0.,0.,0.,0.);
139   fLVl = G4LorentzVector(0.,0.,0.,0.);
140   fLVt = G4LorentzVector(0.,0.,0.,0.);
141   fLVcpi = G4LorentzVector(0.,0.,0.,0.);
142 
143   fQEratioA = 0.5; // mean value around 1 GeV neutrino beams 
144 
145   theMuonMinus = G4MuonMinus::MuonMinus();
146   theMuonPlus = G4MuonPlus::MuonPlus();
147 
148   // PDG2016: sin^2 theta Weinberg
149 
150   fSin2tW = 0.23129; // 0.2312;
151 
152   fCutEnergy = 0.; // default value
153 
154 
155   /* 
156   // G4VPreCompoundModel* ptr;
157   // reuse existing pre-compound model as in binary cascade
158   
159    fPrecoInterface = new  G4GeneratorPrecompoundInterface ;  
160  
161     if( !fPreCompound )
162     {
163       G4HadronicInteraction* p =
164         G4HadronicInteractionRegistry::Instance()->FindModel("PRECO");
165       G4VPreCompoundModel* fPreCompound = static_cast<G4VPreCompoundModel*>(p);
166       
167       if(!fPreCompound)
168       {
169   fPreCompound = new G4PreCompoundModel();
170       }
171       fPrecoInterface->SetDeExcitation(fPreCompound);
172     }
173     fDeExcitation = GetDeExcitation()->GetExcitationHandler();
174   */ 
175     
176   fDeExcitation   = new G4ExcitationHandler();
177   fPreCompound    = new G4PreCompoundModel(fDeExcitation);
178   fPrecoInterface = new  G4GeneratorPrecompoundInterface ;  
179   fPrecoInterface->SetDeExcitation(fPreCompound);
180   
181   fPDGencoding = 0; // unphysical as default
182   fRecoil = nullptr;
183 
184   // Creator model ID
185   fSecID = G4PhysicsModelCatalog::GetModelID( "model_" + GetModelName() );  
186 }
187 
188 
189 G4NeutrinoNucleusModel::~G4NeutrinoNucleusModel()
190 {
191  if(fPrecoInterface) delete fPrecoInterface;
192 }
193 
194 
195 void G4NeutrinoNucleusModel::ModelDescription(std::ostream& outFile) const
196 {
197 
198     outFile << "G4NeutrinoNucleusModel is a neutrino-nucleus general\n"
199             << "model which uses the standard model \n"
200             << "transfer parameterization.  The model is fully relativistic\n";
201 
202 }
203 
204 /////////////////////////////////////////////////////////
205 
206 G4bool G4NeutrinoNucleusModel::IsApplicable(const G4HadProjectile & aPart, 
207                     G4Nucleus & )
208 {
209   G4bool result  = false;
210   G4String pName = aPart.GetDefinition()->GetParticleName();
211   G4double energy = aPart.GetTotalEnergy();
212   
213   if(  pName == "nu_mu" // || pName == "anti_nu_mu"   ) 
214         &&
215         energy > fMinNuEnergy                                )
216   {
217     result = true;
218   }
219 
220   return result;
221 }
222 
223 //////////////////////////////////////
224 
225 G4double G4NeutrinoNucleusModel::SampleXkr(G4double energy)
226 {
227   G4int i(0), nBin(50);
228   G4double xx(0.), prob = G4UniformRand();
229 
230   for( i = 0; i < nBin; ++i ) 
231   {
232     if( energy <= fNuMuEnergyLogVector[i] ) break;
233   }
234   if( i <= 0)          // E-edge
235   {
236     fEindex = 0;
237     xx = GetXkr( 0, prob);  
238   }
239   else if ( i >= nBin) 
240   {
241     fEindex = nBin-1;  
242     xx = GetXkr( nBin-1, prob); 
243   }
244   else
245   {
246     fEindex = i;
247     G4double x1 = GetXkr(i-1,prob);
248     G4double x2 = GetXkr(i,prob);
249 
250     G4double e1 = G4Log(fNuMuEnergyLogVector[i-1]);
251     G4double e2 = G4Log(fNuMuEnergyLogVector[i]);
252     G4double e  = G4Log(energy);
253 
254     if( e2 <= e1) xx = x1 + G4UniformRand()*(x2-x1);
255     else          xx = x1 + (e-e1)*(x2-x1)/(e2-e1);  // lin in energy log-scale
256   }
257   return xx;
258 }
259 
260 //////////////////////////////////////////////
261 //
262 // sample X according to prob (xmin,1) at a given energy index iEnergy
263 
264 G4double G4NeutrinoNucleusModel::GetXkr(G4int iEnergy, G4double prob)
265 {
266   G4int i(0), nBin=50; 
267   G4double xx(0.);
268 
269   for( i = 0; i < nBin; ++i ) 
270   {
271     if( prob <= fNuMuXdistrKR[iEnergy][i] ) 
272       break;
273   }
274   if(i <= 0 )  // X-edge
275   {
276     fXindex = 0;
277     xx = fNuMuXarrayKR[iEnergy][0];
278   }
279   if ( i >= nBin ) 
280   {
281     fXindex = nBin;
282     xx = fNuMuXarrayKR[iEnergy][nBin];
283   }  
284   else
285   {
286     fXindex = i;
287     G4double x1 = fNuMuXarrayKR[iEnergy][i];
288     G4double x2 = fNuMuXarrayKR[iEnergy][i+1];
289 
290     G4double p1 = 0.;
291 
292     if( i > 0 ) p1 = fNuMuXdistrKR[iEnergy][i-1];
293 
294     G4double p2 = fNuMuXdistrKR[iEnergy][i];  
295 
296     if( p2 <= p1 ) xx = x1 + G4UniformRand()*(x2-x1);
297     else           xx = x1 + (prob-p1)*(x2-x1)/(p2-p1);
298   }
299   return xx;
300 }
301 
302 //////////////////////////////////////
303 //
304 // Sample fQtransfer at a given Enu and fX
305 
306 G4double G4NeutrinoNucleusModel::SampleQkr( G4double energy, G4double xx)
307 {
308   G4int nBin(50), iE=fEindex, jX=fXindex;
309   G4double qq(0.), qq1(0.), qq2(0.);
310   G4double prob = G4UniformRand();
311 
312   // first E
313 
314   if( iE <= 0 )          
315   {
316     qq1 = GetQkr( 0, jX, prob);  
317   }
318   else if ( iE >= nBin-1) 
319   {
320     qq1 = GetQkr( nBin-1, jX, prob); 
321   }
322   else
323   {
324     G4double q1 = GetQkr(iE-1,jX, prob);
325     G4double q2 = GetQkr(iE,jX, prob);
326 
327     G4double e1 = G4Log(fNuMuEnergyLogVector[iE-1]);
328     G4double e2 = G4Log(fNuMuEnergyLogVector[iE]);
329     G4double e  = G4Log(energy);
330 
331     if( e2 <= e1) qq1 = q1 + G4UniformRand()*(q2-q1);
332     else          qq1 = q1 + (e-e1)*(q2-q1)/(e2-e1);  // lin in energy log-scale
333   }
334 
335   // then X
336 
337   if( jX <= 0 )          
338   {
339     qq2 = GetQkr( iE, 0, prob);  
340   }
341   else if ( jX >= nBin) 
342   {
343     qq2 = GetQkr( iE, nBin, prob); 
344   }
345   else
346   {
347     G4double q1 = GetQkr(iE,jX-1, prob);
348     G4double q2 = GetQkr(iE,jX, prob);
349 
350     G4double e1 = G4Log(fNuMuXarrayKR[iE][jX-1]);
351     G4double e2 = G4Log(fNuMuXarrayKR[iE][jX]);
352     G4double e  = G4Log(xx);
353 
354     if( e2 <= e1) qq2 = q1 + G4UniformRand()*(q2-q1);
355     else          qq2 = q1 + (e-e1)*(q2-q1)/(e2-e1);  // lin in energy log-scale
356   }
357   qq = 0.5*(qq1+qq2);
358 
359   return qq;
360 }
361 
362 //////////////////////////////////////////////
363 //
364 // sample Q according to prob (qmin,qmax) at a given energy index iE and X index jX
365 
366 G4double G4NeutrinoNucleusModel::GetQkr( G4int iE, G4int jX, G4double prob )
367 {
368   G4int i(0), nBin=50; 
369   G4double qq(0.);
370 
371   for( i = 0; i < nBin; ++i ) 
372   {
373     if( prob <= fNuMuQdistrKR[iE][jX][i] ) 
374       break;
375   }
376   if(i <= 0 )  // Q-edge
377   {
378     fQindex = 0;
379     qq = fNuMuQarrayKR[iE][jX][0];
380   }
381   if ( i >= nBin ) 
382   {
383     fQindex = nBin;
384     qq = fNuMuQarrayKR[iE][jX][nBin];
385   }  
386   else
387   {
388     fQindex = i;
389     G4double q1 = fNuMuQarrayKR[iE][jX][i];
390     G4double q2 = fNuMuQarrayKR[iE][jX][i+1];
391 
392     G4double p1 = 0.;
393 
394     if( i > 0 ) p1 = fNuMuQdistrKR[iE][jX][i-1];
395 
396     G4double p2 = fNuMuQdistrKR[iE][jX][i];  
397 
398     if( p2 <= p1 ) qq = q1 + G4UniformRand()*(q2-q1);
399     else           qq = q1 + (prob-p1)*(q2-q1)/(p2-p1);
400   }
401   return qq;
402 }
403 
404 
405 ///////////////////////////////////////////////////////////
406 //
407 // Final meson to theParticleChange
408 
409 void G4NeutrinoNucleusModel::FinalMeson( G4LorentzVector & lvM, G4int, G4int pdgM) // qM
410 {
411   G4int pdg = pdgM;
412   // if      ( qM ==  0 ) pdg = pdgM - 100;
413   // else if ( qM == -1 ) pdg = -pdgM;
414 
415   if( pdg == 211 || pdg == -211 || pdg == 111) // pions
416   {
417     G4ParticleDefinition* pd2 = G4ParticleTable::GetParticleTable()->FindParticle(pdg); 
418     G4DynamicParticle*    dp2 = new G4DynamicParticle( pd2, lvM);
419     theParticleChange.AddSecondary( dp2, fSecID );
420   }
421   else // meson resonances
422   {
423     G4ParticleDefinition* rePart = G4ParticleTable::GetParticleTable()->
424       FindParticle(pdg); 
425     G4KineticTrack ddkt( rePart, 0., G4ThreeVector(0.,0.,0.), lvM);
426     G4KineticTrackVector* ddktv = ddkt.Decay();
427 
428     G4DecayKineticTracks decay( ddktv );
429 
430     for( unsigned int i = 0; i < ddktv->size(); i++ ) // add products to partchange
431     {
432       G4DynamicParticle * aNew = 
433       new G4DynamicParticle( ddktv->operator[](i)->GetDefinition(),
434                              ddktv->operator[](i)->Get4Momentum());
435 
436       // G4cout<<"       "<<i<<", "<<aNew->GetDefinition()->GetParticleName()<<", "<<aNew->Get4Momentum()<<G4endl;
437 
438       theParticleChange.AddSecondary( aNew, fSecID );
439       delete ddktv->operator[](i);
440     }
441     delete ddktv;
442   }
443 }
444 
445 ////////////////////////////////////////////////////////
446 //
447 // Final barion to theParticleChange, and recoil nucleus treatment
448 
449 void G4NeutrinoNucleusModel::FinalBarion( G4LorentzVector & lvB, G4int, G4int pdgB) // qB
450 {
451   G4int A(0), Z(0), pdg = pdgB;
452   // G4bool FiNucleon(false);
453   
454   // if      ( qB ==  1 ) pdg = pdgB - 10;
455   // else if ( qB ==  0 ) pdg = pdgB - 110;
456   // else if ( qB == -1 ) pdg = pdgB - 1110;
457 
458   if( pdg == 2212 || pdg == 2112)
459   {
460     fMr = G4ParticleTable::GetParticleTable()->FindParticle(pdg)->GetPDGMass();
461     // FiNucleon = true;
462   }
463   else fMr = lvB.m();
464   
465   G4ThreeVector bst = fLVt.boostVector();
466   lvB.boost(-bst); // in fLVt rest system
467   
468   G4double eX = lvB.e();
469   G4double det(0.), det2(0.), rM(0.), mX = lvB.m();
470   G4ThreeVector dX = (lvB.vect()).unit();
471   G4double pX = sqrt(eX*eX-mX*mX);
472 
473   if( fRecoil )
474   {
475     Z  = fRecoil->GetZ_asInt();
476     A  = fRecoil->GetA_asInt();
477     rM = fRecoil->AtomicMass(A,Z); //->AtomicMass(); // 
478     rM = fLVt.m();
479   }
480   else // A=0 nu+p
481   {
482     A = 0;
483     Z = 1;
484     rM = electron_mass_c2;
485   }
486   // G4cout<<A<<", ";
487 
488   G4double sumE = eX + rM;   
489   G4double B = sumE*sumE + rM*rM - fMr*fMr - pX*pX;
490   G4double a = 4.*(sumE*sumE - pX*pX);
491   G4double b = -4.*B*pX;
492   G4double c = 4.*sumE*sumE*rM*rM - B*B;
493   det2       = b*b-4.*a*c;
494   if( det2 <= 0. ) det = 0.;
495   else             det = sqrt(det2);
496   G4double dP = 0.5*(-b - det )/a;
497 
498   fDp = dP;
499 
500   pX -= dP;
501 
502   if(pX < 0.) pX = 0.;
503 
504   // if( A == 0 ) G4cout<<pX/MeV<<", ";
505 
506   eX = sqrt( pX*pX + fMr*fMr );
507   G4LorentzVector lvN( pX*dX, eX );
508   lvN.boost(bst); // back to lab
509 
510   if( pdg == 2212 || pdg == 2112) // nucleons mX >= fMr, dP >= 0
511   {
512     G4ParticleDefinition* pd2 = G4ParticleTable::GetParticleTable()->FindParticle(pdg); 
513     G4DynamicParticle*    dp2 = new G4DynamicParticle( pd2, lvN);
514     theParticleChange.AddSecondary( dp2, fSecID );
515 
516   }
517   else // delta resonances
518   {
519     G4ParticleDefinition* rePart = G4ParticleTable::GetParticleTable()->FindParticle(pdg); 
520     G4KineticTrack ddkt( rePart, 0., G4ThreeVector( 0., 0., 0.), lvN);
521     G4KineticTrackVector* ddktv = ddkt.Decay();
522 
523     G4DecayKineticTracks decay( ddktv );
524 
525     for( unsigned int i = 0; i < ddktv->size(); i++ ) // add products to partchange
526     {
527       G4DynamicParticle * aNew = 
528       new G4DynamicParticle( ddktv->operator[](i)->GetDefinition(),
529                              ddktv->operator[](i)->Get4Momentum()  );
530 
531       // G4cout<<"       "<<i<<", "<<aNew->GetDefinition()->GetParticleName()<<", "<<aNew->Get4Momentum()<<G4endl;
532 
533       theParticleChange.AddSecondary( aNew, fSecID );
534       delete ddktv->operator[](i);
535     }
536     delete ddktv;
537   }
538   // recoil nucleus
539 
540   G4double eRecoil = sqrt( rM*rM + dP*dP );
541   fTr = eRecoil - rM;
542   G4ThreeVector vRecoil(dP*dX);
543   // dP += G4UniformRand()*10.*MeV;
544   G4LorentzVector rec4v(vRecoil, 0.);
545   rec4v.boost(bst); // back to lab
546   fLVt += rec4v;
547   const G4LorentzVector lvTarg = fLVt; // (vRecoil, eRecoil);
548 
549 
550   if( fRecoil ) // proton*?
551   {
552     G4double grM = G4NucleiProperties::GetNuclearMass(A,Z);
553     G4double exE = fLVt.m() - grM;
554     if( exE < 5.*MeV ) exE = 5.*MeV + G4UniformRand()*10.*MeV;
555     
556     const G4LorentzVector in4v( G4ThreeVector( 0., 0., 0.), grM );   
557     G4Fragment fragment( A, Z, in4v); // lvTarg );
558     fragment.SetNumberOfHoles(1);
559     fragment.SetExcEnergyAndMomentum( exE, lvTarg );
560     
561     RecoilDeexcitation(fragment);
562   }
563   else // momentum?
564   {
565     theParticleChange.SetLocalEnergyDeposit( fTr ); // eRecoil );
566   }
567 }
568 
569 
570 ///////////////////////////////////////////////////////
571 //
572 // Get final particles from excited recoil nucleus and write them to theParticleChange, delete the particle vector
573 
574 void G4NeutrinoNucleusModel::RecoilDeexcitation( G4Fragment& fragment)
575 {
576   G4ReactionProductVector* products = fPreCompound->DeExcite(fragment);
577 
578   if( products != nullptr )
579   {
580     for( auto & prod : *products ) // prod is the pointer to final hadronic particle
581     {
582       theParticleChange.AddSecondary(new G4DynamicParticle( prod->GetDefinition(),
583                                                             prod->GetTotalEnergy(),
584                                                             prod->GetMomentum() ), fSecID );
585       delete prod;
586     }
587     delete products;
588   }
589 }
590 
591 ///////////////////////////////////////////
592 //
593 // Fragmentation of lvX directly to pion and recoil nucleus (A,Z): fLVh + fLVt -> pi + A*
594 
595 void G4NeutrinoNucleusModel::CoherentPion( G4LorentzVector & lvP, G4int pdgP, G4Nucleus & targetNucleus)
596 {
597   G4int A(0), Z(0), pdg = pdgP;
598   fLVcpi = G4LorentzVector(0.,0.,0.,0.);
599 
600   G4double  rM(0.), mN(938.), det(0.), det2(0.); 
601   G4double mI(0.);
602   mN = G4ParticleTable::GetParticleTable()->FindParticle(2212)->GetPDGMass(); // *0.85; // *0.9; // 
603 
604   // mN = 1.*139.57 + G4UniformRand()*(938. - 1.*139.57);
605 
606   G4ThreeVector vN = lvP.boostVector(), bst(0.,0.,0.);
607   //  G4double gN = lvP.e()/lvP.m();
608   // G4LorentzVector  lvNu(vN*gN*mN, mN*gN);
609   G4LorentzVector  lvNu(0.,0.,0., mN);  // lvNu(bst, mN);
610   lvP.boost(-vN);   // 9-3-20
611   lvP = lvP - lvNu; // 9-3-20  already 1pi
612   lvP.boost(vN);    // 9-3-20
613   lvNu.boost(vN);    // 9-3-20
614 
615   // G4cout<<vN-lvP.boostVector()<<", ";
616 
617   Z  = targetNucleus.GetZ_asInt();
618   A  = targetNucleus.GetA_asInt();
619   rM = targetNucleus.AtomicMass(A,Z); //->AtomicMass(); // 
620 
621   // G4cout<<rM<<", ";
622   // G4cout<<A<<", ";
623   
624   if( A == 1 ) 
625   {
626     bst = vN; // lvNu.boostVector(); // 9-3-20
627     // mI = 0.; // 9-3-20
628     rM = mN;
629   }
630   else
631   {
632     G4Nucleus targ(A-1,Z);
633     mI = targ.AtomicMass(A-1,Z);
634     G4LorentzVector lvTar(0.,0.,0.,mI); 
635     lvNu = lvNu + lvTar;
636     bst = lvNu.boostVector();  
637     // bst = fLVt.boostVector();  // to recoil rest frame
638     // G4cout<<fLVt<<"     "<<bst<<G4endl;
639   }
640   lvP.boost(-bst); // 9-3-20
641   fMr = G4ParticleTable::GetParticleTable()->FindParticle(pdg)->GetPDGMass();
642   G4double eX = lvP.e();
643   G4double mX = lvP.m();
644   // G4cout<<mX-fMr<<", ";
645   G4ThreeVector dX = (lvP.vect()).unit();
646   // G4cout<<dX<<", ";
647   G4double pX = sqrt(eX*eX-mX*mX);
648   // G4cout<<pX<<", ";
649   G4double sumE = eX + rM;   
650   G4double B = sumE*sumE + rM*rM - fMr*fMr - pX*pX;
651   G4double a = 4.*(sumE*sumE - pX*pX);
652   G4double b = -4.*B*pX;
653   G4double c = 4.*sumE*sumE*rM*rM - B*B;
654   det2 = b*b-4.*a*c;
655   if(det2 > 0.) det = sqrt(det2);
656   G4double dP = 0.5*(-b - det )/a;
657 
658   // dP = FinalMomentum( mI, rM, fMr, lvP);
659   dP = FinalMomentum( rM, rM, fMr, lvP); // 9-3-20
660 
661   // G4cout<<dP<<", ";
662   pX -= dP;
663   if( pX < 0. ) pX = 0.;
664   
665   eX = sqrt( dP*dP + fMr*fMr );
666   G4LorentzVector lvN( dP*dX, eX );
667 
668   if( A >= 1 ) lvN.boost(bst); // 9-3-20 back to lab
669 
670   fLVcpi = lvN;
671 
672   G4ParticleDefinition* pd2 = G4ParticleTable::GetParticleTable()->FindParticle(pdg); 
673   G4DynamicParticle*    dp2 = new G4DynamicParticle( pd2, lvN);
674   theParticleChange.AddSecondary( dp2, fSecID ); // coherent pion
675 
676   // recoil nucleus
677 
678   G4double eRecoil = sqrt( rM*rM + pX*pX );
679   G4ThreeVector vRecoil(pX*dX);
680   G4LorentzVector lvTarg1( vRecoil, eRecoil);
681   lvTarg1.boost(bst);
682   
683   const G4LorentzVector lvTarg = lvTarg1;
684 
685   if( A > 1 ) // recoil target nucleus*
686   {
687     G4double grM = G4NucleiProperties::GetNuclearMass(A,Z);
688     G4double exE = fLVt.m() - grM;
689     
690     if( exE < 5.*MeV ) exE = 5.*MeV + G4UniformRand()*10.*MeV; // vmg???
691     
692     const G4LorentzVector in4v( G4ThreeVector( 0., 0., 0.), grM );   
693     G4Fragment fragment( A, Z, in4v); // lvTarg );
694     fragment.SetNumberOfHoles(1);
695     fragment.SetExcEnergyAndMomentum( exE, lvTarg );
696     
697     RecoilDeexcitation(fragment);
698   }
699   else // recoil target proton 
700   {
701     G4double eTkin = eRecoil - rM;
702     G4double eTh   = 0.01*MeV; // 10.*MeV;
703     
704     if( eTkin > eTh )
705     {
706       G4DynamicParticle * aSec = new G4DynamicParticle( G4Proton::Proton(), lvTarg);
707       theParticleChange.AddSecondary(aSec, fSecID);
708     }
709     else theParticleChange.SetLocalEnergyDeposit( eTkin );
710   }
711   return;
712 }
713 
714 
715 ////////////////////////////////////////////////////////////
716 //
717 // Excited barion decay to meson and barion, 
718 // mass distributions and charge exchange are free parameters 
719 
720 void G4NeutrinoNucleusModel::ClusterDecay( G4LorentzVector & lvX, G4int qX)
721 {
722   G4bool   finB = false;
723   G4int    pdgB(0), i(0), qM(0), qB(0); //   pdgM(0),
724   G4double mM(0.), mB(0.), eM(0.), eB(0.), pM(0.), pB(0.);
725   G4double mm1(0.), mm22(0.), M1(0.), M2(0.), mX(0.);
726 
727   mX = lvX.m();
728 
729   G4double mN  = G4ParticleTable::GetParticleTable()->FindParticle(2112)->GetPDGMass();
730   G4double mPi = G4ParticleTable::GetParticleTable()->FindParticle(211)->GetPDGMass();
731 
732   //  G4double deltaM =  1.*MeV; // 30.*MeV; //  10.*MeV; //  100.*MeV; // 20.*MeV; // 
733   G4double deltaMr[4] =  { 0.*MeV, 0.*MeV, 100.*MeV, 0.*MeV}; 
734 
735   G4ThreeVector   dir(0.,0.,0.);
736   G4ThreeVector   bst(0.,0.,0.);
737   G4LorentzVector lvM(0.,0.,0.,0.);
738   G4LorentzVector lvB(0.,0.,0.,0.);
739 
740   for( i = 0; i < fClustNumber; ++i) // check resonance
741   {
742     if( mX >= fBarMass[i] )
743     {
744         pdgB = fBarPDG[i];
745         // mB = G4ParticleTable::GetParticleTable()->FindParticle(pdgB)->GetPDGMass();
746         break;
747     }
748   }
749   if( i == fClustNumber || i == fClustNumber-1 ) // low mass, p || n
750   {
751     if     ( qX == 2 || qX ==  0) { pdgB = 2212; qB = 1;} // p for 2, 0
752     
753     else if( qX == 1 || qX == -1) { pdgB = 2112; qB = 0;} // n for 1, -1
754 
755     return FinalBarion( lvX, qB, pdgB);     
756   }
757   else if( mX < fBarMass[i] + deltaMr[i]  || mX < mN + mPi ) 
758   {
759     finB = true; // final barion -> out
760 
761     if     ( qX == 1  && pdgB != 2212)  pdgB = pdgB - 10;
762     else if( qX == 0  && pdgB != 2212)  pdgB = pdgB - 110;
763     else if( qX == 0  && pdgB == 2212)  pdgB = pdgB - 100;
764 
765     if( finB ) return FinalBarion( lvX, qX, pdgB ); // out
766   }
767   // no barion resonance, try 1->2 decay in COM frame
768 
769   // try meson mass
770 
771   mm1 = mPi + 1.*MeV;     // pi+
772   mm22 = mX - mN; // mX-n
773 
774   if( mm22 <= mm1 ) // out with p or n
775   {
776     if( qX == 2 || qX == 0)       { pdgB = 2212; qB = 1;} // p
777     else if( qX == 1 || qX == -1) { pdgB = 2112; qB = 0;} // n
778 
779     return FinalBarion(lvX, qB, pdgB);
780   }
781   else // try decay -> meson(cluster) + barion(cluster)
782   {
783     // G4double sigmaM = 50.*MeV; // 100.*MeV; // 200.*MeV; // 400.*MeV; // 800.*MeV; //
784     G4double rand   = G4UniformRand();
785 
786     // mM = mm1*mm22/( mm1 + rand*(mm22 - mm1) );
787     // mM = mm1*mm22/sqrt( mm1*mm1 + rand*(mm22*mm22 - mm1*mm1) );
788     // mM = -sigmaM*log( (1.- rand)*exp(-mm22/sigmaM) + rand*exp(-mm1/sigmaM) );
789     mM = mm1 + rand*(mm22-mm1);
790 
791 
792     for( i = 0; i < fClustNumber; ++i)
793     {
794       if( mM >= fMesMass[i] )
795       {
796         // pdgM = fMesPDG[i];
797         // mM = G4ParticleTable::GetParticleTable()->FindParticle(pdgM)->GetPDGMass();
798         break;
799       }
800     }
801     M1 = G4ParticleTable::GetParticleTable()->FindParticle(2112)->GetPDGMass()+2.*MeV; // n
802     M2 = mX - mM;
803 
804     if( M2 <= M1 ) // 
805     {
806       if     ( qX == 2 || qX ==  0) { pdgB = 2212; qB = 1;} // p
807       else if( qX == 1 || qX == -1) { pdgB = 2112; qB = 0;} // n
808 
809       return FinalBarion(lvX, qB, pdgB);     
810     }
811     mB = M1 + G4UniformRand()*(M2-M1);
812     // mB = -sigmaM*log( (1.- rand)*exp(-M2/sigmaM) + rand*exp(-M1/sigmaM) );
813 
814     bst = lvX.boostVector();
815 
816     // dir = G4RandomDirection(); // ???
817     // dir = G4ThreeVector(0.,0.,1.);
818     dir = bst.orthogonal().unit(); // ??
819     // G4double cost =  exp(-G4UniformRand());
820     // G4double sint = sqrt((1.-cost)*(1.+cost));
821     // G4double phi = twopi*G4UniformRand();
822     // dir = G4ThreeVector(sint*cos(phi), sint*sin(phi), cost);
823 
824     eM  = 0.5*(mX*mX + mM*mM - mB*mB)/mX;
825     pM  = sqrt(eM*eM - mM*mM);
826     lvM = G4LorentzVector( pM*dir, eM);
827     lvM.boost(bst);
828 
829     eB  = 0.5*(mX*mX + mB*mB - mM*mM)/mX;
830     pB  = sqrt(eB*eB - mB*mB);
831     lvB = G4LorentzVector(-pB*dir, eB);
832     lvB.boost(bst);
833 
834     // G4cout<<mM<<"/"<<mB<<", ";
835 
836     // charge exchange
837 
838     if     ( qX ==  2 ) { qM =  1; qB = 1;}
839     else if( qX ==  1 ) { qM =  0; qB = 1;}
840     else if( qX ==  0 ) { qM =  0; qB = 0;}
841     else if( qX == -1 ) { qM = -1; qB = 0;}
842 
843     // if     ( qM ==  0 ) pdgM =  pdgM - 100;
844     // else if( qM == -1 ) pdgM = -pdgM;
845 
846     MesonDecay( lvM, qM); // pdgM ); //
847 
848     // else              
849     ClusterDecay( lvB, qB ); // continue
850   }
851 }
852 
853 
854 ////////////////////////////////////////////////////////////
855 //
856 // Excited barion decay to meson and barion, 
857 // mass distributions and charge exchange are free parameters 
858 
859 void G4NeutrinoNucleusModel::MesonDecay( G4LorentzVector & lvX, G4int qX)
860 {
861   G4bool   finB = false;
862   G4int    pdgM(0), pdgB(0), i(0), qM(0), qB(0);
863   G4double mM(0.), mB(0.), eM(0.), eB(0.), pM(0.), pB(0.);
864   G4double mm1(0.), mm22(0.), M1(0.), M2(0.), mX(0.), Tkin(0.);
865 
866   mX = lvX.m();
867   Tkin = lvX.e() - mX;
868 
869   // if( mX < 1120*MeV && mX > 1020*MeV ) // phi(1020)->K+K-
870   if( mX < 1080*MeV && mX > 990*MeV && Tkin < 600*MeV ) // phi(1020)->K+K-
871   {
872     return  FinalMeson( lvX, qB, 333);
873   }
874   G4double mPi = G4ParticleTable::GetParticleTable()->FindParticle(211)->GetPDGMass();
875 
876   G4double deltaMr[4] =  { 0.*MeV, 0.*MeV, 100.*MeV, 0.*MeV}; 
877 
878   G4ThreeVector   dir(0.,0.,0.);
879   G4ThreeVector   bst(0.,0.,0.);
880   G4LorentzVector lvM(0.,0.,0.,0.);
881   G4LorentzVector lvB(0.,0.,0.,0.);
882 
883   for( i = 0; i < fClustNumber; ++i) // check resonance
884   {
885     if( mX >= fMesMass[i] )
886     {
887         pdgB = fMesPDG[i];
888         // mB = G4ParticleTable::GetParticleTable()->FindParticle(pdgB)->GetPDGMass();
889         break;
890     }
891   }
892   if( i == fClustNumber ) // || i == fClustNumber-1 ) // low mass, p || n
893   {
894     if     ( qX ==  1) { pdgB = 211;  qB =  1;} // pi+   
895     else if( qX == 0 ) { pdgB = 111;  qB =  0;} // pi0  
896     else if( qX == -1) { pdgB = -211; qB = -1;} // pi-
897 
898     return FinalMeson( lvX, qB, pdgB);     
899   }
900   else if( mX < fMesMass[i] + deltaMr[i] ) // || mX < mPi + mPi ) //
901   {
902     finB = true; // final barion -> out
903     pdgB = fMesPDG[i];
904     
905     // if     ( qX == 1  && pdgB != 2212)  pdgB = pdgB - 10;
906     
907     if( qX == 0 )        pdgB = pdgB - 100;
908     else if( qX == -1 )  pdgB = -pdgB;
909 
910     if( finB ) return FinalMeson( lvX, qX, pdgB ); // out
911   }
912   // no resonance, try 1->2 decay in COM frame
913 
914   // try meson
915 
916   mm1 = mPi + 1.*MeV;     // pi+
917   mm22 = mX - mPi - 1.*MeV; // mX-n
918 
919   if( mm22 <= mm1 ) // out
920   {
921     if     ( qX ==  1) { pdgB = 211; qB = 1;} // pi+   
922     else if( qX == 0 ) { pdgB = 111; qB = 0;} // pi0  
923     else if( qX == -1) { pdgB = -211; qB = -1;} // pi-
924 
925     return FinalMeson(lvX, qB, pdgB);
926   }
927   else // try decay -> pion + meson(cluster)
928   {
929     // G4double sigmaM = 50.*MeV; // 100.*MeV; // 200.*MeV; // 400.*MeV; // 800.*MeV; //
930     G4double rand   = G4UniformRand();
931 
932     if     ( qX ==  1 ) { qM =  1; qB = 0;}
933     else if( qX ==  0 ) { qM =  -1; qB = 1;} // { qM =  0; qB = 0;} //
934     else if( qX == -1 ) { qM = -1; qB = 0;}
935     /*   
936     mM = mPi;
937     if(qM == 0) mM = G4ParticleTable::GetParticleTable()->FindParticle(111)->GetPDGMass(); //pi0
938     pdgM = fMesPDG[fClustNumber-1];
939     */
940     // mm1*mm22/( mm1 + rand*(mm22 - mm1) );
941     // mM = mm1*mm22/sqrt( mm1*mm1 + rand*(mm22*mm22 - mm1*mm1) );
942     // mM = -sigmaM*log( (1.- rand)*exp(-mm22/sigmaM) + rand*exp(-mm1/sigmaM) );
943     mM = mm1 + rand*(mm22-mm1);
944     // mM = mm1 + 0.9*(mm22-mm1);
945 
946     
947     for( i = 0; i < fClustNumber; ++i)
948     {
949       if( mM >= fMesMass[i] )
950       {
951         pdgM = fMesPDG[i];
952         // mM = G4ParticleTable::GetParticleTable()->FindParticle(pdgM)->GetPDGMass();
953         break;
954       }
955     }
956     if( i == fClustNumber || i == fClustNumber-1 ) // low mass, p || n
957     {
958       if     ( qX ==  1) { pdgB = 211; qB = 1;} // pi+   
959       else if( qX == 0 ) { pdgB = 111; qB = 0;} // pi0  
960       else if( qX == -1) { pdgB = -211; qB = -1;} // pi-
961 
962       return FinalMeson( lvX, qB, pdgB);     
963     }
964     else if( mX < fMesMass[i] + deltaMr[i] ) // || mX < mPi + mPi ) //
965     {
966       finB = true; // final barion -> out
967       pdgB = fMesPDG[i];
968     
969     // if     ( qX == 1  && pdgB != 2212)  pdgB = pdgB - 10;
970     
971       if( qX == 0 )        pdgB = pdgB - 100;
972       else if( qX == -1 )  pdgB = -pdgB;
973 
974       if( finB ) return FinalMeson( lvX, qX, pdgB ); // out
975     }
976     
977     M1 = G4ParticleTable::GetParticleTable()->FindParticle(211)->GetPDGMass()+2.*MeV; // n
978     M2 = mX - mM;
979 
980     if( M2 <= M1 ) // 
981     {
982       if     ( qX ==  1) { pdgB = 211; qB = 1;} // pi+   
983       else if( qX == 0 ) { pdgB = 111; qB = 0;} // pi0  
984       else if( qX == -1) { pdgB = -211; qB = -1;} // pi-
985 
986       return FinalMeson(lvX, qB, pdgB);     
987     }
988     mB = M1 + G4UniformRand()*(M2-M1);
989     // mB = -sigmaM*log( (1.- rand)*exp(-M2/sigmaM) + rand*exp(-M1/sigmaM) );
990     // mB = M1 + 0.9*(M2-M1);
991 
992     bst = lvX.boostVector();
993 
994     // dir = G4RandomDirection();
995     dir = bst.orthogonal().unit();
996 
997     eM  = 0.5*(mX*mX + mM*mM - mB*mB)/mX;
998     pM  = sqrt(eM*eM - mM*mM);
999     lvM = G4LorentzVector( pM*dir, eM);
1000     lvM.boost(bst);
1001 
1002     eB  = 0.5*(mX*mX + mB*mB - mM*mM)/mX;
1003     pB  = sqrt(eB*eB - mB*mB);
1004     lvB = G4LorentzVector(-pB*dir, eB);
1005     lvB.boost(bst);
1006 
1007     // G4cout<<mM<<"/"<<mB<<", ";
1008 
1009     // charge exchange
1010 
1011     // if     ( qX ==  2 ) { qM =  1; qB = 1;}
1012 
1013     if     ( qM ==  0 ) pdgM =  pdgM - 100;
1014     else if( qM == -1 ) pdgM = -pdgM;
1015 
1016     MesonDecay( lvM, qM ); //
1017 
1018     MesonDecay( lvB, qB ); // continue
1019   }
1020 }
1021 
1022 ///////////////////////////////////////////////////////////////////////
1023 //
1024 // return final momentum x in the reaction lvX + mI -> mF + mP with momenta p-x, x
1025 
1026 G4double G4NeutrinoNucleusModel::FinalMomentum(G4double mI, G4double mF, G4double mP, G4LorentzVector lvX)
1027 {
1028   G4double result(0.), delta(0.);
1029   //  G4double mI2 = mI*mI;
1030   G4double mF2 = mF*mF;
1031   G4double mP2 = mP*mP;
1032   G4double eX = lvX.e();
1033   // G4double mX = lvX.m();
1034   G4double pX = lvX.vect().mag();
1035   G4double pX2 = pX*pX;
1036   G4double sI = eX + mI;
1037   G4double sI2 = sI*sI;
1038   G4double B = sI2 - mF2 -pX2 + mP2;
1039   G4double B2 = B*B;
1040   G4double a = 4.*(sI2-pX2);
1041   G4double b = -4.*B*pX;
1042   G4double c = 4.*sI2*mP2 - B2;
1043   G4double delta2 = b*b -4.*a*c;
1044 
1045   if( delta2 >= 0. ) delta = sqrt(delta2);
1046 
1047   result = 0.5*(-b-delta)/a;
1048   // result = 0.5*(-b+delta)/a;
1049 
1050   return result; 
1051 }
1052 
1053 /////////////////////////////////////////////////////////////////
1054 //
1055 //
1056 
1057 G4double G4NeutrinoNucleusModel::FermiMomentum( G4Nucleus & targetNucleus)
1058 {
1059   G4int Z  = targetNucleus.GetZ_asInt();
1060   G4int A  = targetNucleus.GetA_asInt();
1061 
1062   G4double kF(250.*MeV);
1063   G4double kp = 365.*MeV;
1064   G4double kn = 231.*MeV;
1065   G4double t1 = 0.479;
1066   G4double t2 = 0.526;
1067   G4double ZpA  = G4double(Z)/G4double(A);
1068   G4double NpA = 1. - ZpA;
1069 
1070   if      ( Z == 1  && A == 1   ) { kF = 0.;       } // hydrogen ???
1071   else if ( Z == 1  && A == 2   ) { kF = 87.*MeV;  }
1072   else if ( Z == 2  && A == 3   ) { kF = 134.*MeV; }
1073   else if ( Z == 6  && A == 12  ) { kF = 221.*MeV; }
1074   else if ( Z == 14 && A == 28  ) { kF = 239.*MeV; }
1075   else if ( Z == 26 && A == 56  ) { kF = 257.*MeV; }
1076   else if ( Z == 82 && A == 208 ) { kF = 265.*MeV; }
1077   else 
1078   {
1079     kF = kp*ZpA*( 1 - pow( G4double(A), -t1 ) ) + kn*NpA*( 1 - pow( G4double(A), -t2 ) );
1080   }
1081   return kF;  
1082 }
1083 
1084 /////////////////////////////////////////////////////////////////
1085 //
1086 // sample nucleon momentum of Fermi motion for 1p1h and 2p2h modes
1087 
1088 G4double G4NeutrinoNucleusModel::NucleonMomentum( G4Nucleus & targetNucleus)
1089 {
1090   G4int A     = targetNucleus.GetA_asInt();
1091   G4double kF = FermiMomentum( targetNucleus);
1092   G4double mom(0.), kCut = 0.5*GeV; // kCut = 1.*GeV; // kCut = 2.*GeV; // kCut = 4.*GeV; //
1093   //  G4double cof = 2./GeV;
1094   // G4double ksi = kF*kF*cof*cof/pi/pi;
1095   G4double th  = 1.; // 1. - 6.*ksi; //
1096 
1097   if( G4UniformRand() < th || A < 3 )  // 1p1h
1098   {
1099     mom = kF*pow( G4UniformRand(), 1./3.); 
1100   }
1101   else // 2p2h
1102   {
1103     mom  = kF*kCut;
1104     mom /= kCut - G4UniformRand()*(kCut - kF);
1105     f2p2h = true;
1106   }
1107   return mom;
1108 }
1109 
1110 
1111 //////////////////////////////////////////////////////
1112 //
1113 // Excitation energy according Bodek
1114 
1115 G4double G4NeutrinoNucleusModel::GetEx( G4int A, G4bool fP )
1116 {
1117   G4double eX(10.*MeV), a1(0.), a2(0.), e1(0.), e2(0.), aa = G4double(A);
1118   G4int i(0);
1119   const G4int maxBin = 12;
1120   
1121   G4double refA[maxBin] = { 2., 6., 12., 16., 27., 28., 40., 50., 56., 58., 197., 208. };
1122 
1123   G4double pEx[maxBin] = { 0., 12.2, 10.1, 10.9, 21.6, 12.4, 17.8, 17., 19., 16.8, 19.5, 14.7 };  
1124 
1125   G4double nEx[maxBin] = { 0., 12.2, 10., 10.2, 21.6, 12.4, 21.8, 17., 19., 16.8, 19.5, 16.9 };
1126 
1127   G4DataVector dE(12,0.);
1128 
1129   if(fP) for( i = 0; i < maxBin; ++i ) dE[i] = pEx[i];
1130   else                                 dE[i] = nEx[i];
1131 
1132   for( i = 0; i < maxBin; ++i )
1133   {
1134     if( aa <= refA[i] ) break;
1135   }
1136   if( i >= maxBin ) eX = dE[maxBin-1];
1137   else if( i <= 0 ) eX = dE[0];
1138   else
1139   {
1140     a1 = refA[i-1];
1141     a2 = refA[i];
1142     e1 = dE[i-1];
1143     e2 = dE[i];
1144     if (a1 == a2 || e1 == e2 ) eX = dE[i];
1145     else eX = e1 + (e2-e1)*(aa-a1)/(a2-a1);
1146   }
1147   return eX;
1148 }
1149 
1150 
1151 
1152 ///////////////////////////////////////////////////////
1153 //
1154 // Two G-function sampling for the nucleon momentum  
1155 
1156 G4double G4NeutrinoNucleusModel::GgSampleNM(G4Nucleus & nucl)
1157 {
1158   f2p2h = false;
1159   G4double /* distr(0.), tail(0.), */ shift(1.), xx(1.), mom(0.), th(0.1);
1160   G4double kF = FermiMomentum( nucl);
1161   G4double momMax = 2.*kF; //  1.*GeV; //  1.*GeV; // 
1162   G4double aa = 5.5;
1163   G4double ll = 6.0; //  6.5; //
1164 
1165   G4int A = nucl.GetA_asInt();
1166 
1167   if( A <= 12) th = 0.1;
1168   else
1169   {
1170     // th = 0.1/(1.+log(G4double(A)/12.));
1171     th = 1.2/( G4double(A) + 1.35*log(G4double(A)/12.) );
1172   }
1173   shift = 0.99; // 0.95; //
1174   xx = mom/shift/kF;
1175 
1176   G4double rr = G4UniformRand();
1177 
1178   if( rr > th )
1179   {
1180     aa = 5.5;
1181     
1182     if( A <= 12 ) ll = 6.0;
1183     else
1184     {
1185       ll = 6.0 + 1.35*log(G4double(A)/12.);
1186     }
1187     xx = RandGamma::shoot(aa,ll);
1188     shift = 0.99;
1189     mom = xx*shift*kF;
1190   }
1191   else
1192   {
1193     f2p2h = true;
1194     aa = 6.5;
1195     ll = 6.5;
1196     xx = RandGamma::shoot(aa,ll);
1197     shift = 2.5;
1198     mom = xx*shift*kF;
1199   }
1200   if( mom > momMax ) mom = G4UniformRand()*momMax;
1201   if( mom > 2.*kF  ) f2p2h = true;
1202 
1203   // mom = 0.;
1204 
1205   return mom;
1206 }
1207 
1208 
1209 ///////////////////////////////////// experimental arrays and get functions ////////////////////////////////////////
1210 //
1211 // Return index of nu/anu energy array corresponding to the neutrino energy
1212 
1213 G4int G4NeutrinoNucleusModel::GetEnergyIndex(G4double energy)
1214 {
1215   G4int i, eIndex = 0;
1216 
1217   for( i = 0; i < fIndex; i++)
1218   {
1219     if( energy <= fNuMuEnergy[i]*GeV ) 
1220     {
1221       eIndex = i;
1222       break;
1223     }
1224   }
1225   if( i >= fIndex ) eIndex = fIndex;
1226   // G4cout<<"eIndex = "<<eIndex<<G4endl;
1227   return eIndex;
1228 }
1229 
1230 /////////////////////////////////////////////////////
1231 //
1232 // nu_mu QE/Tot ratio for index-1, index linear over energy
1233 
1234 G4double G4NeutrinoNucleusModel::GetNuMuQeTotRat(G4int index, G4double energy)
1235 {
1236   G4double ratio(0.);
1237   // GetMinNuMuEnergy()
1238   if( index <= 0 || energy < fNuMuEnergy[0] ) ratio = 0.;
1239   else if (index >= fIndex) ratio = fNuMuQeTotRat[fIndex-1]*fOnePionEnergy[fIndex-1]*GeV/energy;
1240   else
1241   {
1242     G4double x1 = fNuMuEnergy[index-1]*GeV;
1243     G4double x2 = fNuMuEnergy[index]*GeV;
1244     G4double y1 = fNuMuQeTotRat[index-1];
1245     G4double y2 = fNuMuQeTotRat[index];
1246 
1247     if(x1 >= x2) return fNuMuQeTotRat[index];
1248     else
1249     {
1250       G4double angle = (y2-y1)/(x2-x1);
1251       ratio = y1 + (energy-x1)*angle;
1252     }
1253   }
1254   return ratio;
1255 }
1256 
1257 ////////////////////////////////////////////////////////
1258 
1259 const G4double G4NeutrinoNucleusModel::fNuMuEnergy[50] = 
1260 {
1261   0.112103, 0.117359, 0.123119, 0.129443, 0.136404, 
1262   0.144084, 0.152576, 0.161991, 0.172458, 0.184126, 
1263   0.197171, 0.211801, 0.228261, 0.24684, 0.267887, 
1264   0.291816, 0.319125, 0.350417, 0.386422, 0.428032, 
1265   0.47634, 0.532692, 0.598756, 0.676612, 0.768868, 
1266   0.878812, 1.01062, 1.16963, 1.36271, 1.59876, 
1267   1.88943, 2.25002, 2.70086, 3.26916, 3.99166, 
1268   4.91843, 6.11836, 7.6872, 9.75942, 12.5259, 
1269   16.2605, 21.3615, 28.4141, 38.2903, 52.3062, 
1270   72.4763, 101.93, 145.6, 211.39, 312.172 
1271 };
1272 
1273 ////////////////////////////////////////////////////////
1274 
1275 const G4double G4NeutrinoNucleusModel::fNuMuQeTotRat[50] = 
1276 {
1277   // 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 
1278   // 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 
1279   // 1., 1., 1., 0.982311, 
1280   0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98,
1281   0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98,
1282   0.97, 0.96, 0.95, 0.93,
1283   0.917794, 0.850239, 0.780412, 0.709339, 0.638134, 0.568165, 
1284   0.500236, 0.435528, 0.375015, 0.319157, 0.268463, 0.2232, 0.183284, 
1285   0.148627, 0.119008, 0.0940699, 0.0733255, 0.0563819, 0.0427312, 0.0319274, 
1286   0.0235026, 0.0170486, 0.0122149, 0.00857825, 0.00594018, 0.00405037 
1287 };
1288 
1289 /////////////////////////////////////////////////////
1290 //
1291 // Return index of one pion array corresponding to the neutrino energy
1292 
1293 G4int G4NeutrinoNucleusModel::GetOnePionIndex(G4double energy)
1294 {
1295   G4int i, eIndex = 0;
1296 
1297   for( i = 0; i < fOnePionIndex; i++)
1298   {
1299     if( energy <= fOnePionEnergy[i]*GeV ) 
1300     {
1301       eIndex = i;
1302       break;
1303     }
1304   }
1305   if( i >= fOnePionIndex ) eIndex = fOnePionIndex;
1306   // G4cout<<"eIndex = "<<eIndex<<G4endl;
1307   return eIndex;
1308 }
1309 
1310 /////////////////////////////////////////////////////
1311 //
1312 // nu_mu 1pi/Tot ratio for index-1, index linear over energy
1313 
1314 G4double G4NeutrinoNucleusModel::GetNuMuOnePionProb(G4int index, G4double energy)
1315 {
1316   G4double ratio(0.);
1317 
1318   if(       index <= 0 || energy < fOnePionEnergy[0] ) ratio = 0.;
1319   else if ( index >= fOnePionIndex )      ratio = fOnePionProb[fOnePionIndex-1]*fOnePionEnergy[fOnePionIndex-1]*GeV/energy;
1320   else
1321   {
1322     G4double x1 = fOnePionEnergy[index-1]*GeV;
1323     G4double x2 = fOnePionEnergy[index]*GeV;
1324     G4double y1 = fOnePionProb[index-1];
1325     G4double y2 = fOnePionProb[index];
1326 
1327     if( x1 >= x2) return fOnePionProb[index];
1328     else
1329     {
1330       G4double angle = (y2-y1)/(x2-x1);
1331       ratio = y1 + (energy-x1)*angle;
1332     }
1333   }
1334   return ratio;
1335 }
1336 
1337 ////////////////////////////////////////////////////////////////////////////////////////////////////
1338 
1339 const G4double G4NeutrinoNucleusModel::fOnePionEnergy[58] = 
1340 {
1341 
1342   0.275314, 0.293652, 0.31729, 0.33409, 0.351746, 0.365629, 0.380041, 0.400165, 0.437941, 0.479237, 
1343   0.504391, 0.537803, 0.588487, 0.627532, 0.686839, 0.791905, 0.878332, 0.987405, 1.08162, 1.16971, 
1344   1.2982, 1.40393, 1.49854, 1.64168, 1.7524, 1.87058, 2.02273, 2.15894, 2.3654, 2.55792, 2.73017, 
1345   3.03005, 3.40733, 3.88128, 4.53725, 5.16786, 5.73439, 6.53106, 7.43879, 8.36214, 9.39965, 10.296, 
1346   11.5735, 13.1801, 15.2052, 17.5414, 19.7178, 22.7462, 25.9026, 29.4955, 33.5867, 39.2516, 46.4716, 
1347   53.6065, 63.4668, 73.2147, 85.5593, 99.9854 
1348 };
1349 
1350 
1351 ////////////////////////////////////////////////////////////////////////////////////////////////////
1352 
1353 const G4double G4NeutrinoNucleusModel::fOnePionProb[58] = 
1354 {
1355   0.0019357, 0.0189361, 0.0378722, 0.0502758, 0.0662559, 0.0754581, 0.0865008, 0.0987275, 0.124112, 
1356   0.153787, 0.18308, 0.213996, 0.245358, 0.274425, 0.301536, 0.326612, 0.338208, 0.337806, 0.335948, 
1357   0.328092, 0.313557, 0.304965, 0.292169, 0.28481, 0.269474, 0.254138, 0.247499, 0.236249, 0.221654, 
1358   0.205492, 0.198781, 0.182216, 0.162251, 0.142878, 0.128631, 0.116001, 0.108435, 0.0974843, 0.082092, 
1359   0.0755204, 0.0703121, 0.0607066, 0.0554278, 0.0480401, 0.0427023, 0.0377123, 0.0323248, 0.0298584, 
1360   0.0244296, 0.0218526, 0.019121, 0.016477, 0.0137309, 0.0137963, 0.0110371, 0.00834028, 0.00686127, 0.00538226
1361 };
1362 
1363 //////////////////// QEratio(Z,A,Enu)
1364 
1365 G4double G4NeutrinoNucleusModel::CalculateQEratioA( G4int Z, G4int A, G4double energy, G4int nepdg)
1366 {
1367   energy /= GeV;
1368   G4double qerata(0.5), rr(0.), x1(0.), x2(0.), y1(0.), y2(0.), aa(0.);
1369   G4int i(0), N(0);
1370 
1371   if( A > Z ) N = A-Z;
1372 
1373   for( i = 0; i < 50; i++)
1374   {
1375     if( fQEnergy[i]  >= energy ) break;
1376   }
1377   if(i <= 0) return 1.;
1378   else if (i >= 49) return 0.;
1379   else
1380   {
1381     x1 = fQEnergy[i-1];
1382     x2 = fQEnergy[i];
1383 
1384     if( nepdg == 12 ||  nepdg == 14 )
1385     {
1386       if( x1 >= x2) return fNeMuQEratio[i];
1387 
1388       y1 = fNeMuQEratio[i-1];
1389       y2 = fNeMuQEratio[i];
1390     }
1391     else
1392     {
1393       if( x1 >= x2) return fANeMuQEratio[i];
1394 
1395       y1 = fANeMuQEratio[i-1];
1396       y2 = fANeMuQEratio[i];
1397     }
1398     aa = (y2-y1)/(x2-x1);
1399     rr = y1 + (energy-x1)*aa;
1400 
1401     if( nepdg == 12 ||  nepdg == 14 ) qerata = N*rr/( N*rr + A*( 1 - rr ) );
1402     else                                     qerata = Z*rr/( Z*rr + A*( 1 - rr ) );
1403   }
1404   fQEratioA = qerata;
1405 
1406   return qerata;
1407 }
1408 
1409 const G4double G4NeutrinoNucleusModel::fQEnergy[50] = 
1410 { 
1411   0.12, 0.1416, 0.167088, 0.197164, 0.232653, 0.274531, 0.323946, 0.382257, 0.451063, 0.532254, 
1412   0.62806, 0.741111, 0.874511, 1.03192, 1.21767, 1.43685, 1.69548, 2.00067, 2.36079, 2.78573, 
1413   3.28716, 3.87885, 4.57705, 5.40092, 6.37308, 7.52024, 8.87388, 10.4712, 12.356, 14.5801, 
1414   17.2045, 20.3013, 23.9555, 28.2675, 33.3557, 39.3597, 46.4444, 54.8044, 64.6692, 76.3097, 
1415   90.0454, 106.254, 125.379, 147.947, 174.578, 206.002, 243.082, 286.837, 338.468, 399.392 
1416 };
1417 
1418 const G4double G4NeutrinoNucleusModel::fANeMuQEratio[50] = 
1419 { 
1420   1, 1, 1, 1, 1, 1, 1, 0.97506, 0.920938, 0.847671, 0.762973, 0.677684, 0.597685, 
1421   0.52538, 0.461466, 0.405329, 0.356154, 0.312944, 0.274984, 0.241341, 0.211654, 0.185322, 
1422   0.161991, 0.141339, 0.123078, 0.106952, 0.0927909, 0.0803262, 0.0693698, 0.0598207, 0.0514545, 
1423   0.044193, 0.0378696, 0.0324138, 0.0276955, 0.0236343, 0.0201497, 0.0171592, 0.014602, 0.0124182, 
1424   0.0105536, 0.00896322, 0.00761004, 0.00645821, 0.00547859, 0.00464595, 0.00393928, 
1425   0.00333961, 0.00283086, 0.00239927
1426 };
1427 
1428 const G4double G4NeutrinoNucleusModel::fNeMuQEratio[50] = 
1429 {
1430   1, 1, 1, 1, 1, 1, 1, 0.977592, 0.926073, 0.858783, 0.783874, 0.706868, 0.63113, 0.558681, 
1431   0.490818, 0.428384, 0.371865, 0.321413, 0.276892, 0.237959, 0.204139, 0.1749, 0.149706, 0.128047, 
1432   0.109456, 0.093514, 0.0798548, 0.0681575, 0.0581455, 0.0495804, 0.0422578, 0.036002, 0.0306614, 
1433   0.0261061, 0.0222231, 0.0189152, 0.0160987, 0.0137011, 0.0116604, 0.00992366, 0.00844558, 0.00718766, 
1434   0.00611714, 0.00520618, 0.00443105, 0.00377158, 0.00321062, 0.0027335, 0.00232774, 0.00198258 
1435 };
1436  
1437 //
1438 //
1439 ///////////////////////////
1440