Geant4  10.01
G4Clebsch.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 
28 #include "globals.hh"
29 #include "G4ios.hh"
30 #include "G4HadronicException.hh"
31 #include "G4Clebsch.hh"
32 #include "Randomize.hh"
33 #include "G4Proton.hh"
34 #include "G4HadTmpUtil.hh"
35 
37 {
38  G4int nLogs = 101;
39  logs.push_back(0.);
40  G4int i;
41  for (i=1; i<nLogs; i++)
42  {
43  G4double previousLog = logs.back();
44  G4double value = previousLog + std::log((G4double)i);
45  logs.push_back(value);
46  }
47 }
48 
49 
51 { }
52 
53 
55 {
56  return (this == (G4Clebsch *) &right);
57 }
58 
59 
61 {
62  return (this != (G4Clebsch *) &right);
63 }
64 
65 
67  G4int isoIn2, G4int iso3In2,
68  G4int isoOut1, G4int isoOut2) const
69 {
70  G4double value = 0.;
71 
72  G4int an_m = iso3In1 + iso3In2;
73 
74  G4int jMinIn = std::max(std::abs(isoIn1 - isoIn2), std::abs(an_m));
75  G4int jMaxIn = isoIn1 + isoIn2;
76 
77  G4int jMinOut = std::max(std::abs(isoOut1 - isoOut2), std::abs(an_m));
78  G4int jMaxOut = isoOut1 + isoOut2;
79 
80  G4int jMin = std::max(jMinIn,jMinOut);
81  G4int jMax = std::min(jMaxIn,jMaxOut);
82 
83  G4int j;
84  for (j=jMin; j<=jMax; j+=2)
85  {
86  value += ClebschGordan(isoIn1,iso3In1, isoIn2,iso3In2, j);
87  }
88 
89  return value;
90 }
91 
92 
94  G4int isoIn2, G4int iso3In2,
95  G4int jOut) const
96 {
97  // Calculates Clebsch-Gordan coefficient
98 
99  G4double j1 = isoIn1 / 2.0;
100  G4double j2 = isoIn2 / 2.0;
101  G4double j3 = jOut / 2.0;
102 
103  G4double m_1 = iso3In1 / 2.0;
104  G4double m_2 = iso3In2 / 2.0;
105  G4double m_3 = - (m_1 + m_2);
106 
107  G4int n = G4lrint(m_3+j1+j2+.1);
108  G4double argument = 2. * j3 + 1.;
109  if (argument < 0.)
110  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::ClebschGordan - sqrt of negative argument");
111  G4double coeff = std::sqrt(argument) / (std::pow(-1.,n));
112  G4double clebsch = coeff * Wigner3J(j1,j2,j3, m_1,m_2,m_3);
113  G4double value = clebsch * clebsch;
114 
115 // G4cout << "ClebschGordan("
116 // << isoIn1 << "," << iso3In1 << ","
117 // << isoIn2 << "," << iso3In2 << "," << jOut
118 // << ") = " << value << G4endl;
119 
120  return value;
121 }
122 
123 
125  G4double m_1, G4double m_2, G4double m_3) const
126 {
127  // Calculates Wigner 3-j symbols
128 
129  G4double value = 0.;
130 
131  G4double sigma = j1 + j2 + j3;
132  std::vector<G4double> n;
133  n.push_back(-j1 + j2 + j3); // n0
134  n.push_back(j1 - m_1); // n1
135  n.push_back(j1 + m_1); // n2
136  n.push_back(j1 - j2 + j3); // n3
137  n.push_back(j2 - m_2); // n4
138  n.push_back(j2 + m_2); // n5
139  n.push_back(j1 + j2 - j3); // n6
140  n.push_back(j3 - m_3); // n7
141  n.push_back(j3 + m_3); // n8
142 
143  // Some preliminary checks
144 
145  G4bool ok = true;
146  size_t i;
147  for(i=1; i<=3; i++)
148  {
149  G4double sum1 = n[i-1] + n[i+2] + n[i+5];
150  G4double sum2 = n[3*i-1] + n[3*i-2] + n[3*i-3];
151  if (sum1 != sigma || sum2 != sigma) ok = false;
152  G4int j;
153  for(j=1; j<=3; j++)
154  {
155  if (n[i+3*j-4] < 0.) ok = false;
156  }
157  }
158 
159  if (ok)
160  {
161  G4int iMin = 1;
162  G4int jMin = 1;
163  G4double smallest = n[0];
164 
165  // Find the smallest n
166  for (i=1; i<=3; i++)
167  {
168  G4int j;
169  for (j=1; j<=3; j++)
170  {
171  if (n[i+3*j-4] < smallest)
172  {
173  smallest = n[i+3*j-4];
174  iMin = i;
175  jMin = j;
176  }
177  }
178  }
179 
180  G4int sign = 1;
181 
182  if(iMin > 1)
183  {
184  for(G4int j=1; j<=3; ++j)
185  {
186  G4double tmp = n[j*3-3];
187  n[j*3-3] = n[iMin+j*3-4];
188  n[iMin+j*3-4] = tmp;
189  }
190  sign = (G4int) std::pow(-1.,sigma);
191  }
192 
193  if (jMin > 1)
194  {
195  for(i=1; i<=3; i++)
196  {
197  G4double tmp = n[i-1];
198  n[i-1] = n[i+jMin*3-4];
199  n[i+jMin*3-4] = tmp;
200  }
201  sign *= (G4int) std::pow(-1.,sigma);
202  }
203 
204  const std::vector<G4double>& logVector = logs;//GetLogs();
205  size_t n1 = G4lrint(n[0]);
206 
207  // Some boundary checks
208  G4int logEntries = logVector.size() - 1;
209  for (i=0; i<n.size(); i++)
210  {
211  if (n[i] < 0. || n[i] > logEntries)
212  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::Wigner3J - Outside logVector boundaries, n");
213  }
214 
215  G4double r1 = n[0];
216  G4double r2 = n[3];
217  G4double r3 = n[6];
218  G4double r4 = n[1];
219  G4double r5 = n[4];
220  G4double r6 = n[7];
221  G4double r7 = n[2];
222  G4double r8 = n[5];
223  G4double r9 = n[8];
224 
225  G4double l1 = logVector[(G4int)r1];
226  G4double l2 = logVector[(G4int)r2];
227  G4double l3 = logVector[(G4int)r3];
228  G4double l4 = logVector[(G4int)r4];
229  G4double l5 = logVector[(G4int)r5];
230  G4double l6 = logVector[(G4int)r6];
231  G4double l7 = logVector[(G4int)r7];
232  G4double l8 = logVector[(G4int)r8];
233  G4double l9 = logVector[(G4int)r9];
234 
235  G4double sigma1 = sigma + 1.;
236  if (sigma1 < 0. || sigma1 > logEntries)
237  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::Wigner3J - Outside logVector boundaries, sigma");
238 
239  G4double ls = logVector[static_cast<G4int>(sigma1+.00001)];
240  G4double hlp1 = (l2 + l3 + l4 +l7 -ls -l1 -l5 -l9 -l6 -l8) / 2.;
241  G4int expon = static_cast<G4int>(r6 + r8+.00001);
242  G4double sgn = std::pow(-1., expon);
243  G4double coeff = std::exp(hlp1) * sgn;
244 
245  G4int n61 = static_cast<G4int>(r6 - r1+.00001);
246  if (n61 < 0. || n61 > logEntries)
247  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::Wigner3J - Outside logVector boundaries, n61");
248  G4int n81 = static_cast<G4int>(r8 - r1+.00001);
249  if (n81 < 0. || n81 > logEntries)
250  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::Wigner3J - Outside logVector boundaries, n81");
251 
252  G4double hlp2 = l6 - logVector[n61] + l8 - logVector[n81];
253  G4double sum = std::exp(hlp2);
254  std::vector<G4double> S;
255  S.push_back(sum);
256  n1 = (size_t)r1;
257  for (i=1; i<=n1; i++)
258  {
259  G4double last = S.back();
260  G4double den = i * (r6 - r1 + i) * (r8 - r1 + i);
261  if (den == 0)
262  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::Wigner3J - divide by zero");
263  G4double data = -last * (r1 + 1.0 - i) * (r5 + 1.0 - i) * (r9 + 1. - i) / den;
264  S.push_back(data);
265  sum += data;
266  }
267  value = coeff * sum * sign;
268  } // endif ok
269  else
270  {
271  }
272 
273 
274 // G4cout << "Wigner3j("
275 // << j1 << "," << j2 << "," << j3 << ","
276 // << m1 << "," << m2 << "," << m3 << ") = "
277 // << value
278 // << G4endl;
279 
280  return value;
281 }
282 
283 
284 
285 std::vector<G4double> G4Clebsch::GenerateIso3(G4int isoIn1, G4int iso3In1,
286  G4int isoIn2, G4int iso3In2,
287  G4int isoA, G4int isoB) const
288 {
289  std::vector<G4double> temp;
290 
291  // ---- Special cases first ----
292 
293  // Special case, both Jin are zero
294  if (isoIn1 == 0 && isoIn2 == 0)
295  {
296  G4cout << "WARNING: G4Clebsch::GenerateIso3 - both isoIn are zero" << G4endl;
297  temp.push_back(0.);
298  temp.push_back(0.);
299  return temp;
300  }
301 
302  G4int iso3 = iso3In1 + iso3In2;
303 
304  // Special case, either Jout is zero
305  if (isoA == 0)
306  {
307  temp.push_back(0.);
308  temp.push_back(iso3);
309  return temp;
310  }
311  if (isoB == 0)
312  {
313  temp.push_back(iso3);
314  temp.push_back(0.);
315  return temp;
316  }
317 
318  // Number of possible states, in
319  G4int jMinIn = std::max(std::abs(isoIn1 - isoIn2), std::abs(iso3));
320  G4int jMaxIn = isoIn1 + isoIn2;
321 
322  // Number of possible states, out
323 
324  G4int jMinOut = 9999;
325  G4int jTmp, i, j;
326 
327  for(i=-1; i<=1; i+=2)
328  {
329  for(j=-1; j<=1; j+=2)
330  {
331  jTmp= std::abs(i*isoA + j*isoB);
332  if(jTmp < jMinOut) jMinOut = jTmp;
333  }
334  }
335  jMinOut = std::max(jMinOut, std::abs(iso3));
336  G4int jMaxOut = isoA + isoB;
337 
338  // Possible in and out common states
339  G4int jMin = std::max(jMinIn, jMinOut);
340  G4int jMax = std::min(jMaxIn, jMaxOut);
341  if (jMin > jMax)
342  {
343  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - jMin > JMax");
344  }
345 
346  // Number of possible isospins
347  G4int nJ = (jMax - jMin) / 2 + 1;
348 
349  // A few consistency checks
350 
351  if ( (isoIn1 == 0 || isoIn2 == 0) && jMin != jMax )
352  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - J1 or J2 = 0, but jMin != JMax");
353 
354  // MGP ---- Shall it be a warning or an exception?
355  if (nJ == 0)
356  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - nJ is zero, no overlap between in and out");
357 
358  // Loop over all possible combinations of isoIn1, isoIn2, iso3In11, iso3In2, jTot
359  // to get the probability of each of the in-channel couplings
360 
361  std::vector<G4double> clebsch;
362 
363  for(j=jMin; j<=jMax; j+=2)
364  {
365  G4double cg = ClebschGordan(isoIn1, iso3In1, isoIn2, iso3In2, j);
366  clebsch.push_back(cg);
367  }
368 
369  // Consistency check
370  if (static_cast<G4int>(clebsch.size()) != nJ)
371  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - nJ inconsistency");
372 
373  G4double sum = clebsch[0];
374 
375  for (j=1; j<nJ; j++)
376  {
377  sum += clebsch[j];
378  }
379  // Consistency check
380  if (sum <= 0.)
381  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - Sum of Clebsch-Gordan probabilities <=0");
382 
383  // Generate a normalized pdf
384 
385  std::vector<G4double> clebschPdf;
386  G4double previous = clebsch[0];
387  clebschPdf.push_back(previous/sum);
388  for (j=1; j<nJ; j++)
389  {
390  previous += clebsch[j];
391  G4double prob = previous / sum;
392  clebschPdf.push_back(prob);
393  }
394 
395  // Generate a random jTot according to the Clebsch-Gordan pdf
396  G4double rand = G4UniformRand();
397  G4int jTot = 0;
398  for (j=0; j<nJ; j++)
399  {
400  G4bool found = false;
401  if (rand < clebschPdf[j])
402  {
403  found = true;
404  jTot = jMin + 2*j;
405  }
406  if (found) break;
407  }
408 
409  // Generate iso3Out
410 
411  std::vector<G4double> mMin;
412  mMin.push_back(-isoA);
413  mMin.push_back(-isoB);
414 
415  std::vector<G4double> mMax;
416  mMax.push_back(isoA);
417  mMax.push_back(isoB);
418 
419  // Calculate the possible |J_i M_i> combinations and their probability
420 
421  std::vector<G4double> m1Out;
422  std::vector<G4double> m2Out;
423 
424  const G4int size = 20;
425  G4double prbout[size][size];
426 
427  G4int m1pos(0), m2pos(0);
428  G4int j12;
429  G4int m1pr(0), m2pr(0);
430 
431  sum = 0.;
432  for(j12 = std::abs(isoA-isoB); j12<=(isoA+isoB); j12+=2)
433  {
434  m1pos = -1;
435  for (m1pr = static_cast<G4int>(mMin[0]+.00001); m1pr <= mMax[0]; m1pr+=2)
436  {
437  m1pos++;
438  if (m1pos >= size)
439  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - m1pos > size");
440  m1Out.push_back(m1pr);
441  m2pos = -1;
442  for (m2pr = static_cast<G4int>(mMin[1]+.00001); m2pr <= mMax[1]; m2pr+=2)
443  {
444  m2pos++;
445  if (m2pos >= size)
446  {
447  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - m2pos > size");
448  }
449  m2Out.push_back(m2pr);
450 
451  if(m1pr + m2pr == iso3)
452  {
453  G4int m12 = m1pr + m2pr;
454  G4double c12 = ClebschGordan(isoA, m1pr, isoB,m2pr, j12);
455  G4double c34 = ClebschGordan(0,0,0,0,0);
456  G4double ctot = ClebschGordan(j12, m12, 0, 0, jTot);
457  G4double cleb = c12*c34*ctot;
458  prbout[m1pos][m2pos] = cleb;
459  sum += cleb;
460  }
461  else
462  {
463  prbout[m1pos][m2pos] = 0.;
464  }
465  }
466  }
467  }
468 
469  if (sum <= 0.)
470  throw G4HadronicException(__FILE__, __LINE__, "G4Clebsch::GenerateIso3 - sum (out) <=0");
471 
472  for (i=0; i<size; i++)
473  {
474  for (j=0; j<size; j++)
475  {
476  prbout[i][j] /= sum;
477  }
478  }
479 
480  rand = G4UniformRand();
481 
482  G4int m1p, m2p;
483 
484  for (m1p=0; m1p<m1pos; m1p++)
485  {
486  for (m2p=0; m2p<m2pos; m2p++)
487  {
488  if (rand < prbout[m1p][m2p])
489  {
490  temp.push_back(m1Out[m1p]);
491  temp.push_back(m2Out[m2p]);
492  return temp;
493  }
494  else
495  {
496  rand -= prbout[m1p][m2p];
497  }
498  }
499  }
500 
501  throw G4HadronicException(__FILE__, __LINE__, "Should never get here ");
502  return temp;
503 }
504 
505 
507  G4int J1, G4int J2,
508  G4int m_1, G4int m_2) const
509 {
510  // Calculate the normalized Clebsch-Gordan coefficient, that is the prob
511  // of isospin decomposition of (J,m) into J1, J2, m1, m2
512 
513  G4double cleb = 0.;
514 
515  if(J1 == 0 || J2 == 0) return cleb;
516 
517  G4double sum = 0.0;
518 
519  // Loop over all J1,J2,Jtot,m1,m2 combinations
520 
521  for(G4int m1Current=-J1; m1Current<=J1; m1Current+=2)
522  {
523  G4int m2Current = M - m1Current;
524 
525  G4double prob = ClebschGordan(J1, m1Current, J2, m2Current, J);
526  sum += prob;
527  if (m2Current == m_2 && m1Current == m_1) cleb += prob;
528  }
529 
530  // Normalize probs to 1
531  if (sum > 0.) cleb /= sum;
532 
533  return cleb;
534 }
G4double NormalizedClebschGordan(G4int J, G4int m, G4int J1, G4int J2, G4int m1, G4int m2) const
Definition: G4Clebsch.cc:506
int G4int
Definition: G4Types.hh:78
std::vector< G4double > GenerateIso3(G4int isoIn1, G4int iso3In1, G4int isoIn2, G4int iso3In2, G4int isoOut1, G4int isoOut2) const
Definition: G4Clebsch.cc:285
#define G4UniformRand()
Definition: Randomize.hh:95
G4GLOB_DLL std::ostream G4cout
bool G4bool
Definition: G4Types.hh:79
const G4int n
virtual ~G4Clebsch()
Definition: G4Clebsch.cc:50
G4double Wigner3J(G4double j1, G4double j2, G4double j3, G4double m1, G4double m2, G4double m3) const
Definition: G4Clebsch.cc:124
int G4lrint(double ad)
Definition: templates.hh:163
T max(const T t1, const T t2)
brief Return the largest of the two arguments
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
std::vector< G4double > logs
Definition: G4Clebsch.hh:89
G4double Weight(G4int isoIn1, G4int iso3In1, G4int isoIn2, G4int iso3In2, G4int isoOut1, G4int isoOut2) const
Definition: G4Clebsch.cc:66
#define G4endl
Definition: G4ios.hh:61
G4bool operator!=(const G4Clebsch &right) const
Definition: G4Clebsch.cc:60
G4bool operator==(const G4Clebsch &right) const
Definition: G4Clebsch.cc:54
double G4double
Definition: G4Types.hh:76
G4int sign(const T t)
A simple sign function that allows us to port fortran code to c++ more easily.
G4double ClebschGordan(G4int isoIn1, G4int iso3In1, G4int isoIn2, G4int iso3In2, G4int jOut) const
Definition: G4Clebsch.cc:93