ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4NuMuNucleusNcModel.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4NuMuNucleusNcModel.cc
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: G4NuMuNucleusNcModel.cc 91806 2015-08-06 12:20:45Z gcosmo $
27 //
28 // Geant4 Header : G4NuMuNucleusNcModel
29 //
30 // Author : V.Grichine 12.2.19
31 //
32 
33 #include "G4NuMuNucleusNcModel.hh"
34 #include "G4NeutrinoNucleusModel.hh"
35 
36 // #include "G4NuMuResQX.hh"
37 
38 #include "G4SystemOfUnits.hh"
39 #include "G4ParticleTable.hh"
40 #include "G4ParticleDefinition.hh"
41 #include "G4IonTable.hh"
42 #include "Randomize.hh"
43 #include "G4RandomDirection.hh"
44 
45 // #include "G4Integrator.hh"
46 #include "G4DataVector.hh"
47 #include "G4PhysicsTable.hh"
48 #include "G4KineticTrack.hh"
49 #include "G4DecayKineticTracks.hh"
50 #include "G4KineticTrackVector.hh"
51 #include "G4Fragment.hh"
53 
54 
55 #include "G4NeutrinoMu.hh"
56 #include "G4AntiNeutrinoMu.hh"
57 #include "G4Nucleus.hh"
58 #include "G4LorentzVector.hh"
59 
60 using namespace std;
61 using namespace CLHEP;
62 
64 
65 const G4double G4NuMuNucleusNcModel::fResMass[6] = // [fResNumber] =
66  {2190., 1920., 1700., 1600., 1440., 1232. };
67 
69 
70 const G4double G4NuMuNucleusNcModel::fMesMass[4] = {1260., 980., 770., 139.57};
71 const G4int G4NuMuNucleusNcModel::fMesPDG[4] = {20213, 9000211, 213, 211};
72 
73 // const G4double G4NuMuNucleusNcModel::fBarMass[4] = {1905., 1600., 1232., 939.57};
74 // const G4int G4NuMuNucleusNcModel::fBarPDG[4] = {2226, 32224, 2224, 2212};
75 
76 const G4double G4NuMuNucleusNcModel::fBarMass[4] = {1700., 1600., 1232., 939.57};
77 const G4int G4NuMuNucleusNcModel::fBarPDG[4] = {12224, 32224, 2224, 2212};
78 
80 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,
81 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,
82 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,
83 30988.8, 35765.7, 41279, 47642.2, 54986.3, 63462.4, 73245.2, 84536, 97567.2, 112607, 129966 };
84 
87 G4double G4NuMuNucleusNcModel::fNuMuQarrayKR[50][51][51] = {{{1.0}}};
88 G4double G4NuMuNucleusNcModel::fNuMuQdistrKR[50][51][50] = {{{1.0}}};
89 
90 #ifdef G4MULTITHREADED
91  G4Mutex G4NuMuNucleusNcModel::numuNucleusModel = G4MUTEX_INITIALIZER;
92 #endif
93 
94 
97 {
98  SetMinEnergy( 0.0*GeV );
99  SetMaxEnergy( 100.*TeV );
100  SetMinEnergy(1.e-6*eV);
101 
102  fMnumu = 0.;
103  fData = fMaster = false;
104  InitialiseModel();
105 
106 }
107 
108 
110 {}
111 
112 
113 void G4NuMuNucleusNcModel::ModelDescription(std::ostream& outFile) const
114 {
115 
116  outFile << "G4NuMuNucleusNcModel is a neutrino-nucleus (neutral current) scattering\n"
117  << "model which uses the standard model \n"
118  << "transfer parameterization. The model is fully relativistic\n";
119 
120 }
121 
123 //
124 // Read data from G4PARTICLEXSDATA (locally PARTICLEXSDATA)
125 
127 {
128  G4String pName = "nu_mu";
129 
130  G4int nSize(0), i(0), j(0), k(0);
131 
132  if(!fData)
133  {
134 #ifdef G4MULTITHREADED
135  G4MUTEXLOCK(&numuNucleusModel);
136  if(!fData)
137  {
138 #endif
139  fMaster = true;
140 #ifdef G4MULTITHREADED
141  }
142  G4MUTEXUNLOCK(&numuNucleusModel);
143 #endif
144  }
145 
146  if(fMaster)
147  {
148  char* path = getenv("G4PARTICLEXSDATA");
149  std::ostringstream ost1, ost2, ost3, ost4;
150  ost1 << path << "/" << "neutrino" << "/" << pName << "/xarraynckr";
151 
152  std::ifstream filein1( ost1.str().c_str() );
153 
154  // filein.open("$PARTICLEXSDATA/");
155 
156  filein1>>nSize;
157 
158  for( k = 0; k < fNbin; ++k )
159  {
160  for( i = 0; i <= fNbin; ++i )
161  {
162  filein1 >> fNuMuXarrayKR[k][i];
163  // G4cout<< fNuMuXarrayKR[k][i] << " ";
164  }
165  }
166  // G4cout<<G4endl<<G4endl;
167 
168  ost2 << path << "/" << "neutrino" << "/" << pName << "/xdistrnckr";
169  std::ifstream filein2( ost2.str().c_str() );
170 
171  filein2>>nSize;
172 
173  for( k = 0; k < fNbin; ++k )
174  {
175  for( i = 0; i < fNbin; ++i )
176  {
177  filein2 >> fNuMuXdistrKR[k][i];
178  // G4cout<< fNuMuXdistrKR[k][i] << " ";
179  }
180  }
181  // G4cout<<G4endl<<G4endl;
182 
183  ost3 << path << "/" << "neutrino" << "/" << pName << "/q2arraynckr";
184  std::ifstream filein3( ost3.str().c_str() );
185 
186  filein3>>nSize;
187 
188  for( k = 0; k < fNbin; ++k )
189  {
190  for( i = 0; i <= fNbin; ++i )
191  {
192  for( j = 0; j <= fNbin; ++j )
193  {
194  filein3 >> fNuMuQarrayKR[k][i][j];
195  // G4cout<< fNuMuQarrayKR[k][i][j] << " ";
196  }
197  }
198  }
199  // G4cout<<G4endl<<G4endl;
200 
201  ost4 << path << "/" << "neutrino" << "/" << pName << "/q2distrnckr";
202  std::ifstream filein4( ost4.str().c_str() );
203 
204  filein4>>nSize;
205 
206  for( k = 0; k < fNbin; ++k )
207  {
208  for( i = 0; i <= fNbin; ++i )
209  {
210  for( j = 0; j < fNbin; ++j )
211  {
212  filein4 >> fNuMuQdistrKR[k][i][j];
213  // G4cout<< fNuMuQdistrKR[k][i][j] << " ";
214  }
215  }
216  }
217  fData = true;
218  }
219 }
220 
222 
224  G4Nucleus & targetNucleus)
225 {
226  G4bool result = false;
227  G4String pName = aPart.GetDefinition()->GetParticleName();
228  G4double energy = aPart.GetTotalEnergy();
229 
230  if( pName == "nu_mu" // || pName == "anti_nu_mu" )
231  &&
232  energy > fMinNuEnergy )
233  {
234  result = true;
235  }
236  G4int Z = targetNucleus.GetZ_asInt();
237  Z *= 1;
238 
239  return result;
240 }
241 
243 //
244 //
245 
247  const G4HadProjectile& aTrack, G4Nucleus& targetNucleus)
248 {
250  fProton = f2p2h = fBreak = false;
251  const G4HadProjectile* aParticle = &aTrack;
252  G4double energy = aParticle->GetTotalEnergy();
253 
254  G4String pName = aParticle->GetDefinition()->GetParticleName();
255 
256  if( energy < fMinNuEnergy )
257  {
260  return &theParticleChange;
261  }
262  SampleLVkr( aTrack, targetNucleus);
263 
264  if( fBreak == true || fEmu < fMnumu ) // ~5*10^-6
265  {
266  // G4cout<<"ni, ";
269  return &theParticleChange;
270  }
271 
272  // LVs of initial state
273 
274  G4LorentzVector lvp1 = aParticle->Get4Momentum();
275  G4LorentzVector lvt1( 0., 0., 0., fM1 );
277 
278  // 1-pi by fQtransfer && nu-energy
279  G4LorentzVector lvpip1( 0., 0., 0., mPip );
280  G4LorentzVector lvsum, lv2, lvX;
281  G4ThreeVector eP;
282  G4double cost(1.), sint(0.), phi(0.), muMom(0.), massX2(0.);
283  G4DynamicParticle* aLept = nullptr; // lepton lv
284 
285  G4int Z = targetNucleus.GetZ_asInt();
286  G4int A = targetNucleus.GetA_asInt();
287  G4double mTarg = targetNucleus.AtomicMass(A,Z);
288  G4int pdgP(0), qB(0);
289  // G4double mSum = G4ParticleTable::GetParticleTable()->FindParticle(2212)->GetPDGMass() + mPip;
290 
291  G4int iPi = GetOnePionIndex(energy);
292  G4double p1pi = GetNuMuOnePionProb( iPi, energy);
293 
294  if( p1pi > G4UniformRand() ) // && fQtransfer < 0.95*GeV ) // mu- & coherent pion + nucleus
295  {
296  // lvsum = lvp1 + lvpip1;
297  lvsum = lvp1 + lvt1;
298  // cost = fCosThetaPi;
299  cost = fCosTheta;
300  sint = std::sqrt( (1.0 - cost)*(1.0 + cost) );
302  eP = G4ThreeVector( sint*std::cos(phi), sint*std::sin(phi), cost );
303 
304  // muMom = sqrt(fEmuPi*fEmuPi-fMnumu*fMnumu);
305  muMom = sqrt(fEmu*fEmu-fMnumu*fMnumu);
306 
307  eP *= muMom;
308 
309  // lv2 = G4LorentzVector( eP, fEmuPi );
310  lv2 = G4LorentzVector( eP, fEmu );
311  lv2 = fLVl;
312 
313  lvX = lvsum - lv2;
314  lvX = fLVh;
315  massX2 = lvX.m2();
316 
317  if ( massX2 <= 0. ) // vmg: very rarely ~ (1-4)e-6 due to big Q2/x, to be improved
318  {
321  return &theParticleChange;
322  }
323  fW2 = massX2;
324 
325  if( pName == "nu_mu" ) aLept = new G4DynamicParticle( theNuMu, lv2 );
326  else if( pName == "anti_nu_mu") aLept = new G4DynamicParticle( theANuMu, lv2 );
327  else
328  {
331  return &theParticleChange;
332  }
333 
334  pdgP = 111;
335 
336  G4double eCut = fMpi + 0.5*(fMpi*fMpi - massX2)/mTarg; // massX -> fMpi
337 
338  if ( lvX.e() > eCut ) // && sqrt( GetW2() ) < 1.4*GeV ) //
339  {
340  CoherentPion( lvX, pdgP, targetNucleus);
341  }
342  else
343  {
346  return &theParticleChange;
347  }
349 
350  return &theParticleChange;
351  }
352  else // lepton part in lab
353  {
354  lvsum = lvp1 + lvt1;
355  cost = fCosTheta;
356  sint = std::sqrt( (1.0 - cost)*(1.0 + cost) );
358  eP = G4ThreeVector( sint*std::cos(phi), sint*std::sin(phi), cost );
359 
360  muMom = sqrt(fEmu*fEmu-fMnumu*fMnumu);
361 
362  eP *= muMom;
363 
364  lv2 = G4LorentzVector( eP, fEmu );
365 
366  lvX = lvsum - lv2;
367 
368  massX2 = lvX.m2();
369 
370  if ( massX2 <= 0. ) // vmg: very rarely ~ (1-4)e-6 due to big Q2/x, to be improved
371  {
374  return &theParticleChange;
375  }
376  fW2 = massX2;
377 
378  if( pName == "nu_mu" ) aLept = new G4DynamicParticle( theNuMu, lv2 );
379  else if( pName == "anti_nu_mu") aLept = new G4DynamicParticle( theANuMu, lv2 );
380 
382  }
383 
384  // hadron part
385 
386  fRecoil = nullptr;
387  fCascade = false;
388  fString = false;
389 
390  if( A == 1 )
391  {
392  qB = 1;
393 
394  // if( G4UniformRand() > 0.1 ) // > 0.9999 ) // > 0.0001 ) //
395  {
396  ClusterDecay( lvX, qB );
397  }
398  return &theParticleChange;
399  }
400  G4Nucleus recoil;
401  G4double rM(0.), ratio = G4double(Z)/G4double(A);
402 
403  if( ratio > G4UniformRand() ) // proton is excited
404  {
405  fProton = true;
406  recoil = G4Nucleus(A-1,Z-1);
407  fRecoil = &recoil;
408  rM = recoil.AtomicMass(A-1,Z-1);
409 
412  }
413  else // excited neutron
414  {
415  fProton = false;
416  recoil = G4Nucleus(A-1,Z);
417  fRecoil = &recoil;
418  rM = recoil.AtomicMass(A-1,Z);
419 
422  }
423  G4int index = GetEnergyIndex(energy);
424  G4double qeTotRat = GetNuMuQeTotRat(index, energy);
425 
426  G4ThreeVector dX = (lvX.vect()).unit();
427  G4double eX = lvX.e(); // excited nucleon
428  G4double mX = sqrt(massX2);
429  G4double dP(0.), pX = sqrt( eX*eX - mX*mX );
430  G4double sumE = eX + rM;
431  G4double a(0.), b(0.), c(0.), B(0.);
432 
433  if( qeTotRat > G4UniformRand() || mX <= fMt ) // || eX <= 1232.*MeV) // QE
434  {
435  fString = false;
436 
437  if( fProton ) // pName == "nu_mu" )
438  {
439  fPDGencoding = 2212;
441  recoil = G4Nucleus(A-1,Z-1);
442  fRecoil = &recoil;
443  rM = recoil.AtomicMass(A-1,Z-1);
444  }
445  else // if( pName == "anti_nu_mu" )
446  {
447  fPDGencoding = 2112;
449  FindParticle(fPDGencoding)->GetPDGMass(); // 939.5654133*MeV;
450  recoil = G4Nucleus(A-1,Z);
451  fRecoil = &recoil;
452  rM = recoil.AtomicMass(A-1,Z);
453  }
454  sumE = eX + rM;
455  G4double eTh = fMr+0.5*(fMr*fMr-mX*mX)/rM;
456 
457  if(eX <= eTh) // vmg, very rarely out of kinematics
458  {
461  return &theParticleChange;
462  }
463  B = sumE*sumE + rM*rM - fMr*fMr - pX*pX;
464  a = 4.*(sumE*sumE - pX*pX);
465  b = -4.*B*pX;
466  c = 4.*sumE*sumE*rM*rM - B*B;
467  G4double det2 = b*b-4.*a*c;
468  if( det2 < 0.) det2 = 0.;
469  dP = 0.5*(-b - sqrt(det2) )/a;
470  pX -= dP;
471  eX = sqrt( pX*pX + fMr*fMr );
472  G4LorentzVector qeLV( pX*dX, eX );
473 
475  FindParticle(fPDGencoding);
476 
477  G4DynamicParticle* qeDyn = new G4DynamicParticle( qePart, qeLV);
479 
480  G4double eRecoil = sqrt(rM*rM + dP*dP);
481  G4ThreeVector vRecoil(dP*dX);
482  G4LorentzVector lvTarg(vRecoil, eRecoil);
483 
484  if( eRecoil > 100.*MeV ) // add recoil nucleus
485  {
486  G4ParticleDefinition * recoilDef = 0;
487  G4int Zr = recoil.GetZ_asInt();
488  G4int Ar = recoil.GetA_asInt();
489 
490  if ( Zr == 1 && Ar == 1 ) { recoilDef = G4Proton::Proton(); }
491  else if ( Zr == 0 && Ar == 1 ) { recoilDef = G4Neutron::Neutron(); }
492  else if ( Zr == 1 && Ar == 2 ) { recoilDef = G4Deuteron::Deuteron(); }
493  else if ( Zr == 1 && Ar == 3 ) { recoilDef = G4Triton::Triton(); }
494  else if ( Zr == 2 && Ar == 3 ) { recoilDef = G4He3::He3(); }
495  else if ( Zr == 2 && Ar == 4 ) { recoilDef = G4Alpha::Alpha(); }
496  else
497  {
498  recoilDef =
500  }
501  G4DynamicParticle * aSec = new G4DynamicParticle( recoilDef, lvTarg);
503  }
504  else if( eRecoil > 0.0 )
505  {
507  }
508  }
509  else if ( eX < 95000.*GeV ) // < 25.*GeV) // < 95.*GeV ) // < 2.5*GeV ) //cluster decay
510  {
511  if ( fProton && pName == "nu_mu" ) qB = 1;
512  else if( fProton && pName == "anti_nu_mu" ) qB = 1;
513  else if( !fProton && pName == "nu_mu" ) qB = 0;
514  else if( !fProton && pName == "anti_nu_mu" ) qB = 0;
515 
516  // if( G4UniformRand() > 0.1 )
517  {
518  ClusterDecay( lvX, qB );
519  }
520  // else
521  {
522  pdgP = 111;
523 
524  if ( fQtransfer < 0.95*GeV ) // < 0.99*GeV ) //
525  {
526  // if( lvX.m() > mSum ) CoherentPion( lvX, pdgP, targetNucleus);
527  }
528  }
529  }
530  else // string
531  {
532  return &theParticleChange;
533 
534  }
535  return &theParticleChange;
536 }
537 
538 
542 
544 //
545 // sample x, then Q2
546 
547 void G4NuMuNucleusNcModel::SampleLVkr(const G4HadProjectile & aTrack, G4Nucleus& targetNucleus)
548 {
549  fBreak = false;
550  G4int A = targetNucleus.GetA_asInt(), iTer(0), iTerMax(100);
551  G4int Z = targetNucleus.GetZ_asInt();
552  G4double e3(0.), pMu2(0.), pX2(0.), nMom(0.), rM(0.), hM(0.), tM = targetNucleus.AtomicMass(A,Z);
553  G4double cost(1.), sint(0.), phi(0.), muMom(0.);
554  G4ThreeVector eP, bst;
555  const G4HadProjectile* aParticle = &aTrack;
556  G4LorentzVector lvp1 = aParticle->Get4Momentum();
557  nMom = NucleonMomentum( targetNucleus );
558 
559  if( A == 1 || nMom == 0. ) // hydrogen, no Fermi motion ???
560  {
561  fNuEnergy = aParticle->GetTotalEnergy();
562  iTer = 0;
563 
564  do
565  {
569 
570  if( fXsample > 0. )
571  {
572  fW2 = fM1*fM1 - fQ2 + fQ2/fXsample; // sample excited hadron mass
573  fEmu = fNuEnergy - fQ2/2./fM1/fXsample;
574  }
575  else
576  {
577  fW2 = fM1*fM1;
578  fEmu = fNuEnergy;
579  }
580  e3 = fNuEnergy + fM1 - fEmu;
581 
582  // if( e3 < sqrt(fW2) ) G4cout<<"energyX = "<<e3/GeV<<", fW = "<<sqrt(fW2)/GeV<<G4endl; // vmg ~10^-5 for NC
583 
584  pMu2 = fEmu*fEmu - fMnumu*fMnumu;
585  pX2 = e3*e3 - fW2;
586 
587  fCosTheta = fNuEnergy*fNuEnergy + pMu2 - pX2;
588  fCosTheta /= 2.*fNuEnergy*sqrt(pMu2);
589  iTer++;
590  }
591  while( ( abs(fCosTheta) > 1. || fEmu < fMnumu ) && iTer < iTerMax );
592 
593  if( iTer >= iTerMax ) { fBreak = true; return; }
594 
595  if( abs(fCosTheta) > 1.) // vmg: due to big Q2/x values. To be improved ...
596  {
597  G4cout<<"H2: fCosTheta = "<<fCosTheta<<", fEmu = "<<fEmu<<G4endl;
598  // fCosTheta = -1. + 2.*G4UniformRand();
599  if(fCosTheta < -1.) fCosTheta = -1.;
600  if(fCosTheta > 1.) fCosTheta = 1.;
601  }
602  // LVs
603 
604  G4LorentzVector lvt1 = G4LorentzVector( 0., 0., 0., fM1 );
605  G4LorentzVector lvsum = lvp1 + lvt1;
606 
607  cost = fCosTheta;
608  sint = std::sqrt( (1.0 - cost)*(1.0 + cost) );
610  eP = G4ThreeVector( sint*std::cos(phi), sint*std::sin(phi), cost );
611  muMom = sqrt(fEmu*fEmu-fMnumu*fMnumu);
612  eP *= muMom;
613  fLVl = G4LorentzVector( eP, fEmu );
614 
615  fLVh = lvsum - fLVl;
616  fLVt = G4LorentzVector( 0., 0., 0., 0. ); // no recoil
617  }
618  else // Fermi motion, Q2 in nucleon rest frame
619  {
620  G4ThreeVector nMomDir = nMom*G4RandomDirection();
621 
622  if( !f2p2h ) // 1p1h
623  {
624  G4Nucleus recoil(A-1,Z);
625  rM = sqrt( recoil.AtomicMass(A-1,Z)*recoil.AtomicMass(A-1,Z) + nMom*nMom );
626  hM = tM - rM;
627 
628  fLVt = G4LorentzVector( nMomDir, sqrt( rM*rM+nMom*nMom ) );
629  fLVh = G4LorentzVector(-nMomDir, sqrt( hM*hM+nMom*nMom ) );
630  }
631  else // 2p2h
632  {
633  G4Nucleus recoil(A-2,Z-1);
634  rM = recoil.AtomicMass(A-2,Z-1)+sqrt(nMom*nMom+fM1*fM1);
635  hM = tM - rM;
636 
637  fLVt = G4LorentzVector( nMomDir, sqrt( rM*rM+nMom*nMom ) );
638  fLVh = G4LorentzVector(-nMomDir, sqrt( hM*hM+nMom*nMom ) );
639  }
640  // G4cout<<hM<<", ";
641  bst = fLVh.boostVector();
642 
643  lvp1.boost(-bst); // -> nucleon rest system, where Q2 transfer is ???
644 
645  fNuEnergy = lvp1.e();
646  iTer = 0;
647 
648  do
649  {
653 
654  if( fXsample > 0. )
655  {
656  fW2 = fM1*fM1 - fQ2 + fQ2/fXsample; // sample excited hadron mass
657  fEmu = fNuEnergy - fQ2/2./fM1/fXsample;
658  }
659  else
660  {
661  fW2 = fM1*fM1;
662  fEmu = fNuEnergy;
663  }
664 
665  // if(fEmu < 0.) G4cout<<"fEmu = "<<fEmu<<" hM = "<<hM<<G4endl;
666 
667  e3 = fNuEnergy + fM1 - fEmu;
668 
669  // if( e3 < sqrt(fW2) ) G4cout<<"energyX = "<<e3/GeV<<", fW = "<<sqrt(fW2)/GeV<<G4endl;
670 
671  pMu2 = fEmu*fEmu - fMnumu*fMnumu;
672  pX2 = e3*e3 - fW2;
673 
674  fCosTheta = fNuEnergy*fNuEnergy + pMu2 - pX2;
675  fCosTheta /= 2.*fNuEnergy*sqrt(pMu2);
676  iTer++;
677  }
678  while( ( abs(fCosTheta) > 1. || fEmu < fMnumu ) && iTer < iTerMax );
679 
680  if( iTer >= iTerMax ) { fBreak = true; return; }
681 
682  if( abs(fCosTheta) > 1.) // vmg: due to big Q2/x values. To be improved ...
683  {
684  G4cout<<"FM: fCosTheta = "<<fCosTheta<<", fEmu = "<<fEmu<<G4endl;
685  // fCosTheta = -1. + 2.*G4UniformRand();
686  if(fCosTheta < -1.) fCosTheta = -1.;
687  if(fCosTheta > 1.) fCosTheta = 1.;
688  }
689  // LVs
690  G4LorentzVector lvt1 = G4LorentzVector( 0., 0., 0., fM1 );
691  G4LorentzVector lvsum = lvp1 + lvt1;
692 
693  cost = fCosTheta;
694  sint = std::sqrt( (1.0 - cost)*(1.0 + cost) );
696  eP = G4ThreeVector( sint*std::cos(phi), sint*std::sin(phi), cost );
697  muMom = sqrt(fEmu*fEmu-fMnumu*fMnumu);
698  eP *= muMom;
699  fLVl = G4LorentzVector( eP, fEmu );
700  fLVh = lvsum - fLVl;
701  // back to lab system
702  fLVl.boost(bst);
703  fLVh.boost(bst);
704  }
705  //G4cout<<iTer<<", "<<fBreak<<"; ";
706 }
707 
709 
711 {
712  G4int i(0), nBin(50);
713  G4double xx(0.), prob = G4UniformRand();
714 
715  for( i = 0; i < nBin; ++i )
716  {
717  if( energy <= fNuMuEnergyLogVector[i] ) break;
718  }
719  if( i <= 0) // E-edge
720  {
721  fEindex = 0;
722  xx = GetXkr( 0, prob);
723  }
724  else if ( i >= nBin-1)
725  {
726  fEindex = nBin-1;
727  xx = GetXkr( nBin-1, prob);
728  }
729  else
730  {
731  fEindex = i;
732  G4double x1 = GetXkr(i-1,prob);
733  G4double x2 = GetXkr(i,prob);
734 
737  G4double e = G4Log(energy);
738 
739  if( e2 <= e1) xx = x1 + G4UniformRand()*(x2-x1);
740  else xx = x1 + (e-e1)*(x2-x1)/(e2-e1); // lin in energy log-scale
741  }
742  return xx;
743 }
744 
746 //
747 // sample X according to prob (xmin,1) at a given energy index iEnergy
748 
750 {
751  G4int i(0), nBin=50;
752  G4double xx(0.);
753 
754  for( i = 0; i < nBin; ++i )
755  {
756  if( prob <= fNuMuXdistrKR[iEnergy][i] )
757  break;
758  }
759  if(i <= 0 ) // X-edge
760  {
761  fXindex = 0;
762  xx = fNuMuXarrayKR[iEnergy][0];
763  }
764  if ( i >= nBin )
765  {
766  fXindex = nBin;
767  xx = fNuMuXarrayKR[iEnergy][nBin];
768  }
769  else
770  {
771  fXindex = i;
772  G4double x1 = fNuMuXarrayKR[iEnergy][i];
773  G4double x2 = fNuMuXarrayKR[iEnergy][i+1];
774 
775  G4double p1 = 0.;
776 
777  if( i > 0 ) p1 = fNuMuXdistrKR[iEnergy][i-1];
778 
779  G4double p2 = fNuMuXdistrKR[iEnergy][i];
780 
781  if( p2 <= p1 ) xx = x1 + G4UniformRand()*(x2-x1);
782  else xx = x1 + (prob-p1)*(x2-x1)/(p2-p1);
783  }
784  return xx;
785 }
786 
788 //
789 // Sample fQtransfer at a given Enu and fX
790 
792 {
793  G4int nBin(50), iE=fEindex, jX=fXindex;
794  G4double qq(0.), qq1(0.), qq2(0.);
795  G4double prob = G4UniformRand();
796 
797  // first E
798 
799  if( iE <= 0 )
800  {
801  qq1 = GetQkr( 0, jX, prob);
802  }
803  else if ( iE >= nBin-1)
804  {
805  qq1 = GetQkr( nBin-1, jX, prob);
806  }
807  else
808  {
809  G4double q1 = GetQkr(iE-1,jX, prob);
810  G4double q2 = GetQkr(iE,jX, prob);
811 
814  G4double e = G4Log(energy);
815 
816  if( e2 <= e1) qq1 = q1 + G4UniformRand()*(q2-q1);
817  else qq1 = q1 + (e-e1)*(q2-q1)/(e2-e1); // lin in energy log-scale
818  }
819 
820  // then X
821 
822  if( jX <= 0 )
823  {
824  qq2 = GetQkr( iE, 0, prob);
825  }
826  else if ( jX >= nBin)
827  {
828  qq2 = GetQkr( iE, nBin, prob);
829  }
830  else
831  {
832  G4double q1 = GetQkr(iE,jX-1, prob);
833  G4double q2 = GetQkr(iE,jX, prob);
834 
835  G4double e1 = G4Log(fNuMuXarrayKR[iE][jX-1]);
836  G4double e2 = G4Log(fNuMuXarrayKR[iE][jX]);
837  G4double e = G4Log(xx);
838 
839  if( e2 <= e1) qq2 = q1 + G4UniformRand()*(q2-q1);
840  else qq2 = q1 + (e-e1)*(q2-q1)/(e2-e1); // lin in energy log-scale
841  }
842  qq = 0.5*(qq1+qq2);
843 
844  return qq;
845 }
846 
848 //
849 // sample Q according to prob (qmin,qmax) at a given energy index iE and X index jX
850 
852 {
853  G4int i(0), nBin=50;
854  G4double qq(0.);
855 
856  for( i = 0; i < nBin; ++i )
857  {
858  if( prob <= fNuMuQdistrKR[iE][jX][i] )
859  break;
860  }
861  if(i <= 0 ) // Q-edge
862  {
863  fQindex = 0;
864  qq = fNuMuQarrayKR[iE][jX][0];
865  }
866  if ( i >= nBin )
867  {
868  fQindex = nBin;
869  qq = fNuMuQarrayKR[iE][jX][nBin];
870  }
871  else
872  {
873  fQindex = i;
874  G4double q1 = fNuMuQarrayKR[iE][jX][i];
875  G4double q2 = fNuMuQarrayKR[iE][jX][i+1];
876 
877  G4double p1 = 0.;
878 
879  if( i > 0 ) p1 = fNuMuQdistrKR[iE][jX][i-1];
880 
881  G4double p2 = fNuMuQdistrKR[iE][jX][i];
882 
883  if( p2 <= p1 ) qq = q1 + G4UniformRand()*(q2-q1);
884  else qq = q1 + (prob-p1)*(q2-q1)/(p2-p1);
885  }
886  return qq;
887 }
888 
889 //
890 //