Geant4  v4-10.4-release
 모두 클래스 네임스페이스들 파일들 함수 변수 타입정의 열거형 타입 열거형 멤버 Friends 매크로 그룹들 페이지들
G4PolarizationTransition.cc
이 파일의 문서화 페이지로 가기
1 // ********************************************************************
2 // * License and Disclaimer *
3 // * *
4 // * The Geant4 software is copyright of the Copyright Holders of *
5 // * the Geant4 Collaboration. It is provided under the terms and *
6 // * conditions of the Geant4 Software License, included in the file *
7 // * LICENSE and available at http://cern.ch/geant4/license . These *
8 // * include a list of copyright holders. *
9 // * *
10 // * Neither the authors of this software system, nor their employing *
11 // * institutes,nor the agencies providing financial support for this *
12 // * work make any representation or warranty, express or implied, *
13 // * regarding this software system or assume any liability for its *
14 // * use. Please see the license in the file LICENSE and URL above *
15 // * for the full disclaimer and the limitation of liability. *
16 // * *
17 // * This code implementation is the result of the scientific and *
18 // * technical work of the GEANT4 collaboration. *
19 // * By using, copying, modifying or distributing the software (or *
20 // * any work based on the software) you agree to acknowledge its *
21 // * use in resulting scientific publications, and indicate your *
22 // * acceptance of all terms of the Geant4 Software license. *
23 // ********************************************************************
24 //
25 //
26 // -------------------------------------------------------------------
27 // GEANT4 Class file
28 //
29 // File name: G4PolarizationTransition
30 //
31 // Author: Jason Detwiler (jasondet@gmail.com)
32 //
33 // Creation date: Aug 2012
34 // -------------------------------------------------------------------
35 #include <iostream>
36 #include <vector>
37 #include "Randomize.hh"
38 
40 #include "G4Clebsch.hh"
41 #include "G4PolynomialPDF.hh"
42 #include "G4Fragment.hh"
43 #include "G4NuclearPolarization.hh"
44 #include "G4SystemOfUnits.hh"
45 #include "G4Exp.hh"
46 
47 using namespace std;
48 
50  : fVerbose(0), fTwoJ1(0), fTwoJ2(0), fLbar(1), fL(0), fDelta(0), kEps(1.e-15),
51  kPolyPDF(0, nullptr, -1, 1)
52 {}
53 
55 {}
56 
58  G4int twoJ2, G4int twoJ1) const
59 {
60  G4double fCoeff = G4Clebsch::Wigner3J(2*LL, 2, 2*Lprime, -2, 2*K, 0);
61  if(fCoeff == 0) return 0;
62  fCoeff *= G4Clebsch::Wigner6J(2*LL, 2*Lprime, 2*K, twoJ1, twoJ1, twoJ2);
63  if(fCoeff == 0) return 0;
64  if(((twoJ1+twoJ2)/2 - 1) %2) fCoeff = -fCoeff;
65  return fCoeff*std::sqrt(G4double((2*K+1)*(twoJ1+1)*(2*LL+1)*(2*Lprime+1)));
66 }
67 
69  G4int LL, G4int Lprime,
70  G4int twoJ2, G4int twoJ1) const
71 {
72  G4double fCoeff = G4Clebsch::Wigner3J(2*LL, 2, 2*Lprime, -2, 2*K, 0);
73  if(fCoeff == 0) return 0;
74  fCoeff *= G4Clebsch::Wigner9J(twoJ2, 2*LL, twoJ1, twoJ2, 2*Lprime, twoJ1,
75  2*K2, 2*K, 2*K1);
76  if(fCoeff == 0) return 0;
77  if((Lprime+K2+K1+1) % 2) fCoeff = -fCoeff;
78 
79  //AR-13Jun2017 : apply Jason Detwiler's conversion to double
80  // in the argument of sqrt() to avoid integer overflows.
81  return fCoeff*std::sqrt(G4double((twoJ1+1)*(twoJ2+1)*(2*LL+1))
82  *G4double((2*Lprime+1)*(2*K+1)*(2*K1+1)*(2*K2+1)));
83 }
84 
86 {
87  double transFCoeff = FCoefficient(K, fLbar, fLbar, fTwoJ2, fTwoJ1);
88  if(fDelta == 0) return transFCoeff;
89  transFCoeff += 2.*fDelta*FCoefficient(K, fLbar, fL, fTwoJ2, fTwoJ1);
90  transFCoeff += fDelta*fDelta*FCoefficient(K, fL, fL, fTwoJ2, fTwoJ1);
91  return transFCoeff;
92 }
93 
95  G4int K1) const
96 {
97  double transF3Coeff = F3Coefficient(K, K2, K1, fLbar, fLbar, fTwoJ2, fTwoJ1);
98  if(fDelta == 0) return transF3Coeff;
99  transF3Coeff += 2.*fDelta*F3Coefficient(K, K2, K1, fLbar, fL, fTwoJ2, fTwoJ1);
100  transF3Coeff += fDelta*fDelta*F3Coefficient(K, K2, K1, fL, fL, fTwoJ2, fTwoJ1);
101  return transF3Coeff;
102 }
103 
105 {
106  size_t length = pol.size();
107  // Isotropic case
108  if(length <= 1) return G4UniformRand()*2.-1.;
109 
110  // kappa > 0 terms integrate out to zero over phi: 0->2pi, so just need (k,0)
111  // terms to generate cos theta distribution
112  vector<G4double> polyPDFCoeffs(length, 0.0);
113  for(size_t k = 0; k < length; k += 2) {
114  if ((pol[k]).size() > 0 ) {
115  if(std::abs(((pol)[k])[0].imag()) > kEps && fVerbose > 0) {
116  G4cout << "G4PolarizationTransition::GenerateGammaCosTheta WARNING: \n"
117  << " fPolarization["
118  << k << "][0] has imag component: = "
119  << ((pol)[k])[0].real() << " + "
120  << ((pol)[k])[0].imag() << "*i" << G4endl;
121  }
122  G4double a_k = std::sqrt((G4double)(2*k+1))*GammaTransFCoefficient(k)*((pol)[k])[0].real();
123  size_t nCoeff = fgLegendrePolys.GetNCoefficients(k);
124  for(size_t iCoeff=0; iCoeff < nCoeff; ++iCoeff) {
125  polyPDFCoeffs[iCoeff] += a_k*fgLegendrePolys.GetCoefficient(iCoeff, k);
126  }
127  } else {
128  G4cout << "G4PolarizationTransition::GenerateGammaCosTheta: WARNING: \n"
129  << " size of pol[" << k << "] = " << (pol[k]).size()
130  << " returning isotropic " << G4endl;
131  return G4UniformRand()*2.-1.;
132  }
133  }
134  if(polyPDFCoeffs[polyPDFCoeffs.size()-1] == 0 && fVerbose > 0) {
135  G4cout << "G4PolarizationTransition::GenerateGammaCosTheta: WARNING: "
136  << "got zero highest-order coefficient." << G4endl;
137  DumpTransitionData(pol);
138  }
139  kPolyPDF.SetCoefficients(polyPDFCoeffs);
140  return kPolyPDF.GetRandomX();
141 }
142 
144  const POLAR& pol)
145 {
146  size_t length = pol.size();
147  // Isotropic case
148  G4bool phiIsIsotropic = true;
149  for(size_t i=0; i<length; ++i) {
150  if(((pol)[i]).size() > 1) {
151  phiIsIsotropic = false;
152  break;
153  }
154  }
155  if(phiIsIsotropic) { return G4UniformRand()*CLHEP::twopi; }
156 
157  // map<G4int, map<G4int, G4double> > cache;
158  map<G4int, map<G4int, G4double> >* cachePtr = nullptr;
159  // if(length > 10) cachePtr = &cache;
160 
161  // Otherwise, P(phi) can be written as a sum of cos(kappa phi + phi_kappa).
162  // Calculate the amplitude and phase for each term
163  std::vector<G4double> amp(length, 0.0);
164  std::vector<G4double> phase(length, 0.0);
165  for(size_t kappa = 0; kappa < length; ++kappa) {
166  G4complex cAmpSum(0.,0.);
167  for(size_t k = kappa + (kappa % 2); k < length; k += 2) {
168  size_t kmax = (pol[k]).size();
169  if(kmax > 0) {
170  if(kappa >= kmax || std::abs(((pol)[k])[kappa]) < kEps) { continue; }
171  G4double tmpAmp = GammaTransFCoefficient(k);
172  if(tmpAmp == 0) { continue; }
173  tmpAmp *= std::sqrt((G4double)(2*k+1))
174  * fgLegendrePolys.EvalAssocLegendrePoly(k, kappa, cosTheta, cachePtr);
175  if(kappa > 0) tmpAmp *= 2.*G4Exp(0.5*(LnFactorial(k-kappa) - LnFactorial(k+kappa)));
176  cAmpSum += ((pol)[k])[kappa]*tmpAmp;
177  } else {
178  if(fVerbose > 0) {
179  G4cout << "G4PolarizationTransition::GenerateGammaPhi: WARNING: \n"
180  << " size of pol[" << k << "] = " << (pol[k]).size()
181  << " returning isotropic " << G4endl;
182  }
183  return G4UniformRand()*CLHEP::twopi;
184  }
185  }
186  if(kappa == 0 && std::abs(cAmpSum.imag()) > kEps && fVerbose > 0) {
187  G4cout << "G4PolarizationTransition::GenerateGammaPhi: WARNING: \n"
188  << " Got complex amp for kappa = 0! A = " << cAmpSum.real()
189  << " + " << cAmpSum.imag() << "*i" << G4endl;
190  }
191  amp[kappa] = std::abs(cAmpSum);
192  phase[kappa] = arg(cAmpSum);
193  }
194 
195  // Normalize PDF and calc max (note: it's not the true max, but the max
196  // assuming that all of the phases line up at a max)
197  G4double pdfMax = 0.;
198  for(size_t kappa = 0; kappa < length; ++kappa) { pdfMax += amp[kappa]; }
199  if(pdfMax < kEps && fVerbose > 0) {
200  G4cout << "G4PolarizationTransition::GenerateGammaPhi: WARNING "
201  << "got pdfMax = 0 for \n";
202  DumpTransitionData(pol);
203  G4cout << "I suspect a non-allowed transition! Returning isotropic phi..."
204  << G4endl;
205  return G4UniformRand()*CLHEP::twopi;
206  }
207 
208  // Finally, throw phi until it falls in the pdf
209  for(size_t i=0; i<100; ++i) {
211  G4double prob = G4UniformRand()*pdfMax;
212  G4double pdfSum = amp[0];
213  for(size_t kappa = 1; kappa < length; ++kappa) {
214  pdfSum += amp[kappa]*std::cos(phi*kappa + phase[kappa]);
215  }
216  if(pdfSum > pdfMax && fVerbose > 0) {
217  G4cout << "G4PolarizationTransition::GenerateGammaPhi: WARNING: \n"
218  << "got pdfSum (" << pdfSum << ") > pdfMax ("
219  << pdfMax << ") at phi = " << phi << G4endl;
220  }
221  if(prob <= pdfSum) { return phi; }
222  }
223  if(fVerbose > 0) {
224  G4cout << "G4PolarizationTransition::GenerateGammaPhi: WARNING: \n"
225  << "no phi generated in 1000 throws! Returning isotropic phi..." << G4endl;
226  }
227  return G4UniformRand()*CLHEP::twopi;
228 }
229 
231  G4NuclearPolarization* nucpol,
232  G4int twoJ1, G4int twoJ2,
233  G4int L0, G4int Lp, G4double mpRatio,
234  G4double& cosTheta, G4double& phi)
235 {
236  if(nucpol == nullptr) {
237  if(fVerbose > 0) {
238  G4cout << "G4PolarizationTransition::SampleGammaTransition ERROR: "
239  << "cannot update NULL nuclear polarization" << G4endl;
240  }
241  return;
242  }
243  fTwoJ1 = twoJ1; // add abs to remove negative J
244  fTwoJ2 = twoJ2;
245  fLbar = L0;
246  fL = Lp;
247  fDelta = mpRatio;
248  if(fVerbose > 1) {
249  G4cout << "G4PolarizationTransition: 2J1= " << fTwoJ1 << " 2J2= " << fTwoJ2
250  << " Lbar= " << fLbar << " delta= " << fDelta << " Lp= " << fL << G4endl;
251  G4cout << *nucpol << G4endl;
252  }
253 
254  if(fTwoJ1 == 0) {
255  nucpol->Unpolarize();
256  cosTheta = 2*G4UniformRand() - 1.0;
257  phi = CLHEP::twopi*G4UniformRand();
258  return;
259  }
260 
261  const POLAR& pol = nucpol->GetPolarization();
262 
263  cosTheta = GenerateGammaCosTheta(pol);
264  if(fVerbose > 1) {
265  G4cout << "G4PolarizationTransition::SampleGammaTransition: cosTheta= "
266  << cosTheta << G4endl;
267  }
268  phi = GenerateGammaPhi(cosTheta, pol);
269  if(fVerbose > 1) {
270  G4cout << "G4PolarizationTransition::SampleGammaTransition: phi= "
271  << phi << G4endl;
272  }
273 
274  if(fTwoJ2 == 0) {
275  nucpol->Unpolarize();
276  return;
277  }
278 
279  size_t newlength = fTwoJ2+1;
280  //POLAR newPol(newlength);
281  POLAR newPol;
282 
283  //map<G4int, map<G4int, G4double> > cache;
284  map<G4int, map<G4int, G4double> >* cachePtr = nullptr;
285  //if(newlength > 10 || pol.size() > 10) cachePtr = &cache;
286 
287  for(size_t k2=0; k2<newlength; ++k2) {
288  std::vector<G4complex> npolar;
289  npolar.resize(k2+1, 0);
290  //(newPol[k2]).assign(k2+1, 0);
291  for(size_t k1=0; k1<pol.size(); ++k1) {
292  for(size_t k=0; k<=k1+k2; k+=2) {
293  // TransF3Coefficient takes the most time. Only calculate it once per
294  // (k, k1, k2) triplet, and wait until the last possible moment to do
295  // so. Break out of the inner loops as soon as it is found to be zero.
296  G4double tF3 = 0.;
297  G4bool recalcTF3 = true;
298  for(size_t kappa2=0; kappa2<=k2; ++kappa2) {
299  G4int ll = (pol[k1]).size();
300  for(G4int kappa1 = 1 - ll; kappa1<ll; ++kappa1) {
301  if(k+k2<k1 || k+k1<k2) continue;
302  G4complex tmpAmp = (kappa1 < 0) ?
303  conj((pol[k1])[-kappa1])*(kappa1 % 2 ? -1.: 1.) : (pol[k1])[kappa1];
304  if(std::abs(tmpAmp) < kEps) continue;
305  G4int kappa = kappa1-(G4int)kappa2;
306  tmpAmp *= G4Clebsch::Wigner3J(2*k1, -2*kappa1, 2*k, 2*kappa, 2*k2, 2*kappa2);
307  if(std::abs(tmpAmp) < kEps) continue;
308  if(recalcTF3) {
309  tF3 = GammaTransF3Coefficient(k, k2, k1);
310  recalcTF3 = false;
311  }
312  if(std::abs(tF3) < kEps) break;
313  tmpAmp *= tF3;
314  if(std::abs(tmpAmp) < kEps) continue;
315  tmpAmp *= ((kappa1+(G4int)k1)%2 ? -1. : 1.)
316  * sqrt((2.*k+1.)*(2.*k1+1.)/(2.*k2+1.));
317  //AR-13Jun2017 Useful for debugging very long computations
318  //G4cout << "G4PolarizationTransition::UpdatePolarizationToFinalState : k1=" << k1
319  // << " ; k2=" << k2 << " ; kappa1=" << kappa1 << " ; kappa2=" << kappa2 << G4endl;
320  tmpAmp *= fgLegendrePolys.EvalAssocLegendrePoly(k, kappa, cosTheta, cachePtr);
321  if(kappa != 0) {
322  tmpAmp *= G4Exp(0.5*(LnFactorial(((G4int)k)-kappa)
323  - LnFactorial(((G4int)k)+kappa)));
324  tmpAmp *= polar(1., phi*kappa);
325  }
326  //(newPol[k2])[kappa2] += tmpAmp;
327  npolar[kappa2] += tmpAmp;
328  }
329  if(!recalcTF3 && std::abs(tF3) < kEps) break;
330  }
331  }
332  }
333  newPol.push_back(npolar);
334  }
335 
336  // sanity checks
337  if(0.0 == newPol[0][0] && fVerbose > 1) {
338  G4cout << "G4PolarizationTransition::SampleGammaTransition WARNING:"
339  << " P[0][0] is zero!" << G4endl;
340  G4cout << "Old pol is: " << *nucpol << G4endl;
341  DumpTransitionData(newPol);
342  G4cout << "Unpolarizing..." << G4endl;
343  nucpol->Unpolarize();
344  return;
345  }
346  if(std::abs((newPol[0])[0].imag()) > kEps && fVerbose > 1) {
347  G4cout << "G4PolarizationTransition::SampleGammaTransition WARNING: \n"
348  << " P[0][0] has a non-zero imaginary part! Unpolarizing..."
349  << G4endl;
350  nucpol->Unpolarize();
351  return;
352  }
353  if(fVerbose > 2) {
354  G4cout << "Before normalization: " << G4endl;
355  DumpTransitionData(newPol);
356  }
357  // Normalize and trim
358  size_t lastNonEmptyK2 = 0;
359  for(size_t k2=0; k2<newlength; ++k2) {
360  G4int lastNonZero = -1;
361  for(size_t kappa2=0; kappa2<(newPol[k2]).size(); ++kappa2) {
362  if(k2 == 0 && kappa2 == 0) {
363  lastNonZero = 0;
364  continue;
365  }
366  if(std::abs((newPol[k2])[kappa2]) > 0.0) {
367  lastNonZero = kappa2;
368  (newPol[k2])[kappa2] /= (newPol[0])[0];
369  }
370  }
371  while((newPol[k2]).size() != size_t (lastNonZero+1)) (newPol[k2]).pop_back();
372  if((newPol[k2]).size() > 0) lastNonEmptyK2 = k2;
373  }
374 
375  // Remove zero-value entries
376  while(newPol.size() != lastNonEmptyK2+1) { newPol.pop_back(); }
377  (newPol[0])[0] = 1.0;
378 
379  nucpol->SetPolarization(newPol);
380  if(fVerbose > 1) {
381  G4cout << "Updated polarization: " << *nucpol << G4endl;
382  }
383 }
384 
386 {
387  G4cout << "G4PolarizationTransition: ";
388  (fTwoJ1 % 2) ? G4cout << fTwoJ1 << "/2" : G4cout << fTwoJ1/2;
389  G4cout << " --(" << fLbar;
390  if(fDelta != 0) G4cout << " + " << fDelta << "*" << fL;
391  G4cout << ")--> ";
392  (fTwoJ2 % 2) ? G4cout << fTwoJ2 << "/2" : G4cout << fTwoJ2/2;
393  G4cout << ", P = [ { ";
394  for(size_t k=0; k<pol.size(); ++k) {
395  if(k>0) G4cout << " }, { ";
396  for(size_t kappa=0; kappa<(pol[k]).size(); ++kappa) {
397  if(kappa > 0) G4cout << ", ";
398  G4cout << (pol[k])[kappa].real() << " + " << (pol[k])[kappa].imag() << "*i";
399  }
400  }
401  G4cout << " } ]" << G4endl;
402 }
403 
G4double LnFactorial(int k) const
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:183
static const G4int LL[nN]
void SampleGammaTransition(G4NuclearPolarization *np, G4int twoJ1, G4int twoJ2, G4int L0, G4int Lp, G4double mpRatio, G4double &cosTheta, G4double &phi)
#define G4endl
Definition: G4ios.hh:61
G4double FCoefficient(G4int K, G4int L, G4int Lprime, G4int twoJ2, G4int twoJ1) const
G4double EvalAssocLegendrePoly(G4int l, G4int m, G4double x, std::map< G4int, std::map< G4int, G4double > > *cache=NULL)
Double_t K
static size_t GetNCoefficients(size_t order)
std::vector< std::vector< G4complex > > POLAR
std::complex< G4double > G4complex
Definition: G4Types.hh:81
double G4double
Definition: G4Types.hh:76
bool G4bool
Definition: G4Types.hh:79
#define G4UniformRand()
Definition: Randomize.hh:53
G4double GammaTransF3Coefficient(G4int K, G4int K2, G4int K1) const
G4double GenerateGammaCosTheta(const POLAR &)
static constexpr double twopi
Definition: SystemOfUnits.h:55
int G4int
Definition: G4Types.hh:78
G4double GenerateGammaPhi(G4double &cosTheta, const POLAR &)
G4double GetRandomX()
void SetCoefficients(const std::vector< G4double > &v)
G4double F3Coefficient(G4int K, G4int K2, G4int K1, G4int L, G4int Lprime, G4int twoJ2, G4int twoJ1) const
G4GLOB_DLL std::ostream G4cout
G4LegendrePolynomial fgLegendrePolys
static G4double Wigner9J(G4int twoJ1, G4int twoJ2, G4int twoJ3, G4int twoJ4, G4int twoJ5, G4int twoJ6, G4int twoJ7, G4int twoJ8, G4int twoJ9)
Definition: G4Clebsch.cc:533
static G4double Wigner3J(G4double j1, G4double j2, G4double j3, G4double m1, G4double m2, G4double m3)
Definition: G4Clebsch.cc:345
std::vector< std::vector< G4complex > > & GetPolarization()
G4double GammaTransFCoefficient(G4int K) const
void DumpTransitionData(const POLAR &pol) const
void SetPolarization(std::vector< std::vector< G4complex > > &p)
G4double GetCoefficient(size_t i, size_t order)
static G4double Wigner6J(G4int twoJ1, G4int twoJ2, G4int twoJ3, G4int twoJ4, G4int twoJ5, G4int twoJ6)
Definition: G4Clebsch.cc:432