FdEnergyFinder.cc
Go to the documentation of this file.
1 
9 #include "FdEnergyFinder.h"
10 
11 #include <evt/Event.h>
12 #include <fevt/FEvent.h>
13 #include <fevt/Eye.h>
14 #include <fevt/EyeRecData.h>
15 #include <evt/ShowerFRecData.h>
16 #include <evt/GaisserHillas4Parameter.h>
17 #include <fwk/CentralConfig.h>
18 #include <utl/TabulatedFunctionErrors.h>
19 #include <utl/AugerUnits.h>
20 #include <utl/PhysicalConstants.h>
21 #include <utl/Reader.h>
22 #include <utl/ErrorLogger.h>
23 //BRD added 28/2/05
24 #include <utl/PhysicalFunctions.h>
25 
26 #include <iostream>
27 #include <TMinuit.h>
28 
29 
30 
31 using namespace FdEnergyFinderOG;
32 using namespace utl;
33 using namespace evt;
34 using namespace std;
35 
37 double FdEnergyFinder::fChisqGH =0;
38 double FdEnergyFinder::fNdof=0;
39 
41 
43 
44  Branch topB =
45  cc->GetTopBranch("FdEnergyFinder");
46 
47  topB.GetChild("fixX0").GetData(fFixX0);
48  topB.GetChild("composition").GetData(fComposition);
49  topB.GetChild("unseenEnergyModel").GetData(fUnseenEnergyModel);
50 
51  // SYB: Checks are now performed by XML schema.
52 // if ( fUnseenEnergyModel > 2 || fUnseenEnergyModel < 1 ) {
53 // ERROR("Error - unknown unseen energy model (1=QGSJET, 2=SIBYLL");
54 // return eFailure;
55 // }
56 // //DV for unsigned this is always false
57 // if (/*fComposition < 0 ||*/ fComposition > 2) {
58 // ERROR("Error - unknown composition (0 = proton-iron mixed; 1 = protons; 2 = iron)");
59 // return eFailure;
60 // }
61 
62  fNmaxGH = 0;
63  fXmaxGH = 0;
64  fX0GH = 0;
65  fEemGH = 0;
66  fNmaxGH_error = 0;
67  fXmaxGH_error = 0;
68  fX0GH_error = 0;
69  fChisqGH = 0;
70  fNdof =0;
71  fLongProfile =0;
72 
73  return eSuccess;
74 }
75 
77 
78  if (!event.HasFEvent()) return eSuccess;
79 
81 
82  for (eyeiter= event.GetFEvent().EyesBegin();
83  eyeiter != event.GetFEvent().EyesEnd();
84  ++eyeiter){
85 
86 
87  fNmaxGH = 0;
88  fXmaxGH = 0;
89  fX0GH = 0;
90  fEemGH = 0;
91  fNmaxGH_error = 0;
92  fXmaxGH_error = 0;
93  fX0GH_error = 0;
94  fChisqGH = 0;
95  fNdof =0;
96  fLongProfile =0;
97  fMinuitFailed=false;
98 
99  if (! eyeiter->HasRecData() ) continue;
100  if (! eyeiter->GetRecData().HasFRecShower() ) continue;
101  ShowerFRecData& frecshower = eyeiter->GetRecData().GetFRecShower();
102 
103  // Getting energy cutoff
104  fEnergyCutoff = frecshower.GetEnergyCutoff();
105  cout << "Energy cutoff = " << fEnergyCutoff/MeV << " [MeV]" << endl;
106 
107  if (!frecshower.HasLongitudinalProfile()) continue;
108 
109  const TabulatedFunctionErrors& long_profile =
110  frecshower.GetLongitudinalProfile();
111 
112  fLongProfile = &long_profile;
113 
114 
115  if (!frecshower.HasGHParameters()) {
117  frecshower.MakeGHParameters (gh_tmp);
118  }
119 
120  fGHParameters = dynamic_cast <evt::GaisserHillas4Parameter*>
121  (&(frecshower.GetGHParameters()));
122 
123  if (fGHParameters==0) {
124  WARNING ("ShowerFRecData of this eye already contains GH parameters.");
125  continue;
126  }
127 
128  fGHParameters->SetShapeParameter(gh::eLambda, kLambdaGH, 0.);
129 
130  this->FitProfile();
131 
132  fGHParameters->SetXMax(fXmaxGH,fXmaxGH_error );
133  fGHParameters->SetShapeParameter(gh::eX0, fX0GH, fX0GH_error);
134  fGHParameters->SetChiSquare( fChisqGH, (unsigned int)fNdof);
135  fGHParameters->SetNMax(fNmaxGH,fNmaxGH_error );
136 
137  if (fMinuitFailed){
138  fGHParameters->SetXMax (-999,0);
139  fGHParameters->SetShapeParameter(gh::eX0, -999, 0);
140  fGHParameters->SetChiSquare( -999, 0);
141  fGHParameters->SetNMax(-999, 0 );
142  }
143 
144  this->FindEmEnergy();
145 
146  this->FindEmEnergyError();
147 
148  this->FindTotalEnergy();
149 
150  frecshower.SetEmEnergy(fEemGH,fEemGH_error);
151 
152  frecshower.SetTotalEnergy(fEtotalGH,fEemGH_error );
153 
154 
155  cout << "Em energy [GeV]" << fEemGH/GeV << " +- "
156  << fEemGH_error/GeV << endl;
157  cout << "Total Energy [GeV] " << fEtotalGH/GeV << endl;
158 
159  } // loop on eyes
160 
161  return eSuccess;
162 }
163 
165 
166  const int npar = 3; // number of parameters
167 
168  TMinuit theMinuit(npar); // 3 parameter fit
169 
170  theMinuit.SetPrintLevel(-1); // minuit verbosity
171  theMinuit.SetFCN(FdEnergyFinder::MinuitFitFunction);
172 
173  double arglist[npar]; // arguments to pass to the Minuit interpreter
174  int ierflag =0;
175 
176  arglist[0]=1; // [up]
177  arglist[1]=1; // unused
178  theMinuit.mnexcm("SET ERR", arglist,1,ierflag);
179 
180  if (ierflag) ERROR ("Minuit SET ERR failed");
181 
182  static double vstart[npar]; // inital point
183  static double step[npar]; // step size
184 
185  double log_n_max = 20.7;
186  double x_max = 700 * (g/cm2);
187  double x0 = 0.0 * (g/cm2);
188 
189 
190  // something better has to be found for starting points
191  vstart[0] = log_n_max;
192  vstart[1] = x_max;
193  vstart[2] = x0;
194 
195  step[0] = 0.05;
196  // step[1]=0.5;
197  // step[2]=0.1;
198  step[1] = 10 * (g/cm2);
199  step[2] = 10 * (g/cm2);
200 
201  if (fFixX0) step[2] = 0.0;
202 
203  cout << " x0 step " << step[2] << endl;
204 
205  theMinuit.mnparm(0,"log_n_max",vstart[0], step[0],0,0,ierflag);
206  theMinuit.mnparm(1,"x_max", vstart[1], step[1],0,0,ierflag);
207  theMinuit.mnparm(2,"x0", vstart[2], step[2],0,0,ierflag);
208 
209  // Now ready for minimization step
210  arglist[0] = 500; // [maxcalls]
211  arglist[1] = 1.; // [tolerance]
212  theMinuit.mnexcm("MIGRAD", arglist , 2, ierflag);
213 
214  if (ierflag) {
215  ERROR ("Minuit MIGRAD failed");
216  fMinuitFailed=true;
217  }
218 
219  double p[6];
220  theMinuit.GetParameter(0, p[0], p[3]);
221  theMinuit.GetParameter(1, p[1], p[4]);
222  theMinuit.GetParameter(2, p[2], p[5]);
223 
224  fNmaxGH = exp(p[0]);
225  fXmaxGH = p[1];
226  fX0GH = p[2];
227 
228  fNmaxGH_error = p[3]* fNmaxGH;
229  fXmaxGH_error = p[4];
230  fX0GH_error = p[5];
231 
232  cout << endl;
233  cout << endl << "Gaisser-Hillas Fit result:" << endl;
234  cout << "n_max " << fNmaxGH << " +/- " << fNmaxGH_error << "\n"
235  << " X_max [g/cm2] " << fXmaxGH / (g/cm2)
236  << " +/- " << fXmaxGH_error / (g/cm2) << "\n"
237  << " X0 " << fX0GH / (g/cm2)
238  << " +/- " << fX0GH_error / (g/cm2) << endl;
239 
240  cout << "Energy Estimate from Nmax[Gev] " << fNmaxGH / 1.3 << endl;
241 
242 }
243 
244 
247 {
248  return eSuccess;
249 }
250 
251 
252 void
253 FdEnergyFinder::MinuitFitFunction(int& /*npar*/, double* /*gin*/, double& f,
254  double* par, int /*iflag*/)
255 {
256  // Eventually need maximum likelihood. But for now,
257  // calculate chisq bin by bin, and ignore empty bins. Statistics
258  // may not be quite correct for small pe numbers, but near enough.
259 
260  double chisq = 0;
261 
262  double Nmax= exp(par[0]);;
263  double Xmax= par[1]; ;
264  double X0 = par[2];;
265 
266  int ndof_chisq =0;
267  double size = 0.;
268 
269  const unsigned int npoints = fLongProfile->GetNPoints();
270  for (unsigned int i=4; i<npoints; i++){
271 
272  double X = fLongProfile->GetX(i);
273  double n_e = fLongProfile->GetY(i);
274  double n_e_err = fLongProfile->GetYErr(i);
275 
276  if (X>X0 && Xmax>0) {
277  size = Nmax*pow((X-X0)/(Xmax-X0),(Xmax-X0)/kLambdaGH)*exp((Xmax-X)/kLambdaGH);
278  chisq += pow((n_e - size)/ n_e_err,2);
279  ndof_chisq++;
280  } // if X
281 
282  }// for points
283 
284  if (ndof_chisq < 1) chisq = 9999;
285 
286  f = chisq;
287 
288  fChisqGH = f;
289  fNdof = (ndof_chisq - 3);
290 }
291 
293 
294  if (fMinuitFailed) {
295  fEemGH = 0;
296  return;
297  }
298 
299  /*
300  double alpha = (fXmaxGH - fX0GH)/kLambdaGH;
301 
302  if(fNmaxGH <= 0. || fXmaxGH <= 0. || alpha <= 0.) {
303  fEemGH = 0.;
304  return;
305  }
306 
307  if(alpha >= 40.)
308  alpha = 40.; // avoids overflows in gh_gamma
309 
310  double gamma = fGHParameters->GammaIntegral(alpha);
311  */
312 
313  //BRD New Eem calculation using mean dE/dX
314  double size = 0;
315  double sum_size=0;
316  double sum_dEdX=0;
317  for (unsigned int i=0; i<50; i++){
318  double X = i*40.*(g/cm2);
319  if (X>fX0GH && fXmaxGH>0) {
320  size = GaisserHillas(X, fX0GH, fXmaxGH, fNmaxGH, kLambdaGH);
321  sum_size += size;
322  //BRD NOTE!
323  //double fEnergyCutoff = 1.0*MeV;
324  sum_dEdX += size*EnergyDeposit(X, fXmaxGH, fEnergyCutoff);
325  }
326  }
327  double mean_dEdX=0.;
328  if (sum_size)
329  mean_dEdX = sum_dEdX/sum_size;
330  cout << "Mean dEdX " << mean_dEdX/(MeV/(g/cm2)) << endl;
331  //fEemGH = gamma * fNmaxGH * kLambdaGH * mean_dEdX;
332  //
335 
336  fEemGH = fGHParameters->GetIntegral() * mean_dEdX;
337 
338 }
339 
340 
342 
343  if (fMinuitFailed) {
344  fEemGH_error = 9.9e99;
345  return;
346  }
347 
348  fEemGH_error = fEemGH * fGHParameters->GetIntegralError();
349 
350  /*
351  double alpha = (fXmaxGH - fX0GH)/kLambdaGH;
352 
353  if (fXmaxGH_error == 0. && fX0GH_error == 0. ){
354  fEemGH_error = 9.9e99;
355  return;
356  }
357 
358  double alpha_error = sqrt(fXmaxGH_error*fXmaxGH_error
359  + fX0GH_error*fX0GH_error) / kLambdaGH;
360 
361 
362  double alpha1 = alpha + alpha_error;
363  double alpha2 = alpha - alpha_error;
364 
365  if(fNmaxGH <= 0. || fXmaxGH <= 0. || alpha <= 0. || alpha2 <= 0. )
366  {
367  fEemGH_error = 9.9e99;
368  return;
369  }
370 
371  if(alpha >= 40.) alpha = 40.; //avoids overflows in gh_gamma
372 
373  if(alpha1 >= 40.) alpha1 = 40.; //avoids overflows in gh_gamma
374 
375  double gamma = fGHParameters->GammaIntegral(alpha);
376 
377  double gamma1 = fGHParameters->GammaIntegral(alpha1);
378 
379  double gamma2 = fGHParameters->GammaIntegral(alpha2);
380 
381 
382  double f1 = (gamma1-gamma2)/gamma/2;
383  double f2 = fNmaxGH_error/fNmaxGH;
384  fEemGH_error = sqrt(f1*f1 + f2*f2);
385  fEemGH_error *= fEemGH;
386  */
387 
388 }
389 
390 
391 void
393 {
394  using namespace utl::InvisibleEnergy;
395  const EInteractionModel model =
396  (fUnseenEnergyModel == 1) ? eQGSJET01 : eSIBYLL21;
397 
398  ECompositionModel compo;
399  if (fComposition == 1)
400  compo = eProton;
401  else if (fComposition == 2)
402  compo = eIron;
403  else
404  compo = eMixedComposition;
405 
406  double dummycostheta=0.7071067; //this module does not use the data based invisible energy, so theta is not required
407  fEtotalGH = fEemGH * Factor(fEemGH, model, compo,dummycostheta);
408 }
409 
410 
411 // /*!
412 
413 // RETURN total energy BY USING Eem/ETotal BASED ON CORSIKA SHOWER MONTE CARLO
414 // (QGSJET MODEL). CHS 6/18/98
415 // NEW PARAMERIZATION HAVE BEEN DONE. THE THRESHOLD ENERGY OF ELECTRON
416 // AND PHOTON BOTH IS 100 KeV(FROM 3 MeV ). CHS 11/09/98
417 // Ref: "Primary Energy Reconstruction through Fluorescence Light Detection"
418 // tech note by Chihwa Song.
419 // 1 Dec 1998: Mod by BRD
420 // Reduce "missing energy" by 5% for all energies/primaries. Chihwa
421 // has shown that about 10% of primary energy ends up as sub-Mev gamma
422 // -rays. These will not participate in cascading, but will produce
423 // energetic e's thru Compton scattering and photoelectric effect.
424 // We have not evaluated how much of this ~10% will make it into
425 // visible energy - guess 5%, then we can only be a few % wrong.
426 
427 // @note takes energy in GeV, which is not auger-convention correct
428 // */
429 // void FdEnergyFinder::FindTotalEnergy(double Eem){
430 
431 // const int nx = 6;
432 // //std::vector<double> xa;
433 // //std::vector<double> ya;
434 // double xa[nx+1];
435 // double ya[nx+1];
436 // double minlog10energy = 0.;
437 // double maxlog10energy = 0.;
438 
439 // // Paramerization
440 // // Mean between proton and iron
441 // const double mixed_parameters[3][7]={{ 0,0,0,0,0,0,0},
442 // { 0, 7.342, 7.877, 8.364, 8.895, 9.379, 9.907},
443 // { 0, 0.733, 0.754, 0.770, 0.786, 0.797, 0.807}};
444 // // For proton
445 // const double proton_parameters[3][7]={{0,0,0,0,0,0,0},
446 // {0, 7.366, 7.895, 8.379, 8.908, 9.389, 9.915},
447 // {0, 0.775, 0.786, 0.797, 0.810, 0.816, 0.823}};
448 // // For iron
449 // const double iron_parameters[3][7]={{0,0,0,0,0,0,0},
450 // {0, 7.317, 7.858, 8.348, 8.881, 9.368, 9.898},
451 // {0, 0.691, 0.721, 0.742, 0.761, 0.777, 0.790}};
452 
453 
454 // // Get energy conversion factor for given primary particle type
455 // if (fComposition == 0)
456 // {
457 // for (int i=1; i<=nx; i++)
458 // {
459 // xa[i] = mixed_parameters[1][i];
460 // ya[i] = mixed_parameters[2][i];
461 // }
462 // minlog10energy = 7.342;
463 // maxlog10energy = 9.907;
464 // }
465 // else if (fComposition == 1)
466 // {
467 // for (int i=1; i<=nx; i++)
468 // {
469 // xa[i] = proton_parameters[1][i];
470 // ya[i] = proton_parameters[2][i];
471 // }
472 // minlog10energy = 7.366;
473 // maxlog10energy = 9.915;
474 // }
475 // else if (fComposition == 2)
476 // {
477 // for (int i=1; i<=nx; i++)
478 // {
479 // xa[i] = iron_parameters[1][i];
480 // ya[i] = iron_parameters[2][i];
481 // }
482 // minlog10energy = 7.317;
483 // maxlog10energy = 9.898;
484 // }
485 // else
486 // {
487 // cerr << "Error by FdEnergyFinder: primary type must be 0, 1 or 2"
488 // << endl;
489 // return;
490 // }
491 
492 
493 // // If Eem is out of range, use the value at end point
494 
495 // double log10E = log10(Eem);
496 
497 // if (log10E < minlog10energy)
498 // {
499 // log10E = minlog10energy;
500 // WARNING("Eem is out of range");
501 // }
502 // else if (log10E > maxlog10energy)
503 // {
504 // log10E = maxlog10energy;
505 // WARNING("Eem is out of range");
506 // }
507 
508 // double Eem_to_Etot = PolinomialInterpolation(xa, ya, nx, log10E);
509 
510 // // Add extra 5% to visible energy (see note at top. BRD 1 Dec 98)
511 
512 // Eem_to_Etot *= 1.05;
513 
514 // fEtotalGH = Eem/Eem_to_Etot * GeV;
515 
516 
517 // }
518 
519 
520 // Polynomial function interpolation and extrapolation from
521 // Numerical Recipes
522 // double FdEnergyFinder::PolinomialInterpolation(double xa[], double ya[],
523 // int n, double exp){
524 
525 // const int nmax = 10;
526 // int ns = 0;
527 // double diff_i = 0.;
528 // double c[nmax];
529 // double d[nmax];
530 // double Pol_Int = 0.;
531 // double dPol_Int = 0.;
532 // double den, ho, hp, w;
533 
534 // ns = 1;
535 // double diff_1 = abs(exp-xa[1]);
536 // for (int i=1; i<=n; i++)
537 // {
538 // diff_i = abs(exp-xa[i]);
539 // if (diff_i < diff_1)
540 // {
541 // ns = i;
542 // diff_1 = diff_i;
543 // }
544 // c[i] = ya[i];
545 // d[i] = ya[i];
546 // }
547 
548 // Pol_Int = ya[ns];
549 // ns = ns - 1;
550 
551 // for (int m=1; m<=n-1; m++)
552 // {
553 // for (int i=1; i<=n-m; i++)
554 // {
555 // ho = xa[i] - exp;
556 // hp = xa[i+m] - exp;
557 // w = c[i+1] - d[i];
558 // den = ho - hp;
559 // if (den == 0)
560 // {
561 // cerr << "Fatal error by PolinomialInterpolation: denominator = 0" << endl;
562 // exit(1);
563 // }
564 // den = w/den;
565 // d[i] = hp*den;
566 // c[i] = ho*den;
567 // }
568 // if (2*ns < n-m)
569 // dPol_Int = c[ns+1];
570 // else
571 // {
572 // dPol_Int = d[ns];
573 // ns = ns - 1;
574 // }
575 
576 // Pol_Int = Pol_Int + dPol_Int;
577 // }
578 
579 // return Pol_Int;
580 
581 // }
582 
583 // Configure (x)emacs for this file ...
584 // Local Variables:
585 // mode:c++
586 // compile-command: "make -C .. -k"
587 // End:
double Factor(const double energyEM, const EInteractionModel intMod, const ECompositionModel compMod, const double cosTheta)
invisible energy factor, finv=Etot/Eem, given Eem. CosTheta only needed when using data driven estima...
static void MinuitFitFunction(int &npar, double *gin, double &f, double *par, int iflag)
static const utl::TabulatedFunctionErrors * fLongProfile
bool HasFEvent() const
const unsigned int npar
Definition: UnivRec.h:75
boost::filter_iterator< ComponentSelector, AllEyeIterator > EyeIterator
selective Eye iterators
Definition: FEvent.h:55
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double pow(const double x, const unsigned int i)
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
constexpr double MeV
Definition: AugerUnits.h:184
Class representing a document branch.
Definition: Branch.h:107
bool HasLongitudinalProfile() const
EyeIterator EyesBegin(const ComponentSelector::Status status)
Definition: FEvent.h:58
constexpr double g
Definition: AugerUnits.h:200
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
void SetEmEnergy(const double energy, const double energyError, const EUncertaintyType type=eTotal)
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
double GaisserHillas(const double x, const double x0, const double xMax, const double nMax, const double lambda)
Calculate the Gaisser-Hillas function.
fevt::FEvent & GetFEvent()
bool HasGHParameters() const
constexpr double GeV
Definition: AugerUnits.h:187
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
utl::TabulatedFunctionErrors & GetLongitudinalProfile()
retrieve longitudinal profile information (size vs depth)
constexpr double kLambdaGH
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
double EnergyDeposit(const double age, const double enCut)
Parametrization for the average energy deposit per particle.
Interface class to access to Fluorescence reconstruction of a Shower.
Main configuration utility.
Definition: CentralConfig.h:51
Gaisser Hillas with 4 parameters.
void SetTotalEnergy(const double energy, const double energyError, const EUncertaintyType type=eTotal)
void MakeGHParameters(const VGaisserHillasParameter &gh)
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
double GetEnergyCutoff() const
retrieve energy cutoff for which the profile of charged particles was calculated. ...
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
constexpr double cm2
Definition: AugerUnits.h:118

, generated on Tue Sep 26 2023.