GammaWare  Head Version for release 0.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
BaseGEM.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004 by Olivier Stezowski *
3  * stezow(AT)ipnl.in2p3.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
23 #include "BaseGEM.h"
24 
25 // Required for the wigner symbols / legendre in MathMore
26 #include "RConfigure.h"
27 #include "TFile.h"
28 #include "TMath.h"
29 #include "TLorentzVector.h"
30 #include "TF1.h"
31 #include "TROOT.h"
32 
33 #include "Spin.h"
34 #include "GammaLink.h"
35 #include "NuclearLevel.h"
36 
37 using namespace Gw;
38 
39 #ifdef R__HAS_MATHMORE
40 #include "Math/SpecFuncMathMore.h"
41 //
42 namespace { // anonymous namespace for specifics to Angular Distribution. Hidden from the user point of view because of the root dependancy to wigner symbol
43 
44  Gw::Spin s_zero;
45 
46  // Population of one sub-state m with gaussian center at 0 and with a width sigma
47  Double_t P(const Gw::Spin &Ii, const Gw::Spin &m, Double_t sigma)
48  {
49  Double_t temp = 0.0;
50 
51  for (Gw::Spin i = -Ii ; i <= Ii ; i+=1) {
52  temp += TMath::Exp(-(i.Get()*i.Get())/(2*sigma*sigma));
53  if ( gDebug > 0 )
54  printf("temp = %f , sigma = %f , exp = %f\n",temp,sigma,TMath::Exp(-(i.Get()*i.Get())/(2*sigma*sigma)));
55  }
56 
57  return TMath::Exp(-(m.Get()*m.Get())/(2*sigma*sigma))/temp;
58  }
59  Double_t ClebschGordan(const Gw::Spin &j1, const Gw::Spin &m1, const Gw::Spin &j2, const Gw::Spin &m2, const Gw::Spin &J, const Gw::Spin &M)
60  {
61  Double_t CG = TMath::Power(-1,j1.Get()-j2.Get()+M.Get())
62  * TMath::Sqrt(2*J.Get()+1)
63  * ROOT::Math::wigner_3j(j1.GetInTwoHalfUnit(),j2.GetInTwoHalfUnit(),J.GetInTwoHalfUnit(),m1.GetInTwoHalfUnit(),m2.GetInTwoHalfUnit(),-M.GetInTwoHalfUnit());
64  //Double_t CG1 = TMath::Power(-1,j1.Get()-j2.Get()+M.Get());
65  //Double_t CG2 = TMath::Sqrt(2*J.Get()+1);
66  //Double_t CG3 = ROOT::Math::wigner_3j(j1.GetInTwoHalfUnit(),j2.GetInTwoHalfUnit(),J.GetInTwoHalfUnit(),m1.GetInTwoHalfUnit(),m2.GetInTwoHalfUnit(),-M.GetInTwoHalfUnit());
67 
68  //printf("Calculated Parameters CG1 %f CG2 %f CG3 %f\n",CG1,CG2,CG3);
69 
70  return CG;
71  }
73  Double_t B(const Gw::Spin &Ii, Int_t lambda)
74  {
75  Double_t result = 0, CG = 0;
76  Gw::Spin s_lambda(lambda,1);
77 
78  if( !Ii.IsHalfInt() ) // I1 integer
79  {
80  CG = ClebschGordan(Ii,s_zero,Ii,s_zero,s_lambda,s_zero);
81  result = TMath::Sqrt(2*Ii.Get()+1)*TMath::Power(-1,Ii.Get())*CG;
82  }
83  else // Ii half integer
84  {
85  Gw::Spin s_1_2(1,2), m_s_1_2(-1,2);
86 
87  CG = ClebschGordan(Ii,m_s_1_2,Ii,s_1_2,s_lambda,s_zero);
88  result = TMath::Sqrt(2*Ii.Get()+1)*(-1)*TMath::Power(-1,Ii.Get()+0.5)*CG;
89  }
90  //printf("Calculated Parameters CG %f result %f\n",CG,result);
91 
92  return result;
93  }
95  Double_t B(const Gw::Spin &Ii, Double_t lambda, Double_t sigma)
96  {
97 
98  Double_t result = 0.0, CG = 0.0; Gw::Spin s_lambda(lambda,1);
99 
100  for (Gw::Spin m = -Ii ; m <= Ii ; m+=1)
101  {
102  Gw::Spin m_m = -m;
103  CG = ClebschGordan(Ii,m_m,Ii,m,s_lambda,s_zero);
104 
105  result += TMath::Power(-1,Ii.Get()+m.Get())*CG*P(Ii,m,sigma);
106  }
107  result = TMath::Sqrt(2*Ii.Get()+1)*result;
108 
109  return result;
110  }
111  // F-coefficients ordinaires dans le cas d'une transition avec melange
112  Double_t F(const Gw::Spin &Ii, const Gw::Spin &If, Int_t L1, Int_t L2, Double_t lambda)
113  {
114  Double_t threeJ, sixJ, result;
115 
116  threeJ = ROOT::Math::wigner_3j(2*L1,2*L2,2*lambda,2,-2,0);
117  sixJ = ROOT::Math::wigner_6j(2*L1,2*L2,2*lambda,Ii.GetInTwoHalfUnit(),Ii.GetInTwoHalfUnit(),If.GetInTwoHalfUnit());
118 
119  result = TMath::Power(-1,1+Ii.Get()+If.Get())*TMath::Sqrt((2*lambda+1)*(2*L1+1)*(2*L2+1)*(2*Ii.Get()+1))*threeJ*sixJ;
120 
121  //printf("Calculated Parameters three %f six %f result %f\n",threeJ,sixJ,result);
122 
123  return result;
124  }
125  // ROOT suitable function to draw angular distribution up to order 4.
126  Double_t Wth(Double_t *x, Double_t *par)
127  {
128  Double_t p2,p4;
129  p2 = ROOT::Math::legendre(2,TMath::Cos(x[0]));
130  p4 = ROOT::Math::legendre(4,TMath::Cos(x[0]));
131 
132  return par[0]+par[1]*p2+par[2]*p4;
133  }
134  Double_t WthDeg(Double_t *x, Double_t *par)
135  {
136  Double_t p2,p4;
137  p2 = ROOT::Math::legendre(2,TMath::Cos(x[0]*TMath::Pi()/180.));
138  p4 = ROOT::Math::legendre(4,TMath::Cos(x[0]*TMath::Pi()/180.));
139 
140  return par[0]+par[1]*p2+par[2]*p4;
141  }
142  // ROOT suitable function to draw angular distribution up to order 4
143  Double_t WthCos(Double_t *x, Double_t *par)
144  {
145  Double_t p2,p4;
146  p2 = ROOT::Math::legendre(2,x[0]);
147  p4 = ROOT::Math::legendre(4,x[0]);
148 
149  return par[0]+par[1]*p2+par[2]*p4;
150  }
151 }
152 #endif
153 
155 
157  TObject(),
158  fLevelScheme(0x0), fFeeding(), fRandFeeding(), fRandDown(), fAD(), fRand0(), fTmp(), fEoC(),
159  fDirection(kDown),
160  fMinEnergyFactor(10.0),
161  fADType(0),
162  fCutLifeTime(0.0000000001), /* 0.1*ns from Krane 1971 */
163  fSigma(0.0)
164 {
165  fTmp.SetOwner(kTRUE);
166  fRandDown.SetOwner(kTRUE);
167  fFeeding.SetOwner(kTRUE);
168  fRandFeeding.SetOwner(kTRUE);
169  fAD.SetOwner(kTRUE);
170 }
171 
173 {
174  BaseGEM::Clear(""); // clear everything
175 
176  if ( fLevelScheme ) {
177  delete fLevelScheme;
178  fLevelScheme = 0x0;
179  }
180 }
181 
182 void BaseGEM::Clear(Option_t *o)
183 {
184  TString opt = o;
185  if ( opt.Contains("all") ) {
186  delete fLevelScheme; fLevelScheme = 0x0;
187  }
188 
189  fRand0.Clear(); fFeeding.Clear(); fRandFeeding.Clear(); fRandDown.Clear(); fTmp.Clear(); fAD.Clear();
190  fMinEnergyFactor = 10.0;
191  fDirection = kDown;
192 }
193 
194 Int_t BaseGEM::Import(const Char_t *filename, Option_t *opt)
195 {
196  Int_t ok = 0; Gw::LevelScheme *newlev = 0x0;
197 
198  // init level scheme and test if initialisation has succeded
199  TString lname(filename), lopt(opt);
200  if ( lname.Contains(".root")) { // different way but could be integrated in lev->Import through the ReadTObject method
201  TFile lroot(filename);
202  if ( lroot.IsOpen() ) {
203  newlev = (Gw::LevelScheme *)lroot.Get(opt);
204  if ( newlev )
205  ok = 1;
206  else
207  printf("Impossible to find levelscheme %s in %s \n",filename,opt);
208  }
209  else
210  return ok;
211  }
212  else {
213  newlev = new Gw::LevelScheme();
214  ok = newlev->Import(filename,opt);
215  }
216 
217  if ( newlev && ok ) {
218  if ( fLevelScheme ) {
219  delete fLevelScheme;
220  }
221  fLevelScheme = newlev;
222  InitRandom();
223  }
224  return ok;
225 }
226 
227 Bool_t BaseGEM::SetParameter(const char *name, Int_t value)
228 {
229  TString tname(name);
230  if ( tname == "ADType" ) {
231  fADType = value;
232  return true;
233  }
234  return false;
235 }
236 
237 Bool_t BaseGEM::SetParameter(const char *name, Double_t value)
238 {
239  TString tname(name);
240  if ( tname == "MinEnergyFactor" ) {
242  return true;
243  }
244  if ( tname == "CutLifeTime" ) {
246  return true;
247  }
248  return false;
249 }
250 
252 {
253  if ( fLevelScheme->GetLinks().GetSize() == 0 ) return; // nothing to be done
254 
255  Int_t i, iend, j, jend; Link *gam1 = NULL, *gam2 = NULL;
256 
257  // clear the previous definition BUT NOT the level scheme which has just been read.
258  BaseGEM::Clear("");
259 
260  // set each collection with the right number.
261  fRandDown.Expand(fLevelScheme->GetLinks().GetSize());
262  fRandFeeding.Expand(fLevelScheme->GetLinks().GetSize()); fFeeding.Expand(fLevelScheme->GetLinks().GetSize()); fAD.Expand(fLevelScheme->GetLinks().GetSize());
263 
264  // First it loops to check if all intensities are > 0 and it calculates the lowest positive one MIN .
265  // If at least one intensity is found <=0,
266  // all the gamma-rays with an intensity <= 0 are modified with an intensity = MIN / 100
267  Float_t min = 1000000; Int_t nbwrong = 0;
268  iend = jend = fLevelScheme->GetLinks().GetSize();
269  for (i = 0; i < iend; i++) {
270  gam1 = (Link *)fLevelScheme->GetLinks().At(i);
271  if ( gam1->GetStrength().Get() <= 0 ) {
272  nbwrong++;
273  }
274  else { // more than 0
275  if ( gam1->GetStrength().Get() < min )
276  min = gam1->GetStrength().Get() ;
277  }
278  } // iend
279  if ( nbwrong > 0 ) {
280  printf("\n WARNING in BaseGEM::Import \n");
281  printf(" %d links have been found with an intensity = 0 in %s \n",nbwrong,fLevelScheme->GetName());
282  printf(" The intensity of those links are set to the weakest intensity %f / %f \n \n",min,fMinEnergyFactor);
283  for (i = 0; i < iend; i++) {
284  gam1 = (Link *)fLevelScheme->GetLinks().At(i);
285  if ( gam1->GetStrength().Get() <= 0 ) {
286  gam1->GetStrength().Set(min/fMinEnergyFactor);
287  } // if
288  } // i
289  } // nbwrong
290 
291  // now for each gamma, a generator is created to go down in the path and to set fRand0 which determine the entry point
292  RandObj *down, *downfeeding; TObject *obj;
293  Float_t sum_int_up_in, sum_int_up_out, sum_int_down_in, sum_int_down_out;
294 
295  for (i = 0; i < iend; i++) { // loop on all gammas to build the cascade generator
296 
297  // current link with its associated generators
298  gam1 = (Link *)fLevelScheme->GetLinks().At(i); Gw::GammaLink *gamma = (Gw::GammaLink *)gam1;
299  //
300  down = new RandObj();
301  downfeeding = new RandObj();
302 
303  // feeding link for gam1
304  Link *feeding = new Link();
305  feeding->SetIL(gam1->GetIL());
306  feeding->SetFL(gam1->GetIL());
307 
308  obj = new TObject(); // gam1 is one of the link directly in coincidence with gam1
309  fTmp.Add(obj);
310  obj->SetUniqueID(i);
311  downfeeding->Add(obj,gam1->GetStrength().Get());
312 
313  // look for all gammas up and down in coincidence with gam1
314  sum_int_up_in = 0;
315  sum_int_up_out = gam1->GetStrength().Get();
316  sum_int_down_in = gam1->GetStrength().Get();
317  sum_int_down_out = 0;
318 
319  for (j = 0; j < jend; j++) { // look for gammas in coincidence with gamma # i
320 
321  if ( i == j ) continue;
322 
323  gam2 = (Link *)fLevelScheme->GetLinks().At(j);
324 
325  if ( gam1->GetIL() == gam2->GetFL() ) { // gammas filling the initial level of gam1
326  sum_int_up_in += gam2->GetStrength().Get();
327  }
328  if ( gam1->GetIL() == gam2->GetIL() ) { // gammas desexciting the initial level of gam1
329  sum_int_up_out += gam2->GetStrength().Get();
330 
331  obj = new TObject();
332  fTmp.Add(obj);
333  obj->SetUniqueID(j);
334  downfeeding->Add(obj,gam2->GetStrength().Get());
335  }
336  if ( gam1->GetFL() == gam2->GetIL() ) { // gammas desexciting the final level of gam1
337  sum_int_down_out += gam2->GetStrength().Get();
338 
339  obj = new TObject();
340  fTmp.Add(obj);
341  obj->SetUniqueID(j);
342  down->Add(obj,gam2->GetStrength().Get());
343  }
344 
345  if ( gam1->GetFL() == gam2->GetFL() ) { // gammas filling the final level of gam1
346  sum_int_down_in += gam2->GetStrength().Get();
347  }
348  } // jend
349 
350  // lateral feeding treatment
351  // 01-2015 because in the procedurethe way it is done is ti select randomly directly one gamma of the level scheme
352  // but through the feeding part, one should give a fraction of the feeinf to all gamma de exciting the level
353  if ( sum_int_up_out > sum_int_up_in ) { // the feeding for gam1 has a intensity greater than 0
354  feeding->GetStrength().Set( (sum_int_up_out - sum_int_up_in ) * gam1->GetStrength().Get() / (sum_int_up_out) );
355  }
356  else { feeding->GetStrength().Set(0.0); }
357 
358  // isomeric state not connected and end of cascade treatment
359  if ( sum_int_down_in > sum_int_down_out ) { down->Add(&fEoC,sum_int_down_in - sum_int_down_out); }
360 
361  fRand0.Add(feeding,feeding->GetStrength().Get()); fFeeding.AddAt(feeding,i);
362  fRandFeeding.AddAt(downfeeding,i);
363  fRandDown.AddAt(down,i);
364 
365  // ADType 0 means no angular distribution i.e. use gRandom->Sphere
366  fAD.AddAt(0x0,i);
367  if ( fADType == 1 && gam1->InheritsFrom("Gw::GammaLink") && gamma->GetLambda() > 0 ) {
368 
369 #ifdef R__HAS_MATHMORE
370  Int_t lambda_max = 0, L, L1, L2; Double_t a0,a2,a4; // name and parameters of the function to be used ... limited to order 4
371  a0 = 0.0;
372  a2 = 0.0;
373  a4 = 0.0;
374  Gw::Spin Ii, If;
375 
376  if ( fSigma <= 0.0 ) { // pure orientation of sub-magnetic states
377  //
378  Ii = ((Gw::NuclearLevel *)gamma->GetIL())->GetSpin();
379  If = ((Gw::NuclearLevel *)gamma->GetFL())->GetSpin();
380  Double_t delta = gamma->GetMixing().Get();
381 
382  if ( delta == 0.0 ) { // pure transition
383  L = gamma->GetLambda(); lambda_max = 2*gamma->GetLambda();
384  a0 = B(Ii,0)*F(Ii,If,L,L,0);
385  if ( lambda_max >=2 )
386  a2 = B(Ii,2)*F(Ii,If,L,L,2);
387  if ( lambda_max >=4 )
388  a4 = B(Ii,4)*F(Ii,If,L,L,4);
389  }
390  else { // mixed transition L, L+1
391  L = gamma->GetLambda(); lambda_max = 2*gamma->GetLambda() + 1, L1 = L, L2 = L+1;
392  // cmompute parameters
393  //if ( L1 == L2 ) { // stay null in case L1 != L2 because |L1-L2| <= labda <= L1+L2
394  // a0 = B(Ii,0)*F(Ii,If,L1,L2,0);
395  //}
396  if (lambda_max >=2 )
397  a2 = B(Ii,2)*( F(Ii,If,L1,L1,2) + 2*delta*F(Ii,If,L1,L2,2) + delta*delta*F(Ii,If,L2,L2,2) ) / (1+delta*delta);
398  if (lambda_max >=4 )
399  a4 = B(Ii,4)*( F(Ii,If,L1,L1,4) + 2*delta*F(Ii,If,L1,L2,4) + delta*delta*F(Ii,If,L2,L2,4) ) / (1+delta*delta);
400  }
401  }
402  else {
403  //
404  Ii = ((Gw::NuclearLevel *)gamma->GetIL())->GetSpin();
405  If = ((Gw::NuclearLevel *)gamma->GetFL())->GetSpin();
406  Double_t delta = gamma->GetMixing().Get();
407 
408  if ( delta == 0.0 ) { // pure transition
409  L = gamma->GetLambda(); lambda_max = 2*gamma->GetLambda();
410  //
411  a0 = B(Ii,0,fSigma)*F(Ii,If,L,L,0);
412  if (lambda_max >=2 )
413  a2 = B(Ii,2,fSigma)*F(Ii,If,L,L,2);
414  if (lambda_max >=4 )
415  a4 = B(Ii,4,fSigma)*F(Ii,If,L,L,4);
416  }
417  else { // mixed transition L, L+1
418  L = gamma->GetLambda(); lambda_max = 2*gamma->GetLambda() + 1, L1 = L, L2 = L+1;
419 
420  if ( L1 == L2 ) { // stay null in case L1 != L2 because |L1-L2| <= labda <= L1+L2
421  // a0 = B(Ii,0.fSigma)*F(Ii,If,L1,L2,0);
422  }
423  if (lambda_max >=2 )
424  a2 = B(Ii,2,fSigma)*( F(Ii,If,L1,L1,2) + 2*delta*F(Ii,If,L1,L2,2) + delta*delta*F(Ii,If,L2,L2,2) ) / (1+delta*delta);
425  if (lambda_max >=4 )
426  a4 = B(Ii,4,fSigma)*( F(Ii,If,L1,L1,4) + 2*delta*F(Ii,If,L1,L2,4) + delta*delta*F(Ii,If,L2,L2,4) ) / (1+delta*delta);
427 
428  }
429  }
430 
431  if ( gamma->GetTau().Get() < fCutLifeTime ) { // only if live time of initial state not long i.e. orientation is not washed out by electric/magnetic fields around
432  TString name_function = Form("%s_link_%.1f_%.1f_%.1f",fLevelScheme->GetName(),gamma->GetEnergy().Get(),Ii.Get(),If.Get());
433  TF1 *W = new TF1(name_function.Data(),Wth,0,TMath::Pi(),3);
434  W->SetParameter(0,1);
435  W->SetParameter(1,a2/a0);
436  W->SetParameter(2,a4/a0);
437  W->SetNpx(1000);
438  fAD.AddAt(W,i);
439 
440  // remove from list of function but add a clone that is not used by this. Note that it does not work with the root Clone method ? ...
441  // thus the first function is just removed from list of function while a similar one is kept with just a similar name
442  gROOT->GetListOfFunctions()->Remove(W);
443 
444  W = new TF1(name_function.Data(),Wth,0,TMath::Pi(),3);
445  W->SetParameter(0,1);
446  W->SetParameter(1,a2/a0);
447  W->SetParameter(2,a4/a0);
448  W->SetNpx(1000);
449  }
450 #else
451  printf(" *** Error, cannot set Angular Distribution in BaseGEM, ROOT MathMore lib probably not installed \n");
452 #endif
453  }
454  if ( gDebug > 0 ) {
455  printf(" There are %d gammas feeding the gamma # %d \n",downfeeding->GetSize(),i);
456  printf(" There are %d gammas de-exciting the gamma # %d \n",down->GetSize(),i);
457  }
458  } // iend
459 }
460 
461 /*
462  void BaseGEM::ls(Option_t *o) const
463  {
464  Link *gam1 = NULL; RandObj *robj; Int_t iend = fRand0.GetSize();
465 
466  fRand0.ls(o);
467  for (Int_t i = 0; i < iend; i++ ) {
468  gam1 = (GammaLink *)fRand0.At(i);
469  if ( gam1 ) {
470  printf("%f keV [%d] is stored with weight %f \n",gam1->GetEnergy().Get(),i,fRand0.WeightAt(i)) ;
471 
472  robj = (RandObj *)fRandUp.At(i); printf(" * %d gammas feed it \n",robj->GetSize()) ;
473  for (Int_t j = 0; j < robj->GetSize(); j++) {
474  if ( robj->At(j) == &fEoC ) printf(" Lateral feeding with weight %f \n",robj->WeightAt(j));
475  else {
476  printf(" Gamma #%d, feeding with weight %f \n",robj->At(j)->GetUniqueID(),robj->WeightAt(j)) ;
477  }
478  } // j
479  robj = (RandObj *)fRandDown.At(i); printf(" * %d gammas desexcites it \n",robj->GetSize()) ;
480  for (Int_t j = 0; j < robj->GetSize(); j++) {
481  if ( robj->At(j) == &fEoC ) printf(" EoC with weight %f \n",robj->WeightAt(j));
482  else {
483  printf(" Gamma #%d, desexcitation with weight %f \n",robj->At(j)->GetUniqueID(),robj->WeightAt(j)) ;
484  }
485  } // j
486  } // if gam1
487  } // iend
488  }
489  */
490 
491 // void BaseGEM::FillRandom(TH1 *h, Int_t ntimes) { fRand0.FillRandom(h,ntimes); }
492 
493 Int_t BaseGEM::DoCascade(TSeqCollection &cas, Int_t which_first, Option_t *o)
494 {
495  TObject *obj; Link *link; Int_t result = 0;
496 
497  if ( fRandFeeding.At( which_first ) == 0x0 )
498  return result;
499 
500  TString opt(o);
501  if ( !opt.Contains("add",TString::kIgnoreCase) )
502  cas.Clear("nodelete");
503 
504  // Ask the random generator for that feeding for the next link in the level scheme and keep on going with it
505  obj = ((RandObj *)fRandFeeding.At( which_first ))->Rand();
506  while ( obj != &fEoC ) {
507  link = (Link *)fLevelScheme->GetLinks().At(obj->GetUniqueID());
508  result += link->DoCascade(cas,o);
509  obj = ((RandObj *)fRandDown.At( obj->GetUniqueID() ))->Rand();
510  }
511 
512  if ( fDirection == kUp ) { // if kUp, inverse the cascade
513  TObjArray tmp(100);
514  tmp.SetOwner(kFALSE); tmp.Clear("nodelete"); tmp.AddAll(&cas); cas.Clear("nodelete");
515 
516  for (Int_t i = tmp.GetEntries()-1; i >=0; i-- )
517  cas.Add(tmp.At(i));
518  }
519 
520  return result;
521 }
522 
523 Int_t BaseGEM::DoCascade(TSeqCollection &cas, Option_t *o)
524 {
525  Int_t result = 0;
526 
527  // select the 'entry' point then call a random cascade from it
528  Int_t which_first = 0;
529  fRand0.Rand(which_first);
530  //
531  result += DoCascade(cas,which_first,o);
532 
533  return result;
534 }
535 
536 void BaseGEM::DoAngularDistribution(Int_t which_gamma, TLorentzVector &vector, Bool_t forceiso)
537 {
538  TObject *generator = fAD.At(which_gamma);
539  if ( generator == 0x0 || forceiso ) { // means not a function thus isotropic through gRandom
540  Double_t x,y,z;
541  Gw::Random::Instance()->Current()->Sphere(x,y,z,1.0);
542  vector.SetXYZT(x,y,z,0);
543 
544  // printf("Isotrope for gamma # %d \n",which_gamma);
545  }
546  else {
547  // in two steps. First in 2D through the AD get the theta angle then phi uniform distribution
548  TVector3 v; Double_t theta = 0, phi = 0;
549 
550  TF1 *angdistri2d = (TF1 *)generator;
551  theta = angdistri2d->GetRandom();
552  phi = Gw::Random::Instance()->Current()->Uniform(0.,TMath::TwoPi());
553  v.SetMagThetaPhi(1,theta,phi);
554 
555  vector.SetVect(v); vector.SetT(0.0);
556 
557  //printf("Angular Distribution for gamma # %d \n",which_gamma);
558  }
559 }
560 
561 Int_t BaseGEM::DoCascade(TSeqCollection &cas, TSeqCollection &directions, Int_t which_first, Option_t *o)
562 {
563  TObject *obj; Link *link; Int_t result = 0, result_one_link = 0;
564 
565  if ( fRandFeeding.At( which_first ) == 0x0 )
566  return result;
567 
568  TString opt(o);
569  if ( !opt.Contains("add",TString::kIgnoreCase) ) {
570  cas.Clear("nodelete");
571  directions.Clear("nodelete");
572  }
573 
574  // Ask the random generator for that feeding for the next link in the level scheme and keep on going with it
575  obj = ((RandObj *)fRandFeeding.At( which_first ))->Rand();
576  while ( obj != &fEoC ) {
577  link = (Link *)fLevelScheme->GetLinks().At(obj->GetUniqueID());
578  result_one_link += link->DoCascade(cas,o);
579 
580  for (Int_t i = result; i < result + result_one_link; i++) { // make sur the direction collection is synchronize with cas
581  if ( directions.At(i) == 0 ) {
582  directions.AddAt(new TLorentzVector(),i);
583  }
584  }
585  if ( result_one_link == 1 ) {
586  TLorentzVector *lv = (TLorentzVector *)directions.At(result);
587  if ( cas.At(result) == link ) { // it means the link itself has been added to the cascade --> AD could be done otherwise X conversion ==> isotropic
588  DoAngularDistribution(obj->GetUniqueID(),*lv);
589  }
590  else
591  DoAngularDistribution(obj->GetUniqueID(),*lv,true);
592  }
593  else {
594  for (Int_t i = 0; i < result_one_link; i++) {
595  TLorentzVector *lv = (TLorentzVector *)directions.At(result+i);
596  DoAngularDistribution(obj->GetUniqueID(),*lv,true);
597  }
598  printf("*** TO BE IMPLEMENTED in BaseGEM::DoCascade TSeqCollection &cas, TSeqCollection &directions, Int_t which_first, Option_t *o *** /n");
599  printf("*** Isotropic has been forced for %d links produced by link # %d *** /n",result_one_link,obj->GetUniqueID());
600  }
601  result += result_one_link;
602  obj = ((RandObj *)fRandDown.At( obj->GetUniqueID() ))->Rand();
603  }
604 
605  if ( fDirection == kUp ) { // if kUp, inverse the cascade
606  TObjArray tmpg(30), tmpd(30);
607  tmpg.SetOwner(kFALSE); tmpg.Clear("nodelete"); tmpg.AddAll(&cas); cas.Clear("nodelete");
608  tmpd.SetOwner(kFALSE); tmpd.Clear("nodelete"); tmpd.AddAll(&directions); directions.Clear("nodelete");
609 
610  for (Int_t i = tmpg.GetEntries()-1; i >=0; i-- ) {
611  cas.Add(tmpg.At(i));
612  directions.Add(tmpd.At(i));
613  }
614  }
615 
616  return result;
617 }
618 
619 Int_t BaseGEM::DoCascade(TSeqCollection &cas, TSeqCollection &directions, Option_t *o)
620 {
621  TString opt = o;
622 
623  // Reset the previous cascade.
624  if ( !opt.Contains("add",TString::kIgnoreCase) ) {
625  cas.Clear("nodelete");
626  directions.Clear("nodelete");
627  }
628 
629  // select the 'entry' point then call a random cascade from it
630  Int_t which_first = 0;
631  fRand0.Rand(which_first);
632  //
633  return DoCascade(cas,directions,which_first,o);
634 }
635 
636 
637 
A level Scheme.
Definition: LevelScheme.h:82
virtual TObject * Rand()
it returns a pointer to a randomly selected object from the collection
Definition: RandObj.cpp:93
printf("******************************************************************** \n")
virtual void Set(Data_T data)
set the measure and its error (default err=0)
Definition: Measure.h:66
Double_t fCutLifeTime
Definition: BaseGEM.h:134
virtual Int_t Import(const Char_t *, Option_t *)
to init this level scheme from an existing formatted file (ENSDF, Radware ..)
virtual void Clear(Option_t *opt="all")
Clear everything.
Definition: BaseGEM.cpp:182
Class to get randomly cascades of gammas on the basis of a level scheme.
Definition: BaseGEM.h:107
header file for a NuclearLevel
A nuclear level.
Definition: NuclearLevel.h:66
Int_t fADType
Definition: BaseGEM.h:133
Float_t Get() const
To get the spin as a float.
Definition: Spin.h:166
virtual ~BaseGEM()
Definition: BaseGEM.cpp:172
A class to select randomly an object in a TObjArray of objects.
Definition: RandObj.h:55
UInt_t value[MaxValue]
Definition: ReadDaqAlone.C:29
A spin is defined by two integers: a numerator and a denominator.
Definition: Spin.h:46
virtual void Clear(Option_t *opt="")
clear everything (the objects in the collection are not deleted)
Definition: RandObj.cpp:88
virtual const char * GetName() const
Definition: LevelScheme.h:300
virtual void DoAngularDistribution(Int_t which_gamma, TLorentzVector &, Bool_t forceiso=false)
Definition: BaseGEM.cpp:536
Double_t fMinEnergyFactor
Definition: BaseGEM.h:132
Int_t GetInTwoHalfUnit() const
to get the spin in two half unit
Definition: Spin.h:80
const TList & GetLinks()
to get the list of links
Definition: LevelScheme.h:295
Int_t fDirection
Definition: BaseGEM.h:129
TRandom * Current() const
to get the current TRandomom object
Definition: Random.h:118
virtual Data_T Get() const
get the value, can be overloaded
Definition: Data.h:70
virtual void Add(TObject *, Float_t)
it adds an object with a weight to this collection.
Definition: RandObj.cpp:49
virtual Int_t GetSize() const
Definition: RandObj.h:102
Double_t fSigma
Definition: BaseGEM.h:135
Bool_t IsHalfInt() const
To get the spin as a float.
Definition: Spin.h:72
ClassImp(BaseGEM)
virtual Int_t DoCascade(TSeqCollection &cascade, Option_t *opt="")
cascade simulation
Definition: BaseGEM.cpp:523
static Random * Instance()
to access the unique instance
Definition: Random.cpp:69
virtual Int_t Import(const Char_t *, Option_t *opt="152DY")
Load the level scheme and init the Monte-Carlo.
Definition: BaseGEM.cpp:194
Bool_t SetParameter(const char *name, Int_t value)
to set some parameters that modify the way the simulation is performed. return false is the parameter...
Definition: BaseGEM.cpp:227
virtual void InitRandom()
to be called to init the random generator
Definition: BaseGEM.cpp:251
header file for a BaseGEM (gamma-rays generator)
header file for a spin quantum number