Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/util/src/G4Clebsch.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 #include "G4ios.hh"
 27 #include "G4Clebsch.hh"
 28 #include "G4Pow.hh"
 29 #include "G4Exp.hh"
 30 #include "G4Log.hh"
 31 #include "Randomize.hh"
 32 
 33 const G4int G4POWLOGFACTMAX = 512;
 34 
 35 using namespace std;
 36 
 37 G4double G4Clebsch::ClebschGordanCoeff(G4int twoJ1, G4int twoM1, 
 38                                        G4int twoJ2, G4int twoM2, 
 39                                        G4int twoJ)
 40 {
 41   if(twoJ1 < 0 || twoJ2 < 0 || twoJ < 0 ||
 42      ((twoJ1-twoM1) % 2) || ((twoJ2-twoM2) % 2)) { return 0; }
 43 
 44   G4int twoM = twoM1 + twoM2;
 45   if(twoM1 > twoJ1 || twoM1 < -twoJ1 ||
 46      twoM2 > twoJ2 || twoM2 < -twoJ2 ||
 47      twoM > twoJ || twoM < -twoJ) { return 0; }
 48 
 49   // Checks limits on J1, J2, J3
 50   G4double triangle = TriangleCoeff(twoJ1, twoJ2, twoJ);
 51   if(triangle == 0) { return 0; }
 52 
 53   G4Pow* g4pow = G4Pow::GetInstance();
 54   G4double factor = g4pow->logfactorial((twoJ1 + twoM1)/2) +
 55                     g4pow->logfactorial((twoJ1 - twoM1)/2);
 56   factor += g4pow->logfactorial((twoJ2 + twoM2)/2) +
 57             g4pow->logfactorial((twoJ2 - twoM2)/2);
 58   factor += g4pow->logfactorial((twoJ + twoM)/2) +
 59             g4pow->logfactorial((twoJ - twoM)/2);
 60   factor *= 0.5;
 61 
 62   G4int kMin = 0;
 63   G4int sum1 = (twoJ1 - twoM1)/2;
 64   G4int kMax = sum1;
 65   G4int sum2 = (twoJ - twoJ2 + twoM1)/2;
 66   if(-sum2 > kMin) kMin = -sum2;
 67   G4int sum3 = (twoJ2 + twoM2)/2;
 68   if(sum3 < kMax) kMax = sum3;
 69   G4int sum4 = (twoJ - twoJ1 - twoM2)/2;
 70   if(-sum4 > kMin) kMin = -sum4;
 71   G4int sum5 = (twoJ1 + twoJ2 - twoJ)/2;
 72   if(sum5 < kMax) kMax = sum5;
 73 
 74   // sanity / boundary checks
 75   if(kMin < 0) {
 76     G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch001", 
 77     JustWarning, "kMin < 0");
 78     return 0;
 79   }
 80   if(kMax < kMin) {
 81     G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch002", 
 82     JustWarning, "kMax < kMin");
 83     return 0;
 84   }
 85   if(kMax >= G4POWLOGFACTMAX) {
 86     G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch003", 
 87     JustWarning, "kMax too big for G4Pow");
 88     return 0;
 89   }
 90 
 91   // Now do the sum over k
 92   G4double kSum = 0.;
 93   for(G4int k = kMin; k <= kMax; k++) {
 94     G4double sign = (k % 2) ? -1 : 1;
 95     kSum += sign * G4Exp(factor - g4pow->logfactorial(sum1-k) -
 96        g4pow->logfactorial(sum2+k) -
 97        g4pow->logfactorial(sum3-k) -
 98        g4pow->logfactorial(sum4+k) -
 99        g4pow->logfactorial(k) -
100        g4pow->logfactorial(sum5-k));
101   }
102 
103   return triangle*sqrt(twoJ+1)*kSum;
104 }
105 
106 G4double G4Clebsch::ClebschGordan(G4int twoJ1, G4int twoM1, 
107           G4int twoJ2, G4int twoM2, 
108           G4int twoJ)
109 {
110   // ClebschGordanCoeff() will do all input checking
111   G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ);
112   return clebsch*clebsch;
113 }
114 
115 std::vector<G4double> 
116 G4Clebsch::GenerateIso3(G4int twoJ1, G4int twoM1, 
117       G4int twoJ2, G4int twoM2, 
118       G4int twoJOut1, G4int twoJOut2)
119 {
120   std::vector<G4double> temp;
121 
122   // ---- Special cases first ----
123 
124   // Special case, both Jin are zero
125   if (twoJ1 == 0 && twoJ2 == 0) {
126     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch010", 
127     JustWarning, "both twoJ are zero");
128     temp.push_back(0.);
129     temp.push_back(0.);
130     return temp;
131   }
132 
133   G4int twoM3 = twoM1 + twoM2;
134 
135   // Special case, either Jout is zero
136   if (twoJOut1 == 0) {  
137     temp.push_back(0.);
138     temp.push_back(twoM3);
139     return temp;
140   }
141   if (twoJOut2 == 0) {
142     temp.push_back(twoM3);
143     temp.push_back(0.);
144     return temp;
145   }
146   
147   // Number of possible states, in 
148   G4int twoJMinIn = std::max(std::abs(twoJ1 - twoJ2), std::abs(twoM3));
149   G4int twoJMaxIn = twoJ1 + twoJ2;
150 
151   // Number of possible states, out
152   G4int twoJMinOut = 9999;
153   for(G4int i=-1; i<=1; i+=2) {
154     for(G4int j=-1; j<=1; j+=2) {
155       G4int twoJTmp= std::abs(i*twoJOut1 + j*twoJOut2);
156       if(twoJTmp < twoJMinOut) twoJMinOut = twoJTmp;
157     }
158   }
159   twoJMinOut = std::max(twoJMinOut, std::abs(twoM3));
160   G4int twoJMaxOut = twoJOut1 + twoJOut2;
161 
162   // Possible in and out common states 
163   G4int twoJMin  =  std::max(twoJMinIn, twoJMinOut);
164   G4int twoJMax  =  std::min(twoJMaxIn, twoJMaxOut);
165   if (twoJMin > twoJMax) {
166     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch020", 
167     JustWarning, "twoJMin > twoJMax");
168     return temp;
169   }
170   
171   // Number of possible isospins
172   G4int nJ = (twoJMax - twoJMin) / 2 + 1;
173 
174   // A few consistency checks
175   
176   if ( (twoJ1 == 0 || twoJ2 == 0) && twoJMin != twoJMax ) {
177     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch021", 
178     JustWarning, "twoJ1 or twoJ2 = 0, but twoJMin != JMax");
179     return temp;
180   }
181 
182   // MGP ---- Shall it be a warning or an exception?
183   if (nJ == 0) {
184     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch022", 
185     JustWarning, "nJ is zero, no overlap between in and out");
186     return temp;
187   }
188 
189   // Loop over all possible combinations of twoJ1, twoJ2, twoM11, twoM2, twoJTot
190   // to get the probability of each of the in-channel couplings
191 
192   std::vector<G4double> clebsch;
193   G4double sum = 0.0;
194   for(G4int twoJ=twoJMin; twoJ<=twoJMax; twoJ+=2) {
195     sum += ClebschGordan(twoJ1, twoM1, twoJ2, twoM2, twoJ);
196     clebsch.push_back(sum);
197   }     
198 
199   // Consistency check
200   if (static_cast<G4int>(clebsch.size()) != nJ) {
201     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch023", 
202     JustWarning, "nJ inconsistency");
203     return temp;
204   }
205 
206   // Consistency check
207   if (sum <= 0.) {
208     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch024", 
209     JustWarning, "Sum of Clebsch-Gordan probabilities <=0");
210     return temp;
211   }
212 
213   // Generate a random twoJTot according to the Clebsch-Gordan pdf
214   sum *= G4UniformRand();
215   G4int twoJTot = twoJMin;
216   for (G4int i=0; i<nJ; ++i) {
217     if (sum < clebsch[i]) {
218       twoJTot += 2*i;
219       break;
220     }
221   }
222 
223   // Generate twoM3Out
224 
225   std::vector<G4double> mMin;
226   mMin.push_back(-twoJOut1);
227   mMin.push_back(-twoJOut2);
228 
229   std::vector<G4double> mMax;
230   mMax.push_back(twoJOut1);
231   mMax.push_back(twoJOut2);
232 
233   // Calculate the possible |J_i M_i> combinations and their probability
234 
235   std::vector<G4double> m1Out;
236   std::vector<G4double> m2Out;
237 
238   const G4int size = 20;
239   G4double prbout[size][size];
240 
241   G4int m1pos(0), m2pos(0);
242   G4int j12;
243   G4int m1pr(0), m2pr(0);
244 
245   sum = 0.;
246   for(j12 = std::abs(twoJOut1-twoJOut2); j12<=(twoJOut1+twoJOut2); j12+=2)
247   {
248     m1pos = -1;
249     for (m1pr = static_cast<G4int>(mMin[0]+.00001); m1pr <= mMax[0]; m1pr+=2)
250     {
251       m1pos++;
252       if (m1pos >= size) {
253         G4Exception("G4Clebsch::GenerateIso3()", "Clebsch025", 
254         JustWarning, "m1pos > size");
255         return temp;
256       }
257       m1Out.push_back(m1pr);
258       m2pos = -1;
259       for (m2pr = static_cast<G4int>(mMin[1]+.00001); m2pr <= mMax[1]; m2pr+=2)
260       {
261         m2pos++;
262         if (m2pos >= size)
263         {
264           G4Exception("G4Clebsch::GenerateIso3()", "Clebsch026", 
265           JustWarning, "m2pos > size");
266           return temp;
267         }
268         m2Out.push_back(m2pr);
269 
270         if(m1pr + m2pr == twoM3) 
271         {
272           G4int m12 = m1pr + m2pr;
273           G4double c12 = ClebschGordan(twoJOut1, m1pr, twoJOut2,m2pr, j12);
274           G4double c34 = ClebschGordan(0,0,0,0,0);
275           G4double ctot = ClebschGordan(j12, m12, 0, 0, twoJTot);
276           G4double cleb = c12*c34*ctot;
277           prbout[m1pos][m2pos] = cleb;
278           sum += cleb;
279         }
280         else
281         {
282           prbout[m1pos][m2pos] = 0.;
283         }
284       }
285     }
286   }
287   
288   if (sum <= 0.) {
289     G4Exception("G4Clebsch::GenerateIso3()", "Clebsch027", 
290     JustWarning, "sum (out) <=0");
291     return temp;
292   }
293 
294   for (G4int i=0; i<size; i++) {
295     for (G4int j=0; j<size; j++) {
296       prbout[i][j] /= sum;
297     }
298   }
299 
300   G4double rand = G4UniformRand();
301 
302   G4int m1p, m2p;
303 
304   for (m1p=0; m1p<m1pos; m1p++) {
305     for (m2p=0; m2p<m2pos; m2p++) {
306       if (rand < prbout[m1p][m2p]) {
307         temp.push_back(m1Out[m1p]);
308         temp.push_back(m2Out[m2p]);
309         return temp;
310       }   
311       else rand -= prbout[m1p][m2p];
312     }     
313   }   
314 
315   G4Exception("G4Clebsch::GenerateIso3()", "Clebsch028", 
316         JustWarning, "Should never get here");
317   return temp;
318 }
319 
320 G4double G4Clebsch::Weight(G4int twoJ1,  G4int twoM1, 
321          G4int twoJ2,  G4int twoM2, 
322          G4int twoJOut1, G4int twoJOut2)
323 {
324   G4double value = 0.;
325   
326   G4int twoM = twoM1 + twoM2;
327 
328   G4int twoJMinIn = std::max(std::abs(twoJ1 - twoJ2), std::abs(twoM));
329   G4int twoJMaxIn = twoJ1 + twoJ2;
330 
331   G4int twoJMinOut = std::max(std::abs(twoJOut1 - twoJOut2), std::abs(twoM));
332   G4int twoJMaxOut = twoJOut1 + twoJOut2;
333 
334   G4int twoJMin = std::max(twoJMinIn,twoJMinOut);
335   G4int twoJMax = std::min(twoJMaxIn,twoJMaxOut);
336 
337   for (G4int twoJ=twoJMin; twoJ<=twoJMax; twoJ+=2) {
338     // ClebschGordan() will do all input checking
339     value += ClebschGordan(twoJ1, twoM1, twoJ2, twoM2, twoJ);
340   }
341 
342   return value;
343 }
344 
345 G4double G4Clebsch::Wigner3J(G4double j1, G4double j2, G4double j3, 
346            G4double m1, G4double m2, G4double m3)
347 {
348   //  G4Exception("G4Clebsch::Wigner3J()", "Clebsch030", JustWarning, 
349   //  "G4Clebsch::Wigner3J with double arguments is deprecated. Please use G4int version.");
350   G4int twoJ1 = (G4int) (2.*j1);
351   G4int twoJ2 = (G4int) (2.*j2);
352   G4int twoJ3 = (G4int) (2.*j3);
353   G4int twoM1 = (G4int) (2.*m1);
354   G4int twoM2 = (G4int) (2.*m2);
355   G4int twoM3 = (G4int) (2.*m3);
356   return Wigner3J(twoJ1, twoM1, twoJ2, twoM2, twoJ3, twoM3);
357 }
358 
359 G4double G4Clebsch::Wigner3J(G4int twoJ1, G4int twoM1, 
360                              G4int twoJ2, G4int twoM2, 
361                              G4int twoJ3)
362 {
363   G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ3);
364   if(clebsch == 0) return clebsch;
365   if( (twoJ1-twoJ2+twoM1+twoM2)/2 % 2) clebsch = -clebsch;
366   return clebsch / sqrt(twoJ3+1);
367 }
368 
369 G4double G4Clebsch::Wigner3J(G4int twoJ1, G4int twoM1, 
370                              G4int twoJ2, G4int twoM2, 
371                              G4int twoJ3, G4int twoM3)
372 {
373   if(twoM1 + twoM2 != -twoM3) return 0;
374   G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ3);
375   if(clebsch == 0) return clebsch;
376   if( (twoJ1-twoJ2-twoM3)/2 % 2) clebsch = -clebsch;
377   return clebsch / sqrt(twoJ3+1);
378 }
379 
380 G4double G4Clebsch::NormalizedClebschGordan(G4int twoJ, G4int twoM, 
381               G4int twoJ1, G4int twoJ2,
382               G4int twoM1, G4int twoM2)
383 {
384   // Calculate the normalized Clebsch-Gordan coefficient, that is the prob 
385   // of isospin decomposition of (J,m) into J1, J2, m1, m2
386 
387   G4double cleb = 0.;
388   if(twoJ1 == 0 || twoJ2 == 0) return cleb; 
389   
390   // Loop over all J1,J2,Jtot,m1,m2 combinations
391   G4double sum = 0.0;
392   for(G4int twoM1Current=-twoJ1; twoM1Current<=twoJ1;  twoM1Current+=2) {
393     G4int twoM2Current = twoM - twoM1Current;
394     // ClebschGordan() will do all further input checking
395     G4double prob = ClebschGordan(twoJ1, twoM1Current, twoJ2, 
396           twoM2Current, twoJ);
397     sum += prob;
398     if (twoM2Current == twoM2 && twoM1Current == twoM1) cleb += prob;
399   }
400 
401   // Normalize probs to 1 
402   if (sum > 0.) cleb /= sum; 
403 
404   return cleb;
405 }
406 
407 G4double G4Clebsch::TriangleCoeff(G4int twoA, G4int twoB, G4int twoC)
408 {
409   // TC(ABC) = sqrt[ (A+B-C)! (A-B+C)! (-A+B+C)! / (A+B+C+1)! ]
410   // return 0 if the triad does not satisfy the triangle inequalities
411   G4Pow* g4pow =  G4Pow::GetInstance();
412 
413   double val = 0;
414   G4int i = twoA+twoB-twoC;
415   // only have to check that i is even the first time
416   if(i<0 || (i%2)) return 0;
417   else val += g4pow->logfactorial(i/2);
418 
419   i = twoA-twoB+twoC;
420   if(i<0) return 0;
421   else val += g4pow->logfactorial(i/2);
422 
423   i = -twoA+twoB+twoC;
424   if(i<0) return 0;
425   else val += g4pow->logfactorial(i/2);
426 
427   i = twoA+twoB+twoC+2;
428   if(i<0) return 0;
429   return G4Exp(0.5*(val - g4pow->logfactorial(i/2)));
430 }
431 
432 G4double G4Clebsch::Wigner6J(G4int twoJ1, G4int twoJ2, G4int twoJ3, 
433                  G4int twoJ4, G4int twoJ5, G4int twoJ6)
434 {
435   if(twoJ1 < 0 || twoJ2 < 0 || twoJ3 < 0 || 
436      twoJ4 < 0 || twoJ5 < 0 || twoJ6 < 0) return 0;
437 
438   // There is a fast calculation (no sums or exps) when twoJ6 = 0, 
439   // so permute to use it when possible
440   if(twoJ6 == 0) {
441     if(twoJ1 != twoJ5) return 0;
442     if(twoJ2 != twoJ4) return 0;
443     if(twoJ1+twoJ2 < twoJ3) return 0;
444     if((twoJ1 > twoJ2) && (twoJ3 < (twoJ1-twoJ2))) return 0;
445     if((twoJ2 > twoJ1) && (twoJ3 < (twoJ2-twoJ1))) return 0;
446     if((twoJ1+twoJ2+twoJ3) % 2) return 0;
447     return (((twoJ1+twoJ2+twoJ3)/2) % 2 ? -1. : 1.) /sqrt((twoJ1+1)*(twoJ2+1));
448   }
449   if(twoJ1 == 0) return Wigner6J(twoJ6, twoJ2, twoJ4, twoJ3, twoJ5, 0);
450   if(twoJ2 == 0) return Wigner6J(twoJ1, twoJ6, twoJ5, twoJ4, twoJ3, 0);
451   if(twoJ3 == 0) return Wigner6J(twoJ4, twoJ2, twoJ6, twoJ1, twoJ5, 0);
452   if(twoJ4 == 0) return Wigner6J(twoJ3, twoJ2, twoJ1, twoJ6, twoJ5, 0);
453   if(twoJ5 == 0) return Wigner6J(twoJ1, twoJ3, twoJ2, twoJ4, twoJ6, 0);
454 
455   // Check triangle inequalities and calculate triangle coefficients.
456   // Also check evenness of sums
457   G4Pow* g4pow =  G4Pow::GetInstance();
458   double triangles = 0;
459   G4int i;
460   i =  twoJ1+twoJ2-twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
461   i =  twoJ1-twoJ2+twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
462   i = -twoJ1+twoJ2+twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
463   i =  twoJ1+twoJ2+twoJ3+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
464   i =  twoJ1+twoJ5-twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
465   i =  twoJ1-twoJ5+twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
466   i = -twoJ1+twoJ5+twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
467   i =  twoJ1+twoJ5+twoJ6+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
468   i =  twoJ4+twoJ2-twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
469   i =  twoJ4-twoJ2+twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
470   i = -twoJ4+twoJ2+twoJ6;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
471   i =  twoJ4+twoJ2+twoJ6+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
472   i =  twoJ4+twoJ5-twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
473   i =  twoJ4-twoJ5+twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
474   i = -twoJ4+twoJ5+twoJ3;   if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
475   i =  twoJ4+twoJ5+twoJ3+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
476   triangles = G4Exp(0.5*triangles);
477   
478   // Prepare to sum over k. If we have made it this far, all of the following
479   // sums must be non-negative and divisible by two
480 
481   // k must be >= all of the following sums:
482   G4int sum1 = (twoJ1 + twoJ2 + twoJ3)/2;
483   G4int kMin = sum1;
484   G4int sum2 = (twoJ1 + twoJ5 + twoJ6)/2;
485   if(sum2 > kMin) kMin = sum2;
486   G4int sum3 = (twoJ4 + twoJ2 + twoJ6)/2;
487   if(sum3 > kMin) kMin = sum3;
488   G4int sum4 = (twoJ4 + twoJ5 + twoJ3)/2;
489   if(sum4 > kMin) kMin = sum4;
490 
491   // and k must be <= all of the following sums:
492   G4int sum5 = (twoJ1 + twoJ2 + twoJ4 + twoJ5)/2;
493   G4int kMax = sum5;
494   G4int sum6 = (twoJ2 + twoJ3 + twoJ5 + twoJ6)/2;
495   if(sum6 < kMax) kMax = sum6;
496   G4int sum7 = (twoJ1 + twoJ3 + twoJ4 + twoJ6)/2;
497   if(sum7 < kMax) kMax = sum7;
498 
499   // sanity / boundary checks
500   if(kMin < 0) {
501     G4Exception("G4Clebsch::Wigner6J()", "Clebsch040", 
502     JustWarning, "kMin < 0");
503     return 0;
504   }
505   if(kMax < kMin) {
506     G4Exception("G4Clebsch::Wigner6J()", "Clebsch041", 
507     JustWarning, "kMax < kMin");
508     return 0;
509   }
510   if(kMax >= G4POWLOGFACTMAX) {
511     G4Exception("G4Clebsch::Wigner6J()", "Clebsch041", 
512     JustWarning, "kMax too big for G4Pow");
513     return 0;
514   }
515 
516   // Now do the sum over k
517   G4double kSum = 0.;
518   G4double sign = (kMin % 2) ? -1 : 1;
519   for(G4int k = kMin; k <= kMax; k++) {
520     kSum += sign * G4Exp(g4pow->logfactorial(k+1) -
521                             g4pow->logfactorial(k-sum1) -
522                             g4pow->logfactorial(k-sum2) -
523                             g4pow->logfactorial(k-sum3) -
524                             g4pow->logfactorial(k-sum4) -
525                             g4pow->logfactorial(sum5-k) -
526                             g4pow->logfactorial(sum6-k) -
527                             g4pow->logfactorial(sum7-k));
528     sign *= -1;
529   }
530   return triangles*kSum;
531 }
532 
533 G4double G4Clebsch::Wigner9J(G4int twoJ1, G4int twoJ2, G4int twoJ3, 
534                  G4int twoJ4, G4int twoJ5, G4int twoJ6,
535                  G4int twoJ7, G4int twoJ8, G4int twoJ9)
536 {
537   if(twoJ1 < 0 || twoJ2 < 0 || twoJ3 < 0 || 
538      twoJ4 < 0 || twoJ5 < 0 || twoJ6 < 0 ||
539      twoJ7 < 0 || twoJ8 < 0 || twoJ9 < 0) return 0;
540 
541   if(twoJ9 == 0) {
542     if(twoJ3 != twoJ6) return 0;
543     if(twoJ7 != twoJ8) return 0;
544     G4double sixJ = Wigner6J(twoJ1, twoJ2, twoJ3, twoJ5, twoJ4, twoJ7);
545     if(sixJ == 0) return 0;
546     if((twoJ2+twoJ3+twoJ4+twoJ7)/2 % 2) sixJ = -sixJ;
547     return sixJ/sqrt((twoJ3+1)*(twoJ7+1));
548   }
549   if(twoJ1 == 0) return Wigner9J(twoJ9, twoJ6, twoJ3, twoJ8, twoJ5, twoJ2, twoJ7, twoJ4, twoJ1);
550   if(twoJ2 == 0) return Wigner9J(twoJ7, twoJ9, twoJ8, twoJ4, twoJ6, twoJ5, twoJ1, twoJ3, twoJ2);
551   if(twoJ4 == 0) return Wigner9J(twoJ3, twoJ2, twoJ1, twoJ9, twoJ8, twoJ7, twoJ6, twoJ5, twoJ4);
552   if(twoJ5 == 0) return Wigner9J(twoJ1, twoJ3, twoJ2, twoJ7, twoJ9, twoJ8, twoJ4, twoJ6, twoJ5);
553   G4int twoS = twoJ1+twoJ2+twoJ3+twoJ4+twoJ5+twoJ6+twoJ7+twoJ8+twoJ9;
554   if(twoS % 2) return 0;
555   G4double sign = (twoS/2 % 2) ? -1 : 1;
556   if(twoJ3 == 0) return sign*Wigner9J(twoJ7, twoJ8, twoJ9, twoJ4, twoJ5, twoJ6, twoJ1, twoJ2, twoJ3);
557   if(twoJ6 == 0) return sign*Wigner9J(twoJ1, twoJ2, twoJ3, twoJ7, twoJ8, twoJ9, twoJ4, twoJ5, twoJ6);
558   if(twoJ7 == 0) return sign*Wigner9J(twoJ3, twoJ2, twoJ1, twoJ6, twoJ5, twoJ4, twoJ9, twoJ8, twoJ7);
559   if(twoJ8 == 0) return sign*Wigner9J(twoJ1, twoJ3, twoJ2, twoJ4, twoJ6, twoJ5, twoJ7, twoJ9, twoJ8);
560 
561   // No element is zero: check triads now for speed
562   G4int i;
563   i =  twoJ1+twoJ2-twoJ3; if(i<0 || i%2) return 0;
564   i =  twoJ1-twoJ2+twoJ3; if(i<0 || i%2) return 0;
565   i = -twoJ1+twoJ2+twoJ3; if(i<0 || i%2) return 0;
566   i =  twoJ4+twoJ5-twoJ6; if(i<0 || i%2) return 0;
567   i =  twoJ4-twoJ5+twoJ6; if(i<0 || i%2) return 0;
568   i = -twoJ4+twoJ5+twoJ6; if(i<0 || i%2) return 0;
569   i =  twoJ7+twoJ8-twoJ9; if(i<0 || i%2) return 0;
570   i =  twoJ7-twoJ8+twoJ9; if(i<0 || i%2) return 0;
571   i = -twoJ7+twoJ8+twoJ9; if(i<0 || i%2) return 0;
572   i =  twoJ1+twoJ4-twoJ7; if(i<0 || i%2) return 0;
573   i =  twoJ1-twoJ4+twoJ7; if(i<0 || i%2) return 0;
574   i = -twoJ1+twoJ4+twoJ7; if(i<0 || i%2) return 0;
575   i =  twoJ2+twoJ5-twoJ8; if(i<0 || i%2) return 0;
576   i =  twoJ2-twoJ5+twoJ8; if(i<0 || i%2) return 0;
577   i = -twoJ2+twoJ5+twoJ8; if(i<0 || i%2) return 0;
578   i =  twoJ3+twoJ6-twoJ9; if(i<0 || i%2) return 0;
579   i =  twoJ3-twoJ6+twoJ9; if(i<0 || i%2) return 0;
580   i = -twoJ3+twoJ6+twoJ9; if(i<0 || i%2) return 0;
581   
582   // Okay, have to do the full sum over 6J's
583   // Find limits for K sum
584   G4int twoKMax = twoJ1+twoJ9;
585   if(twoJ4+twoJ8 < twoKMax) twoKMax = twoJ4+twoJ8;
586   if(twoJ2+twoJ6 < twoKMax) twoKMax = twoJ2+twoJ6;
587   G4int twoKMin = twoJ1-twoJ9;
588   if(twoJ9-twoJ1 > twoKMin) twoKMin = twoJ9-twoJ1;
589   if(twoJ4-twoJ8 > twoKMin) twoKMin = twoJ4-twoJ8;
590   if(twoJ8-twoJ4 > twoKMin) twoKMin = twoJ8-twoJ4;
591   if(twoJ2-twoJ6 > twoKMin) twoKMin = twoJ2-twoJ6;
592   if(twoJ6-twoJ2 > twoKMin) twoKMin = twoJ6-twoJ2;
593   if(twoKMin > twoKMax) return 0;
594 
595   G4double sum = 0;
596   for(G4int twoK = twoKMin; twoK <= twoKMax; twoK += 2) {
597     G4double value = Wigner6J(twoJ1, twoJ4, twoJ7, twoJ8, twoJ9, twoK);
598     if(value == 0) continue;
599     value *= Wigner6J(twoJ2, twoJ5, twoJ8, twoJ4, twoK, twoJ6);
600     if(value == 0) continue;
601     value *= Wigner6J(twoJ3, twoJ6, twoJ9, twoK, twoJ1, twoJ2);
602     if(value == 0) continue;
603     if(twoK % 2) value = -value;
604     sum += value*G4double(twoK+1);
605   }
606   return sum;
607 }
608 
609 G4double G4Clebsch::WignerLittleD(G4int twoJ, G4int twoM, G4int twoN, 
610           G4double cosTheta)
611 {
612   if(twoM < -twoJ || twoM > twoJ || twoN < -twoJ || twoN > twoJ 
613      || ((twoM % 2) != (twoJ % 2)) || ((twoN % 2) != (twoJ % 2))) 
614     { return 0; }
615 
616      if(cosTheta == 1.0) { return G4double(twoM == twoN); }
617 
618   G4int kMin = 0;
619   if(twoM > twoN) kMin = (twoM-twoN)/2;
620   G4int kMax = (twoJ + twoM)/2;
621   if((twoJ-twoN)/2 < kMax) kMax = (twoJ-twoN)/2;
622 
623   G4double lnCosHalfTheta = G4Log((cosTheta+1.)*0.5) * 0.5;
624   G4double lnSinHalfTheta = G4Log((1.-cosTheta)*0.5) * 0.5;
625 
626   G4Pow* g4pow =  G4Pow::GetInstance();
627   G4double d = 0;
628   for(G4int k = kMin; k <= kMax; k++) {
629     G4double logSum = 0.5*(g4pow->logfactorial((twoJ+twoM)/2) +
630                            g4pow->logfactorial((twoJ-twoM)/2) +
631                            g4pow->logfactorial((twoJ+twoN)/2) +
632                            g4pow->logfactorial((twoJ-twoN)/2));
633     logSum += -g4pow->logfactorial((twoJ+twoM)/2 - k) -
634                g4pow->logfactorial((twoJ-twoN)/2 - k) -
635                g4pow->logfactorial(k) - 
636                g4pow->logfactorial(k+(twoN-twoM)/2);
637     logSum += (twoJ+(twoM-twoN)/2 - 2*k)*lnCosHalfTheta + 
638       (2*k + (twoN-twoM)/2)*lnSinHalfTheta;
639     G4double sign = (k % 2) ? -1 : 1;
640     d += sign * G4Exp(logSum);
641   }
642   return d;
643 }
644