source: JEM-EUSO/esaf_lal/tags/v1_r0/esaf/packages/simulation/generators/showers/src/SlastShowerGenerator.cc @ 117

Last change on this file since 117 was 117, checked in by moretto, 11 years ago

ESAF version compilable on mac OS

File size: 46.5 KB
Line 
1// ESAF : Euso Simulation and Analysis Framework
2// $Id: SlastShowerGenerator.cc 2991 2011-09-26 10:08:50Z mabl $
3// Author: Dmitry V.Naumov  03/03/2004
4
5/*****************************************************************************
6 * ESAF: Euso Simulation and Analysis Framework                              *
7 *                                                                           *
8 *  Id: SlastShowerGenerator                                                 *
9 *  Package: Shower                                                          *
10 *  Coordinator: Sergio.Bottai, Dmitry Naumov                                *
11 *                                                                           *
12 *****************************************************************************/
13
14//_____________________________________________________________________________
15//
16// SlastShowerGenerator
17//
18// Slast is short of "Shower Light Attenuated to the Space Telescope".
19// Originally written by Dmitry V.Naumov as a collection of F77 routines doing
20// the full chain:
21// Shower generation, light production (fluorescence and cherenkov), light
22// attenuation in the atmosphere.
23// See SlastLightToEuso C++ / Fortran interface which is doing the full chain.
24//
25// SlastShowerGenerator is the simple generator written in pure C++ which is
26// NOT doing the full simulation chain. Instead it returnes only the
27// ShowerTrack object which is taken later by ShowerLightSource and
28// RadiativeTransfer parts of the ESAF package.
29//
30// ESAF prodides some testing macros which can help to understand how to use
31// SlastShowerGenerator.  See macros/CheckDistrs.C as an example.
32//
33// A simple way to use SlastShowerGenerator is directly in root:
34//
35// root[]   gSystem->Load("libatmosphere.so");
36// root[]   gSystem->Load("libgenbase.so");
37// root[]   gSystem->Load("libshowers.so");
38// root[]   SlastShowerGenerator *ShowerGenerator = new SlastShowerGenerator;
39// root[]   ShowerTrack *track = ShowerGenerator->Get();
40// root[]   track->DrawXYZ()
41//
42// as an example.
43//
44// Now having the track object in hand one can use whatever functions avalaible
45// for it. See ShowerTrack class for documentation of ShowerTrack object
46
47#include "SlastShowerGenerator.hh"
48#include "EsafRandom.hh"
49#include "MCTruth.hh"
50#include "ShowerTrack.hh"
51#include "Atmosphere.hh"
52#include "Config.hh"
53#include "EConst.hh"
54#include <TMath.h>
55#include <TRandom.h>
56#include <TProfile.h>
57#include <TH1F.h>
58#include <TGraph.h>
59#include "NumbersFileParser.hh"
60
61ClassImp(SlastShowerGenerator)
62using namespace TMath;
63using namespace sou;
64using namespace EConst;
65
66//_________________________________________________________________________________________
67SlastShowerGenerator::SlastShowerGenerator(Bool_t quiet) : EventGenerator("slast++"), EsafMsgSource(),
68                           fTrack(0), fTruth(0), fInCome(0), fOutCome(0), fQuiet(kFALSE)  {
69    // This is ctor
70    fQuiet = quiet; 
71    fSpectrumRdnm = 0;
72    fEnergy = -1;
73    if(!Init()) Msg(EsafMsg::Panic)<<"SlastShowerGenerator can not be initialized"<<MsgDispatch;
74}
75
76
77//_________________________________________________________________________________________
78Bool_t SlastShowerGenerator::Init() {
79    //
80    // SlastShowerGenerator is initialized reading from config/LightToEuso/GeneratorLightToEuso.cfg file
81    // Edit that file to setup desired parameters of the showers such as energy, theta, phi intervals
82    // or initial position in case of unique parameters.
83    // Init() is called in SlastShowerGenerator ctor
84    //
85   
86    // General Shower Generator initializations
87    ConfigFileParser *pConfig = Config::Get()->GetCF("LightToEuso","GeneratorLightToEuso");
88    fFoV          = pConfig->GetNum("GeneratorLightToEuso.FoV")*deg;
89    fSpectrumType = pConfig->GetStr("GeneratorLightToEuso.SpectrumType");
90    fEnergyMin = pConfig->GetNum("GeneratorLightToEuso.EnergyRangeMin");
91    fEnergyMax = pConfig->GetNum("GeneratorLightToEuso.EnergyRangeMax");
92    fEnergySlope = pConfig->GetNum("GeneratorLightToEuso.EnergySlope");
93    fThetaMin  = pConfig->GetNum("GeneratorLightToEuso.ThetaRangeMin")*deg;
94    fThetaMax  = pConfig->GetNum("GeneratorLightToEuso.ThetaRangeMax")*deg;
95    fPhiMin    = pConfig->GetNum("GeneratorLightToEuso.PhiRangeMin")*deg;
96    fPhiMax    = pConfig->GetNum("GeneratorLightToEuso.PhiRangeMax")*deg;
97    fType      = pConfig->GetStr("GeneratorLightToEuso.UhecrType");
98    fDepthStep = pConfig->GetNum("GeneratorLightToEuso.DepthStep")*g/cm2;
99    fFirstPointX = pConfig->GetNum("GeneratorLightToEuso.InteractionVectorX")*km;
100    fFirstPointY = pConfig->GetNum("GeneratorLightToEuso.InteractionVectorY")*km;
101    fFirstPointZ = pConfig->GetNum("GeneratorLightToEuso.InteractionVectorZ")*km;
102    fFirstType = pConfig->GetStr("GeneratorLightToEuso.InteractionType");
103    fEusoAltitude = pConfig->GetNum("GeneratorLightToEuso.altitude")*km; //TOFIX : to be changed when more general FoV handling achieved
104    fEusoVector.SetXYZ(0,0,fEusoAltitude);
105    fRejectFakeEvents = pConfig->GetBool("GeneratorLightToEuso.RejectFakeEvents");
106    fRejectNoXmax = pConfig->GetBool("GeneratorLightToEuso.RejectNoXmax");
107    if(!fRejectFakeEvents && fRejectNoXmax)
108         Msg(EsafMsg::Panic) << "<Init> if RejectFakeEvents not required, RejectNoXmax cannot be required" << MsgDispatch;
109   
110    // check if bounds are > 1deg -- EXCEPTED in "POS" option of fFirstType
111    if((fThetaMax - fThetaMin) < kTolerance && fFirstType != "POS") {
112        Msg(EsafMsg::Warning) << "<Init> theta bounds width cannot be zero : theta max increased by 1 degree" << MsgDispatch;
113        fThetaMax += 1*DegToRad();
114    }
115    if((fPhiMax - fPhiMin) < kTolerance && fFirstType != "POS") {
116        Msg(EsafMsg::Warning) << "<Init> phi bounds width cannot be zero : phi max increased by 1 degree" << MsgDispatch;
117        fPhiMax += 1*DegToRad();
118    }
119
120    if (!fQuiet) {
121        Msg(EsafMsg::Info) << "SlastShowerGenerator Enabled" << MsgDispatch;
122        Msg(EsafMsg::Info) << "SlastShowerGenerator Enables Atmosphere " << Atmosphere::Get()->GetType() << MsgDispatch;
123        MsgForm(EsafMsg::Info,"Generate %s event(s) in:",fType.c_str());
124        MsgForm(EsafMsg::Info,"Energy interval [%.4E,%.4E]",fEnergyMin,fEnergyMax);
125        MsgForm(EsafMsg::Info,"Theta  interval [%.4f,%.4f]",fThetaMin,fThetaMax);
126        MsgForm(EsafMsg::Info,"Phi    interval [%.4f,%.4f]",fPhiMin,fPhiMax);
127    }
128    else {
129        MsgForm(EsafMsg::Debug,"Generate %s event(s) in:",fType.c_str());
130        MsgForm(EsafMsg::Debug,"Energy interval [%.4E,%.4E]",fEnergyMin,fEnergyMax);
131        MsgForm(EsafMsg::Debug,"Theta  interval [%.4f,%.4f]",fThetaMin,fThetaMax);
132        MsgForm(EsafMsg::Debug,"Phi    interval [%.4f,%.4f]",fPhiMin,fPhiMax);
133
134    }
135    fAtomicMass = AtomicMass(fType);
136   
137    // if non-analytical RC spectrum
138    if(fSpectrumType == "GZKHiRes2005") {
139        // GZK shape from best fit of HiRes data ( Phys. Lett. B 619 (2005) )
140        // graph is recopied "by hand" using g3data software
141        // between 1e19-1e21 eV only
142        if(fEnergyMin < 1e19 || fEnergyMax > 1e21)
143            Msg(EsafMsg::Panic) << "<Init> GZKHiRes2005 spectrum stands within [1e19 - 1e21] only !" << MsgDispatch;
144        NumbersFileParser nf("config/Tools/GZKHiRes2005.dat",2);
145        vector<Double_t> log10E_v   = nf.GetCol(0);  // expressed in eV
146        vector<Double_t> fluxE3_v   = nf.GetCol(1);  // expressed in 10^24 eV2.m-2.s-1.sr-1
147        TArrayD log10E(log10E_v.size()), fluxE3(log10E_v.size());
148        for(size_t i=0; i < log10E_v.size(); i++) {
149            log10E[i] = log10E_v[i];
150            fluxE3[i] = fluxE3_v[i];
151        }
152        TGraph* gr = new TGraph(log10E_v.size(),log10E.GetArray(),fluxE3.GetArray());
153        fSpectrumRdnm = new TH1F("GZK","GZK",10000,Log10(fEnergyMin),Log10(fEnergyMax));
154        for(Int_t i=0; i < 10000; i++) {
155            fSpectrumRdnm->SetBinContent(i+1,gr->Eval(fSpectrumRdnm->GetBinCenter(i+1),0,"") * log(10.) / pow(10,fSpectrumRdnm->GetBinCenter(i+1)*2. - 24.));
156        }
157    }
158   
159   
160    // Initialize SLAST specific options
161    pConfig = Config::Get()->GetCF("LightToEuso","SlastLightToEuso");
162    fEnergyDistribution    = pConfig->GetStr("SlastLightToEuso.EnergyDistributionParametrization");
163    fShowerParametrization = pConfig->GetStr("SlastLightToEuso.ShowerParametrization");
164    return kTRUE;
165}
166
167//_________________________________________________________________________________________
168SlastShowerGenerator::~SlastShowerGenerator() {
169//  This is dtor
170    SafeDelete(fTrack);
171    SafeDelete(fTruth);
172    SafeDelete(fSpectrumRdnm);
173}
174
175//_________________________________________________________________________________________
176void SlastShowerGenerator::SetShower(Double_t e,Double_t t,Double_t p,EarthVector pos) {
177    // This is a special method to setup desired showertrack parameters from the code (not from the config file)
178    // This can be a usefull function in the reconstruction code
179   
180    SetEnergy(fEnergyMin = fEnergyMax = e); 
181    SetTheta(fThetaMin = fThetaMax = t);
182    SetPhi(fPhiMin = fPhiMax = p);
183    fFirstPointX = pos.X();
184    fFirstPointY = pos.Y();
185    fFirstPointZ = pos.Z();
186    fFirstType = "POS";
187}
188
189//_________________________________________________________________________________________
190void SlastShowerGenerator::GetX1() {
191    //
192    // Returns atmosphere depth before the first interaction.
193    // Attention: units are ESAF internal. In order to get in human way one has to multiple by cm2/g
194    //
195   
196    if ( fFirstType == "POS" ) {
197        fX1 = Atmosphere::Get()->Grammage(fInitPoint,-fOmega,"dir");
198    }
199    else if (fFirstType == "X1" ) {
200        ConfigFileParser *pConfig = Config::Get()->GetCF("LightToEuso","GeneratorLightToEuso");
201        fX1      = pConfig->GetNum("GeneratorLightToEuso.InteractionX1")*g/cm2;
202    }
203    else {
204        TRandom *rndm = EsafRandom::Get();
205        fX1 =  -Log(rndm->Rndm())*HadronInteractionLength(fAtomicMass,fEnergy)*g/cm2;
206    }
207}
208
209//_________________________________________________________________________________________
210Double_t SlastShowerGenerator::HadronInteractionLength(Double_t A, Double_t E) {
211    // SlastShowerGenerator internal function which computes the hadronic interactio  length.
212    // Used by GetX1() method
213    Float_t R0 = 1.287e-13, Aair = 14.483,  q = 0.93, AN = 14.00674, AO = 15.9994;
214    Float_t AA = 39.948, AC = 12.011, CN = 0.7847, CO = 0.2105, CA = 0.0047, CC = 0.0001;
215    Float_t S_A = Pi()*Power(R0,2);
216    Float_t F_A1 = Power(S_A*Na(),-1);
217    Float_t F_A2 = Aair*F_A1;
218    Float_t X = Power(A,1./3);
219    Float_t Y = 1./X;
220    Float_t B = Power(AN,1./3);
221    Float_t S = CN*Power(B+X-q*(1./B+Y),2); // Nitrogen (N2);
222    B  = Power(AO,1./3);
223    S += CO*Power(B+X-q*(1./B+Y),2);     // Oxigen (O2)
224    B  = Power(AA,1./3);
225    S += CA*Power(B+X-q*(1./B+Y),2);     // Argon (Ar)
226    B  = Power(AC,1./3);
227    S += CC*Power(B+X-q*(1./B+Y),2);     // Carbon (in CO2)
228    return F_A2/S*NucleonAirCrossSection(1.e11/A)/NucleonAirCrossSection(E/A);
229}
230
231//_________________________________________________________________________________________
232Double_t SlastShowerGenerator::NucleonAirCrossSection(Double_t E) {
233    /*
234    Computes NUCLEN + AIR CROSS SECTION:
235        ... USES AN EMPIRICAL PARAMETRIZATION OF TOTAL INELASTIC
236        ... NUCLEON AIR CROSS SECTION (in mbarn)
237        ... INPUT:  NUCLEON ENERGY in eV
238        ... OUTPUT: NUCLEON AIR CROSS SECTION (in mbarn)
239        ... REFERENCES:
240        ... 1. Mielke H.H., Foller, M, Knapp J.
241        ...    // J.Phys.G: Nucl.Part.Phys. 1994. V 20, P637
242        ... 2. V.A. Naumov, T.S. Sinegovskaya (eq (17))
243    */
244    return 290 - 8.7*Log(E*1.e-9) + 1.14*Power(Log(E*1.e-9),2);
245}
246
247//_________________________________________________________________________________________
248const ShowerStep& SlastShowerGenerator::GetShowerStep() {
249    // Filling the ShowerStep object with relevant information
250    fStep.Clear();
251    fStep.fXi = fXcurrent + fX1;
252    fStep.fXf = fXnext + fX1;
253    fStep.fXYZi = fCurrentPoint;
254    fStep.fXYZf = fNextPoint;
255    fStep.fTimei = fTimecurrent;
256    fStep.fTimef = fTimenext;
257    GetShowerParametrization(fXcurrent);
258    fStep.fAgei = fAge;
259    GetShowerParametrization(fXnext);
260    fStep.fAgef = fAge;
261    GetShowerParametrization((fXnext+fXcurrent)/2);
262    fStep.fNelectrons = fNe;
263    return fStep;
264}
265
266//_________________________________________________________________________________________
267void SlastShowerGenerator::GetShowerParametrization(Double_t x) {
268    //
269    // Assigning of fNe - number of electrons in the current step according to the Shower Parameterization.
270    //  GIL stands for Greizen-Ilina-Linsley which is the QGSJET model
271    // parameterization.
272    // GFA stands for Gaussian Function in Age
273    // GHF stands for Gaisser Hillas Function
274    //
275   
276    if (fShowerParametrization == "GIL")      GIL(x);
277    else Msg(EsafMsg::Panic) << "<GetShowerParametrization> Only GIL formula available so far" <<MsgDispatch;
278    //TOFIX : GFA and GHF not coded correctly, they do not included X1 fluctuations
279    /*
280    else if (fShowerParametrization == "GFA") GFA(x + fX1); 
281    else if (fShowerParametrization == "GHF") GHF(x + fX1);
282    else Msg(EsafMsg::Panic) << "<GetShowerParametrization> Wrong argument for ShowerParametrization :"
283         << fShowerParametrization <<MsgDispatch;
284    */
285}
286
287//_________________________________________________________________________________________
288Bool_t SlastShowerGenerator::FindImpactOnTOA() {
289    //
290    // Generates point uniformly on top of atmosphere on the upper part of the earth hemisphere
291    // theta, phi angles are taken at TOA impact, then translated into MES frame for further steps of event simulation
292    //
293
294    TRandom *rndm = EsafRandom::Get();
295    ConfigFileParser* pConfig = Config::Get()->GetCF("LightToEuso","GeneratorLightToEuso");
296    string ImpactMode = pConfig->GetStr("GeneratorLightToEuso.ImpactMode");
297    string thetaMode  = pConfig->GetStr("GeneratorLightToEuso.ThetaMode");
298    const Atmosphere* atmo = Atmosphere::Get();
299   
300   
301#ifdef DEBUG
302Int_t counterr = 0;
303#endif
304   
305   
306    // find impact on TOA, then find impact at sea level if any. Otherwise, set earthimpact to ******* TOA outgoing point **********
307    // principle : - uniform distribution on a sphere of radius EarthRadius + TOA_altitude
308    //             - sin(2theta) distribution, phi uniform distribution (LOCAL angles, at TOA impact centered frame)
309    //             - check if defined track cut the EUSO FoV cone, if NOT  --> re-try
310    if(ImpactMode == "TOA") {
311        Double_t TOA_alt  = atmo->GetTOAAltitude();
312        Double_t Euso_alt = fEusoVector.Z();
313        Double_t FoV_radius = Euso_alt * Tan(fFoV + 1*deg);
314        Double_t L1 = Sqrt( (EarthRadius() + TOA_alt)*(EarthRadius() + TOA_alt) - EarthRadius()*EarthRadius() );
315        Double_t Zmin,x,y,z;
316        Zmin = EarthRadius()*Sqrt(1 + 2*TOA_alt/EarthRadius() + (TOA_alt*TOA_alt - FoV_radius*FoV_radius)/(EarthRadius()*EarthRadius()));
317        Zmin -= 2*L1 * Sqrt(1 - EarthRadius()*EarthRadius() / (EarthRadius() + TOA_alt) / (EarthRadius() + TOA_alt));
318
319#ifdef DEBUG
320//cout << "********** Zmin = "<<Zmin <<endl;
321
322// *********** if EUSO tilted mode, Zmin is different. The rest of the code (FoV intersection etc..) should be adapted too *********
323/*
324else if(ImpactMode == "TOA_tiltedEuso") {
325Double_t L2 = Sqrt( (EarthRadius() + Euso_alt)*(EarthRadius() + Euso_alt) - EarthRadius()*EarthRadius() );
326Zmin = EarthRadius() + Euso_alt;
327Zmin -= (L1 + L2) * Sqrt(1 - EarthRadius()*EarthRadius() / (EarthRadius() + Euso_alt) / (EarthRadius() + Euso_alt));
328}
329*/
330#endif
331       
332        // find a good candidate shower, which has an opportunity to be seen by EUSO
333        Bool_t eventisfound = kFALSE;
334        Int_t infloop = 0;
335        while(!eventisfound) {
336#ifdef DEBUG
337counterr++;
338#endif
339            // prevent infinite loop
340            if(infloop++ > 100000) {
341                Msg(EsafMsg::Warning) << "<FindImpactOnTOA> TOA impact mode : Inifinite loop broken by hand" << MsgDispatch;
342                return kFALSE;
343            }
344           
345            // 1. get an impact on TOA, uniformly distributed on the upper part of a sphere
346            //    cut in Z (i.e. Zmin, expressed in earth-centered frame) is determined from geometrical considerations
347            z            = (EarthRadius()+TOA_alt - Zmin)*rndm->Rndm() + Zmin;
348            Double_t phi = rndm->Rndm()*TwoPi();
349            x            = EarthRadius()*Sin(ACos(z / (EarthRadius()+TOA_alt) ))*Cos(phi);
350            y            = EarthRadius()*Sin(ACos(z / (EarthRadius()+TOA_alt) ))*Sin(phi);         
351
352
353            // 2. Generate random Theta and Phi w.r.t. local frame
354            // sin(2x) OR linear OR Hmax modes
355            // last one achieves flat Hmax distribution, at E=1e20eV with USStd  ->  theta in [0,70], comes from Hmax = 1.89 - 7.59*log(cos(th))
356            fPhi_local = (TwoPi() - 0)*rndm->Rndm() + 0;
357            if(thetaMode == "sinus") {
358                Double_t r1 = 1.;  // cos(2*0)
359                Double_t r2 = -1.; // cos(2*halfpi)
360                fTheta_local = 0.5*ACos(r1 - rndm->Rndm()*(r1-r2));
361            }
362            else if(thetaMode == "linear") fTheta_local = (PiOver2() - 0)*rndm->Rndm() + 0;
363            else if(thetaMode == "FlatHmax") fTheta_local = ACos( Exp((1.89 - 10)*rndm->Rndm() / 7.59));
364            else Msg(EsafMsg::Panic) << "Wrong argument for theta Mode  ->  " <<thetaMode << MsgDispatch;
365       
366       
367            // 3. Change fOmega from local frame to MES frame, using impact on TOA as the reference vector
368            EarthVector TOA_impact_try(x,y,z);  // in earth-centered frame
369            EarthVector v1 = TOA_impact_try.Unit();
370            EarthVector vrot;
371            fOmega.SetXYZ(1,0,0);
372            EarthVector Uz(0,0,1);
373            vrot = Uz.Cross(v1);
374            if(vrot.Mag() > kTolerance) {
375                fOmega.Rotate(v1.Theta(),vrot);
376                fOmega.Rotate(fPhi_local,v1);
377                vrot = v1.Cross(fOmega);
378                fOmega.Rotate(PiOver2()+fTheta_local,vrot);
379            }
380            else fOmega.SetMagThetaPhi(1.,Pi() - fTheta_local,fPhi_local + Pi());
381           
382            // set angles in MES frame + check if they are within required bounds
383            fTheta_mes = Pi() - fOmega.Theta();
384            if(fTheta_mes < fThetaMin || fTheta_mes > fThetaMax) continue;
385           
386            // to get phi in [0,2pi]  (root returns it within [-pi,pi])
387            if(fOmega.Phi() < 0) fPhi_mes = (fOmega.Phi() + TwoPi()) - Pi();
388            else                 fPhi_mes = fOmega.Phi() + Pi();
389            if(fPhi_mes < fPhiMin || fPhi_mes > fPhiMax) continue;
390           
391           
392            // returns in MES frame
393            TOA_impact_try.SetZ(TOA_impact_try.Z() - EarthRadius()); 
394
395
396            fOutOfFoV = kFALSE;
397            EarthVector intersection, impactASL;
398            // 4. FoV handling
399            if(IsInFoV(TOA_impact_try))  eventisfound = kTRUE;  // look if TOA impact is in FoV
400            else if(!fRejectFakeEvents) {
401                // event always kept in this case
402                EarthVector intersection = FoVintersection(TOA_impact_try,fOmega);
403                EarthVector impactASL    = atmo->ImpactASL(TOA_impact_try,fOmega);
404                // check
405                //    - if track cuts the EUSO FoV
406                //    - if intersection is above ground
407                //    - if intersection is below TOA
408                //    - if track has reached ground before intersection
409                intersection = FoVintersection(TOA_impact_try,fOmega);
410                impactASL    = atmo->ImpactASL(TOA_impact_try,fOmega);
411                if(intersection.Z() == -HUGE || intersection.Z() == HUGE || intersection.IsUnderSeaLevel()) fOutOfFoV = kTRUE;
412                // check if intersection is below TOA altitude
413                else if(intersection.Zv() > TOA_alt) fOutOfFoV = kTRUE;
414                // check if track reaches ground before its intersection with euso FoV cone
415                else if((impactASL - TOA_impact_try).Mag() < (intersection - TOA_impact_try).Mag()) fOutOfFoV = kTRUE;
416                eventisfound = kTRUE;
417            }
418            else {
419                // track is kept
420                //    - if track cuts the EUSO FoV
421                //    - if intersection is above ground
422                //    - if intersection is below TOA
423                //    - if track has reached ground before intersection
424                intersection = FoVintersection(TOA_impact_try,fOmega);
425                impactASL    = atmo->ImpactASL(TOA_impact_try,fOmega);
426                if(intersection.Z() == -HUGE || intersection.Z() == HUGE || intersection.IsUnderSeaLevel()) continue;
427                // check if intersection is below TOA altitude
428                else if(intersection.Zv() > TOA_alt) continue;
429                // check if track reaches ground before its intersection with euso FoV cone
430                else if((impactASL - TOA_impact_try).Mag() < (intersection - TOA_impact_try).Mag()) continue;
431                else eventisfound = kTRUE;
432                fOutOfFoV = kFALSE;  // flag is disabled in 'fRejectFakeEvents == kTRUE' mode
433            }
434        }
435       
436       
437        // 5. a valid TOA impact has been found
438        fTOAImpact.SetXYZ(x,y,z - EarthRadius());
439
440#ifdef DEBUG
441Msg(EsafMsg::Debug) <<"********** Nb of trials = "<<counterr<<MsgDispatch;
442/*
443Msg(EsafMsg::Debug) <<"********** TOA found = "<<fTOAImpact<<MsgDispatch;
444Msg(EsafMsg::Debug) <<"********** TOA found = "<<fTOAImpact.Mag()<<", "<<fTOAImpact.Theta()*RadToDeg()<<", "<<fTOAImpact.Phi()*RadToDeg()<<MsgDispatch;
445
446Msg(EsafMsg::Debug) <<"********** LOCAL theta,phi = "<<fTheta_local*RadToDeg()<<", "<<fPhi_local*RadToDeg()<<MsgDispatch;
447Msg(EsafMsg::Debug) <<"********** direction found = "<<fOmega<<MsgDispatch;
448Msg(EsafMsg::Debug) <<"********** direction found = "<<fOmega.Mag()<<", "<<fOmega.Theta()*RadToDeg()<<", "<<fOmega.Phi()*RadToDeg()<<MsgDispatch;
449*/
450#endif
451
452
453        // 4. Find impact at sea level if exists
454        //    If it does not, set impact to outgoing point at TOA
455        fEarthImpact = atmo->ImpactASL(fTOAImpact,fOmega);
456        fHitGround = 0;
457        if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ImpactASL says fTOAImpact is under sea level" << MsgDispatch;
458        else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Debug) << "<FindImpactOnTOA> No ImpactASL found" << MsgDispatch;
459        else fHitGround = 1;
460       
461        if(fHitGround == 0) {
462            fEarthImpact = atmo->ImpactAtTOA(fTOAImpact,fOmega);
463            if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ImpactAtTOA says fTOAImpact is under sea level" << MsgDispatch;
464            else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Warning) << "<FindImpactOnTOA> No ImpactAtTOA found. IT SHOULD NOT OCCUR HERE" << MsgDispatch;
465        }
466    }
467       
468       
469       
470       
471       
472       
473    // find impact at sea level, then find impact on TOA
474    else if(ImpactMode == "ASL") {
475        Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ASL impact mode : Cosmic Ray LOCAL direction is taken at sea level" << MsgDispatch;
476        Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ASL impact mode : DOES NOT CHECK IF TRACK CUTS THE FOV" << MsgDispatch;
477
478        Int_t infloop = 0;
479        while(kTRUE) {
480            if(infloop++ > 100000) {
481                Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ASL impact mode : Inifinite loop broken by hand" << MsgDispatch;
482                return kFALSE;
483            }
484           
485            // 1. find impact at sea level
486            Double_t x,y,z;
487            Double_t Xmin = pConfig->GetNum("GeneratorLightToEuso.ImpactXmin")*km;
488            Double_t Ymin = pConfig->GetNum("GeneratorLightToEuso.ImpactYmin")*km;
489            Double_t Xmax = pConfig->GetNum("GeneratorLightToEuso.ImpactXmax")*km;
490            Double_t Ymax = pConfig->GetNum("GeneratorLightToEuso.ImpactYmax")*km;
491            x = rndm->Rndm()*(Xmax - Xmin) + Xmin;
492            y = rndm->Rndm()*(Ymax - Ymin) + Ymin;
493            z = sqrt(EarthRadius()*EarthRadius() - (x*x + y*y)); // needs -EarthRadius() before setting z !!
494
495            fEarthImpact.SetXYZ(x,y,z);
496            fEarthImpact.SetZ(fEarthImpact.Z() - EarthRadius());
497            fHitGround = 1;
498
499
500            // 2. Generate random Theta and Phi with respect to the MSS (local frame)
501            // sin(2x) OR linear OR Hmax modes
502            // last one achieving flat Hmax distribution, at E=1e20eV with USStd  ->  theta in [0,70], comes from Hmax = 1.89 - 7.59*log(cos(th))
503            fPhi_local = (TwoPi() - 0)*rndm->Rndm() + 0;
504            if(thetaMode == "sinus") {
505                Double_t r1 = 1.;  // cos(2*0)
506                Double_t r2 = -1.; // cos(2*halfpi)
507                fTheta_local = 0.5*ACos(r1 - rndm->Rndm()*(r1-r2));
508            }
509            else if(thetaMode == "linear") fTheta_local = (PiOver2() - 0)*rndm->Rndm() + 0;
510            else if(thetaMode == "FlatHmax") fTheta_local = ACos( Exp((1.89 - 10)*rndm->Rndm() / 7.59));
511            else Msg(EsafMsg::Panic) << "Wrong argument for theta Mode  ->  " <<thetaMode << MsgDispatch;
512
513
514            // 3. Change fOmega from local frame (MSS) to MES frame, using impact on ground as the reference vector
515            EarthVector v1(x,y,z);
516            v1 = v1.Unit();
517            EarthVector vrot;
518            fOmega.SetXYZ(1,0,0);
519            EarthVector Uz(0,0,1);
520            vrot = Uz.Cross(v1);
521            if(vrot.Mag() > kTolerance) {
522                fOmega.Rotate(v1.Theta(),vrot);
523                fOmega.Rotate(fPhi_local,v1);
524                vrot = v1.Cross(fOmega);
525                fOmega.Rotate(Pi()/2+fTheta_local,vrot);
526            }
527            else fOmega.SetMagThetaPhi(1.,Pi() - fTheta_local,fPhi_local + Pi());
528
529
530            // set angles in MES frame + check if they are within required bounds
531            fTheta_mes = Pi() - fOmega.Theta();
532            fOutOfFoV = kFALSE;
533            // to get phi in [0,2pi]  (root returns it within [-pi,pi]
534            if(fOmega.Phi() < 0) fPhi_mes = (fOmega.Phi() + TwoPi()) - Pi();
535            else                 fPhi_mes = fOmega.Phi() + Pi();
536            if(fPhi_mes < fPhiMin || fPhi_mes > fPhiMax || fTheta_mes < fThetaMin || fTheta_mes > fThetaMax) continue;
537            else break;
538        }
539           
540
541        // 4. Find TOA impact
542        fTOAImpact = atmo->ImpactAtTOA(fEarthImpact,EarthVector(-fOmega));
543        if(fTOAImpact.Z() == -HUGE) Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ImpactAtTOA says fEarthImpact is under sea level" << MsgDispatch;
544        if(fTOAImpact.Z() == HUGE)  Msg(EsafMsg::Warning) << "<FindImpactOnTOA> No ImpactAtTOA found : it Should not occur here" << MsgDispatch;
545       
546       
547        // 4. refine value of impact at sea level (should exist)
548        //    If it does not, set impact to outgoing point at TOA
549        fEarthImpact = atmo->ImpactASL(fTOAImpact,fOmega);
550        fHitGround = 0;
551        if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ImpactASL says fTOAImpact is under sea level" << MsgDispatch;
552        else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Debug) << "<FindImpactOnTOA> No ImpactASL found" << MsgDispatch;
553        else fHitGround = 1;
554        if(fHitGround == 0) {
555            Msg(EsafMsg::Warning) << "<FindImpactASL> No earth impact found. IT SHOULD NOT OCCUR IN ASL mode" << MsgDispatch;
556            fEarthImpact = atmo->ImpactAtTOA(fTOAImpact,fOmega);
557            if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<FindImpactOnTOA> ImpactAtTOA says fTOAImpact is under sea level" << MsgDispatch;
558            else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Warning) << "<FindImpactOnTOA> No ImpactAtTOA found. IT SHOULD NOT OCCUR HERE" << MsgDispatch;
559        }
560    }
561     
562    else Msg(EsafMsg::Panic) << "Wrong argument for GeneratorLightToEuso.ImpactMode config parameter" <<MsgDispatch;
563
564   
565    return kTRUE;
566}
567
568//_____________________________________________________________________________________________________
569Bool_t SlastShowerGenerator::IsInFoV(const EarthVector& pos) const {
570    //
571    // returns true if pos is within Euso FoV cone
572    //
573
574    // 1. change of frame : from MES to NES (local frame with origin on EUSO + Z-axis directed toward the Earth)
575    //    translation --> EUSO vector translation + rotation around x-axis to change Z direction to the opposite
576    //    thus MES/NES Y-axes are in the opposite sens
577    EarthVector Ux(1,0,0);
578    EarthVector pos_e = pos; 
579    pos_e -= fEusoVector; 
580    pos_e.Rotate(Pi(),Ux);
581   
582    if(pos_e.Theta() < fFoV) return kTRUE;
583    else return kFALSE;
584}
585
586//_____________________________________________________________________________________________________
587EarthVector SlastShowerGenerator::FoVintersection(const EarthVector& pos, const EarthVector& dir) const {
588    //
589    // finds the intersection between the given track and the Euso FoV cone, if exists
590    // if does not exist, returns (0,0,HUGE)
591    //
592    // intersection considered only above ground
593    //
594   
595    Double_t w = Cos(fFoV)*Cos(fFoV);
596    EarthVector direc = dir.Unit();
597
598    // 1. if pos is underground
599    EarthVector rtn;
600    if( (pos.Zv() + kAltitudeTolerance) < 0 ) {
601        Msg(EsafMsg::Warning) << "<FoVintersection> Starting position is underground, SHOULD NOT OCCUR" << MsgDispatch;
602        rtn.SetXYZ(0,0,-HUGE);
603        return rtn;
604    }
605   
606    // 2. change of frame : from MES to NES (local frame with origin on EUSO + Z-axis directed toward the Earth)
607    //    translation --> EUSO vector translation + rotation around x-axis to change Z direction to the opposite
608    //    thus MES/NES Y-axes are in the opposite sens
609    EarthVector Ux(1,0,0);
610    EarthVector pos_e = pos; 
611    EarthVector direc_e = direc;
612
613    pos_e -= fEusoVector; 
614    direc_e.Rotate(Pi(),Ux);
615    pos_e.Rotate(Pi(),Ux);
616   
617
618    // 3. now intersection calculation
619    Double_t mag(0);
620    // trinome defining solutions
621    Double_t a = direc_e.Z()*direc_e.Z() - w;
622    Double_t b = 2*pos_e.Z()*direc_e.Z() - 2*w*pos_e*direc_e;
623    Double_t c = pos_e.Z()*pos_e.Z() - pos_e.Mag2()*w;
624    pair<Int_t,Double_t*>& p = findRoots(a,b,c);  // special cases with a=0 and b=c=0 handled
625    if(p.first == 0) {
626        rtn.SetXYZ(0,0,HUGE);
627        return rtn;
628    }
629    if(p.first == 1) mag = p.second[0];
630    else if(p.first == 2) {
631        if((p.second[0]+kAltitudeTolerance) * (p.second[1]+kAltitudeTolerance) < 0) mag = Max(p.second[0],p.second[1]);
632        else mag = Min(p.second[0],p.second[1]);
633    }
634    // if intersection stands before pos, it is rejected
635    if(mag < -kAltitudeTolerance) {
636        rtn.SetXYZ(0,0,HUGE);
637        return rtn;
638    }
639   
640    rtn = pos_e + mag*direc_e;   
641   
642   
643    // 4. change of frame : from NES to MES frame
644    rtn.Rotate(-Pi(),Ux);
645    rtn += fEusoVector;
646
647    return rtn;
648}
649
650//_________________________________________________________________________________________
651Bool_t SlastShowerGenerator::GetFirstPoint(){
652    //
653    // X1 is known --> find the first point fInitPoint from TOA impact
654    // if event goes out atmosphere / OR / reaches ground without interacting, returns kFALSE
655    //
656   
657    Bool_t rtn = kTRUE;
658   
659    if(fFirstType == "POS") {
660        fXcurrent     = 0;
661        fXnext        = fXcurrent;
662        fCurrentPoint = fInitPoint;
663        fNextPoint    = fCurrentPoint;
664        fTimecurrent  = 0;
665        fTimenext     = 0;
666        return rtn;
667    }
668   
669    Int_t status = Atmosphere::Get()->InvertGrammage(fTOAImpact,fOmega,fX1,fInitPoint);
670    if(status == -1) Msg(EsafMsg::Info) << "<GetFirstPoint> InvertGrammage() status is -1, it Should not" << MsgDispatch;
671   
672    else if(status == 0) {
673        fXcurrent     = 0;
674        fXnext        = fXcurrent;
675        fCurrentPoint = fInitPoint;
676        fNextPoint    = fCurrentPoint;
677        fTimecurrent  = 0;
678        fTimenext     = 0;
679    }
680   
681    else if(status == 1)
682             Msg(EsafMsg::Warning) << "<GetFirstPoint> InvertGrammage() status is 1, it SHOULD NOT" << MsgDispatch;
683             
684    else if(status == 2) {
685        if(Atmosphere::Get()->Grammage(fTOAImpact,Atmosphere::Get()->ImpactAtTOA(fTOAImpact,fOmega)) < fX1+kTolerance)
686             Msg(EsafMsg::Info)    << "<GetFirstPoint> TOA reached : Primary has not interacted in the atmosphere" << MsgDispatch;
687        else Msg(EsafMsg::Warning) << "<GetFirstPoint> PROBLEM : TOA reached, BUT primary SHOULD have interacted in the atmosphere" << MsgDispatch;
688        rtn = kFALSE;
689    }
690   
691    else if(status == 3) {
692        if(Atmosphere::Get()->Grammage(fTOAImpact,Atmosphere::Get()->ImpactASL(fTOAImpact,fOmega)) < fX1+kTolerance)
693             Msg(EsafMsg::Info)    << "<GetFirstPoint> Primary has hit the ground without interacting in the atmosphere " << MsgDispatch;
694        else Msg(EsafMsg::Warning) << "<GetFirstPoint> PROBLEM : ground reached, BUT primary SHOULD have interacted before" << MsgDispatch;
695        rtn = kFALSE;
696    }
697   
698    else     Msg(EsafMsg::Warning) << "<GetFirstPoint> InvertGrammage() status unknown : "<< status << MsgDispatch;
699   
700    return rtn;
701}
702
703//_________________________________________________________________________________________
704Bool_t SlastShowerGenerator::IsXmaxInFoV(){
705    //
706    // Assess Xmax position and tell if it is in FoV
707    // used to reject event with Xmax out of FoV, without simulating the dvpt
708    //
709   
710    // inits
711    Bool_t rtn = kTRUE;
712   
713    // get Xmax according to shower dvpt model
714    if (fShowerParametrization != "GIL")
715        Msg(EsafMsg::Panic) << "<GetShowerParametrization> Only GIL formula available so far" <<MsgDispatch;
716    //TOFIX : GFA and GHF not coded correctly, they do not included X1 fluctuations
717    // when these options are reactivated, change the code below accordingly
718    Float_t x0 = 37.15*g/cm2;
719    Float_t Xmax = (1.7 + 0.76*(Log(fEnergy/0.81e8) - Log(fAtomicMass))) * x0 + fX1;
720    EarthVector Maxpos(1);
721
722   
723    Int_t status = Atmosphere::Get()->InvertGrammage(fTOAImpact,fOmega,Xmax,Maxpos);
724    if(status == -1) Msg(EsafMsg::Warning) << "<GetFirstPoint> InvertGrammage() status is -1, it Should not" << MsgDispatch;
725    else if(status == 1) Msg(EsafMsg::Warning) << "<GetFirstPoint> InvertGrammage() status is 1, it SHOULD NOT" << MsgDispatch;
726    // TOA or sea level reached before
727    else if(status == 2 || status == 3) rtn = kFALSE;
728    else if(status == 0) rtn = IsInFoV(Maxpos);
729    else Msg(EsafMsg::Panic) << "<GetFirstPoint> InvertGrammage() status unknown : "<< status << MsgDispatch;
730   
731    return rtn;
732}
733
734//_________________________________________________________________________________________
735Bool_t SlastShowerGenerator::GetNextStep() {
736    // This method checks if next point is visible and makes the next step if it is OK.
737   
738    //TOFIX : old flag
739    fInCome = kTRUE;
740
741    if(fCurrentPoint.IsUnderSeaLevel()) return kFALSE;
742    fCurrentPoint = fNextPoint;
743   
744    // search next shower step position
745    Int_t status = Atmosphere::Get()->InvertGrammage(fCurrentPoint,fOmega,fDepthStep,fNextPoint);
746    if(status == -1) {
747       Msg(EsafMsg::Warning) << "<GetNextStep> InvertGrammage() status is -1, it Should not" << MsgDispatch;
748       return kFALSE;
749    }
750    else if(status == 0) {
751        fXcurrent = fXnext;
752        fXnext    = fXcurrent + fDepthStep;
753        fTimecurrent = (fCurrentPoint-fInitPoint).Mag()/Clight();
754        fTimenext    = (fNextPoint-fInitPoint).Mag()/Clight();
755    }
756    else if(status == 1) {
757       Msg(EsafMsg::Warning) << "<GetNextStep> InvertGrammage() status is 1, it Should not" << MsgDispatch;
758       return kFALSE;
759    }
760    else if(status == 2) {
761       Msg(EsafMsg::Info) << "<GetNextStep> Shower goes out atmosphere : TOA reached " << MsgDispatch;
762       return kFALSE;
763    }
764    else if(status == 3) {
765       Msg(EsafMsg::Info) << "<GetNextStep> Shower reaches the ground " << MsgDispatch;
766       return kFALSE;
767    }
768    else Msg(EsafMsg::Warning) << "<GetNextStep> InvertGrammage() status unknown : "<< status << MsgDispatch;
769   
770    return kTRUE;
771}
772
773
774//_________________________________________________________________________________________
775void SlastShowerGenerator::GIL(Double_t x) {
776    //
777    // Assigning of fNe - number of electrons in the current step according to GIL parameterization.
778    // (GIL stands for Greizen-Ilina-Linsley which is the QGSJET model parameterization.
779    //
780   
781    Float_t x0 = 37.15;
782    Float_t t  = x*cm2/g/x0;
783    Float_t t_max = 1.7 + 0.76*(Log(fEnergy/0.81e8) - Log(fAtomicMass));
784    fAge  = 2*t/(t+t_max);
785    fNe   = 0;
786    if(fAge<=0) {
787        Msg(EsafMsg::Warning)<<"<GIL> Asking for depth <= 0. Zero returned"<<MsgDispatch;
788        fNe = 0.;
789        return;
790    }
791    fNe = fEnergy/1.45e9*Exp(t-t_max-2*t*Log(fAge));
792}
793
794
795//_________________________________________________________________________________________
796void SlastShowerGenerator::GFA(Double_t x) {
797    //
798    // Assigning of fNe - number of electrons in the current step according to Gaussian Function in Age parameterization.
799    // Formulae from C. Song, Astropart. Physics 22(2004)151
800    // sigma values fitted and extrapolated, Xmax, Nmax from GHF used
801    // Factor 1.1 added to Ne because of threshold energy used for corsika simulation (10% particles missing)
802    //
803    // WARNING !!!     not usable yet, cause cannot currently handle X1 fluctuations
804    //
805
806    Float_t Xmax,Nmax;
807    Float_t sigma,p0,p1;
808    if(fAtomicMass == 1) {
809        sigma =  0.3206 - 0.006597*Log10(fEnergy);
810        p0    = -8.9475;
811        p1    =  0.9874;
812        Nmax =  Exp(-20.95 + 2.292*Log10(fEnergy));
813        Xmax = -258.1 + 54.81*Log10(fEnergy);
814    }
815    else if(fAtomicMass == 56) {
816        sigma =  0.470-0.0135*Log10(fEnergy);
817        p0    = -9.043;
818        p1    =  0.9923;
819        Nmax =  Exp(-21.68 + 2.329*Log10(fEnergy));
820        Xmax = -430.7 + 59.08*Log10(fEnergy);
821    }
822    else throw invalid_argument(Form("Gaussian parameterization in age not available for primaries A = %f",fAtomicMass));
823
824    Xmax = Xmax*g/cm2;
825    fAge = 3*x/(x+2.*Xmax);
826    if(fAge<=0) {
827        Msg(EsafMsg::Warning)<<"<GFA> Asking for depth <= 0. Zero returned"<<MsgDispatch;
828        fNe = 0.;
829        return;
830    }
831    fNe = 1.11*Nmax * Exp( -(fAge-1)*(fAge-1) / (2.*sigma*sigma) );
832    return;
833}
834
835//_________________________________________________________________________________________
836void SlastShowerGenerator::GHF(Double_t x) {
837    //
838    // Assigning of fNe - number of electrons in the current step according to
839    // Gaisser Hillas    parametrisation
840    // Formulae from C. Song, Astropart. Physics 22(2004)151
841    // Xmax, Nmax, lambda, X1, X0 values fitted and extrapolated
842    // Factor 1.1 added to Ne because of threshold energy used for corsika simulation (10% particles missing)
843    //
844    // WARNING !!!     not usable yet, cause cannot currently handle X1 fluctuations
845    //
846
847    Float_t Xmax,Nmax;
848    Float_t X,X1,X0,lambda;
849    if(fAtomicMass == 1) {
850        X1   =  106.2 -  3.15*Log10(fEnergy);
851        X0   =  401.9 - 25.79*Log10(fEnergy);
852        Nmax =  Exp(-20.95 + 2.292*Log10(fEnergy));
853        Xmax = -258.1 + 54.81*Log10(fEnergy);
854        lambda= 98.6 -1.922*Log10(fEnergy);
855    }
856    else if(fAtomicMass == 56) {
857        X1   =   29.72 - 1.031*Log10(fEnergy);
858        X0   =  471.1 - 29.49*Log10(fEnergy);
859        Nmax =  Exp(-21.68 + 2.329*Log10(fEnergy));
860        Xmax = -430.7 + 59.08*Log10(fEnergy);
861        lambda= 182.4 -6.1*Log10(fEnergy);
862    }
863    else throw invalid_argument(Form("Gaussian parameterization in age not available for primaries A = %f",fAtomicMass));
864   
865    Xmax = Xmax*g/cm2;
866    X1   = X1*g/cm2;
867    X0   = X0*g/cm2;
868    //  X=x+fX1;
869    X=x;
870    lambda = lambda*g/cm2;
871    fNe = 1.11*Nmax * Power((X-X0)/(Xmax-X0),(Xmax-X0)/lambda) * Exp((Xmax-X)/lambda);
872    fAge = 3*x/(x+2.*Xmax); //should be defined ?
873   
874    if(fAge<=0) {
875        Msg(EsafMsg::Warning)<<"<GHF> Asking for depth <= 0. Zero returned"<<MsgDispatch;
876        fNe = 0.;
877        return;
878    }
879
880    return;
881}
882
883//_________________________________________________________________________________________
884PhysicsData* SlastShowerGenerator::Get() {
885    //
886    // method returning the ShowerTrack object
887    //
888   
889    Reset();
890
891    // generate random Energy, Theta, Phi and the interaction point
892    // energy slope is for differential spectrum
893    TRandom *rndm = EsafRandom::Get();
894   
895    // if power law
896    if(fSpectrumType == "powerlaw") {
897        // flat differential spectrum in log scale
898        if ( fEnergySlope == -1.) {
899            fEnergy = fEnergyMin * Exp(rndm->Rndm() * Log(fEnergyMax/fEnergyMin) );
900        }
901        else {
902            Double_t e1 = Power(fEnergyMin,fEnergySlope + 1);
903            Double_t e2 = Power(fEnergyMax,fEnergySlope + 1);
904            fEnergy = Power( e1 + (e2-e1)*rndm->Rndm(),1/(fEnergySlope + 1) );
905        }
906    }
907    else if(fSpectrumType == "GZKHiRes2005") {
908        fEnergy = -HUGE;
909        while((fEnergy < fEnergyMin) || (fEnergy > fEnergyMax)) {
910            Double_t log10E = fSpectrumRdnm->GetRandom();
911            fEnergy = Power(10.,log10E);
912        }
913    }
914    else Msg(EsafMsg::Panic)<<"<Get> Wrong argument for spectrum type == "<< fSpectrumType <<MsgDispatch;
915
916
917
918    // Check if only a specific point should be generated
919    if( fFirstType == "POS") {
920        fInitPoint.SetXYZ(fFirstPointX,fFirstPointY,fFirstPointZ);
921        fPhi_mes = (fPhiMax - fPhiMin)*rndm->Rndm() + fPhiMin;
922        fTheta_mes = (fThetaMax - fThetaMin)*rndm->Rndm() + fThetaMin;
923        fOmega.SetXYZ(-Sin(fTheta_mes)*Cos(fPhi_mes),-Sin(fTheta_mes)*Sin(fPhi_mes),-Cos(fTheta_mes));
924        Msg(EsafMsg::Info) << "<Get()> Pos option, LOCAL theta and phi set equal to MES values" << MsgDispatch;
925        fTheta_local = fTheta_mes;
926        fPhi_local = fPhi_mes;
927       
928        // find TOA impact and earth impact
929        fTOAImpact = Atmosphere::Get()->ImpactAtTOA(fInitPoint,EarthVector(-fOmega));
930        fEarthImpact = Atmosphere::Get()->ImpactASL(fInitPoint,fOmega);
931        fHitGround = 0;
932        if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<Get(), POS option> ImpactASL says fInitPoint is under sea level" << MsgDispatch;
933        else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Debug) << "<Get(), POS option> Shower does not reach the ground" << MsgDispatch;
934        else fHitGround = 1;
935        if(fHitGround == 0) {
936            fEarthImpact = Atmosphere::Get()->ImpactAtTOA(fInitPoint,fOmega);
937            if(fEarthImpact.Z() == -HUGE)      Msg(EsafMsg::Warning) << "<Get(), POS option> ImpactAtTOA says fInitPoint is under sea level" << MsgDispatch;
938            else if(fEarthImpact.Z() == HUGE)  Msg(EsafMsg::Warning) << "<Get(), POS option> No ImpactAtTOA found. IT SHOULD NOT OCCUR HERE" << MsgDispatch;
939        }
940       
941        // disable standard geometrical flags
942        fRejectFakeEvents = kFALSE;
943        fOutOfFoV = kFALSE;
944        fRejectNoXmax = kFALSE;
945
946        DevelopShower();
947    }
948   
949   
950    // STANDARD WAY
951    else {
952        Int_t cycle(0);
953        while (kTRUE) {
954            if ( cycle++>1000000 )                       break;
955            if ( FindImpactOnTOA() && DevelopShower())   break;
956        }
957    }
958    if (!fQuiet) {
959        MsgForm(EsafMsg::Info,"ShowerTrack produced : Energy = %.2E MeV, Theta_local = %.2f deg, Phi_local = %.2f deg",
960                fTrack->GetEnergy(), fTheta_local*RadToDeg(),fPhi_local*RadToDeg());
961        MsgForm(EsafMsg::Info,"         Impact on TOA : (%.2f,%.2f,%.2f) km with MES angles : Theta_mes = %.2f, Phi_mes = %.2f",
962                fTOAImpact.X()/km,fTOAImpact.Y()/km,fTOAImpact.Z()/km,fTheta_mes*RadToDeg(),fPhi_mes*RadToDeg());
963        MsgForm(EsafMsg::Info,"         First interaction X1 = %.3f at : (%.2f,%.2f,%.2f) km gives a shower with %d steps",
964                fTrack->fX1*cm2/g,fTrack->GetInitPos().X()/km,fTrack->GetInitPos().Y()/km,fTrack->GetInitPos().Z()/km, fTrack->GetNumStep());
965    }
966    else {
967        MsgForm(EsafMsg::Debug,"SlastShowerGenerator produced a ShowerTrack: Energy = %.2E MeV Theta = %.2f deg Phi = %.2f deg",
968                fTrack->GetEnergy(), fTrack->GetTheta()*RadToDeg(),fTrack->GetPhi()*RadToDeg());
969        MsgForm(EsafMsg::Debug,"                              originated with X1 = %.3f at: (%.2f,%.2f,%.2f) km with %d steps",
970                fTrack->fX1*cm2/g,fTrack->GetInitPos().X()/km,fTrack->GetInitPos().Y()/km,fTrack->GetInitPos().Z()/km, fTrack->GetNumStep());
971
972    }
973    return fTrack;
974
975}
976
977//_________________________________________________________________________________________
978void SlastShowerGenerator::Reset() {
979    //
980    // Reset ShowerTrack and SlastShowerGenerator internal parameters
981    //
982   
983    fHitGround = 0;
984    fInCome = kFALSE;
985    fOutCome = kFALSE;
986    fInitPoint.SetXYZ(0,0,HUGE);
987    fOmega.SetXYZ(0,0,HUGE);
988    fCurrentPoint.SetXYZ(0,0,HUGE);
989    fNextPoint.SetXYZ(0,0,HUGE);
990    fEarthImpact.SetXYZ(0,0,HUGE);
991    fTOAImpact.SetXYZ(0,0,HUGE);
992    fTheta_local  = -HUGE;
993    fPhi_local    = -HUGE;
994    fTheta_mes  = -HUGE;
995    fPhi_mes    = -HUGE;
996    fX1     = -HUGE;
997    fEnergy = -HUGE;
998   
999}
1000
1001//_________________________________________________________________________________________
1002void SlastShowerGenerator::GetShowerInfo() {
1003    // Fills ShowerTrack parameters
1004    fTrack->fEnergy    = fEnergy*eV;
1005    fTrack->fTheta     = fTheta_mes;
1006    fTrack->fPhi       = fPhi_mes;
1007    fTrack->fX1        = fX1;
1008    fTrack->fEthrEl    = 0;
1009    fTrack->fDirVers   = fOmega;
1010    fTrack->fInitPos   = fInitPoint;
1011    fTrack->fHitGround = fHitGround;
1012    fTrack->fEarthImpact = fEarthImpact;
1013}
1014
1015//_________________________________________________________________________________________
1016Bool_t SlastShowerGenerator::DevelopShower() {
1017    //
1018    // Method developing the shower
1019    //
1020   
1021    GetX1();
1022    Bool_t has_interacted = GetFirstPoint();
1023   
1024    // init
1025    if(!fTrack) fTrack = new ShowerTrack();
1026    else fTrack->Reset();
1027
1028    // 1. if fake events not allowed, re-try for another event
1029    //    NB : fOutOfFoV flag is not relevant here, cause no showers should be in this case. But kept for safety
1030    if(fRejectFakeEvents && (!has_interacted || fOutOfFoV)) return kFALSE;
1031   
1032    // 1.1 if events without Xmax in the FoV are not allowed, re-try for another event
1033    if(fRejectNoXmax) {
1034        if(!IsXmaxInFoV()) {
1035            Msg(EsafMsg::Info)<<"Shower Xmax is not in FoV --> retry for another event"<<MsgDispatch;
1036            return kFALSE;
1037        }
1038    }
1039
1040    // 2. if fake events allowed + CR has not interacted
1041    // --> X1 related data fixed to HUGE values
1042    if(!has_interacted) {
1043        fX1 = -HUGE;
1044        fInitPoint.SetXYZ(0,0,HUGE);
1045        GetShowerInfo();
1046        Msg(EsafMsg::Info)<<"Cosmic ray has not interacted in the atmosphere"<<MsgDispatch;
1047        return kTRUE;
1048    }
1049
1050    // 3. if fake events allowed + events is out of FoV, shower dvpt avoided
1051    if(!fRejectFakeEvents && fOutOfFoV) {
1052        GetShowerInfo();
1053        Msg(EsafMsg::Info)<<"ShowerTrack does NOT cut the FoV"<<MsgDispatch;
1054        return kTRUE;
1055    }
1056
1057    // 4. "standard" candidate
1058    //    Develop a shower of shower steps
1059    Int_t cycle(0);
1060    while(kTRUE) {
1061        if(cycle++>100000) return kFALSE;
1062        if(!GetNextStep()) break;
1063        if( fInCome) {
1064            ShowerStep s = GetShowerStep();
1065            fTrack->Add(s);
1066        }
1067    }
1068    GetShowerInfo();
1069    Msg(EsafMsg::Info)<<"ShowerTrack cut the FoV"<<MsgDispatch;
1070   
1071    return kTRUE;
1072}
1073
1074//_________________________________________________________________________________________
1075MCTruth* SlastShowerGenerator::GetTruth() {
1076    //
1077    // Method returning the Truth object
1078    //
1079   
1080    // init
1081    if(!fTruth) fTruth = new MCTruth();
1082   
1083    // can be filled even if showertrack has no steps
1084    fTruth->SetEnergy(fTrack->GetEnergy());
1085    fTruth->SetThetaPhi(fTrack->GetTheta(),fTrack->GetPhi());
1086    fTruth->SetFirstInt(fInitPoint,fX1);
1087    Int_t particode = Int_t(floor(fAtomicMass+0.5));
1088    fTruth->SetParticle(particode);
1089    fTruth->SetTOAImpact(fTOAImpact);
1090    fTruth->SetEarthImpact(fEarthImpact);
1091   
1092    // filled only if steps exist   
1093    if (fTrack->Size() > 0) {
1094       const ShowerStep& s = fTrack->GetLastStep();
1095       fTruth->SetEarthAge(s.GetAgef());
1096       // get the shower maximum
1097       Float_t MaxElectrons(0);
1098       Int_t MaxIndex(-1);
1099       for (UInt_t i(0); i<fTrack->Size(); i++) {
1100           const ShowerStep& s = fTrack->GetStep(i);
1101           if (MaxElectrons < s.GetNelectrons()) {
1102               MaxIndex = i;
1103               MaxElectrons = s.GetNelectrons();
1104           }
1105       }
1106       if (MaxIndex != -1) {
1107           const ShowerStep& s = fTrack->GetStep(MaxIndex);
1108           fTruth->SetShowerMax(0.5*(s.GetXYZi() + s.GetXYZf()),0.5*(s.GetXi() + s.GetXf()));
1109       }
1110    }
1111   
1112    return fTruth;
1113}
1114
1115//_________________________________________________________________________________________
1116Double_t SlastShowerGenerator::GetXmax() {
1117    //
1118    // returns Xmax of the shower according to GIL parametrization (used by Reco)
1119    //
1120    Float_t x0 = 37.15*g/cm2;
1121    Float_t fEnergyScale;
1122    if (fEnergy<0) fEnergyScale = 1.e20;
1123    else           fEnergyScale = fEnergy;
1124    Float_t t_max = 1.7 + 0.76*(Log(fEnergyScale/0.81e8) - Log(fAtomicMass));
1125    return t_max*x0;
1126}
Note: See TracBrowser for help on using the repository browser.