Universita' di GenovaINFN Sezione di Genova  
AIRWATCH / EUSO Genova

ShowerLightSource - source file

// ESAF : Euso Simulation and Analysis Framework
// $Id: ShowerLightSource.cc,v 1.53 2005/05/10 16:54:10 moreggia Exp $
// Alessandro Thea created Nov, 24 2003

#include "ShowerLightSource.hh"
#include "Config.hh"

#include "ListPhotonsInAtmosphere.hh"
#include "FluoCalculator.hh"
#include "CrkCalculator.hh"
#include "LightSourceFactory.hh"

#include "Atmosphere.hh"

#include "EAtmosphere.hh"
#include "EAtmosphereBunchAdder.hh"
#include "utils.hh"
#include <TH1F.h>

#include <vector> // test

ClassImp(ShowerLightSource)

//____________________________________________________________________________________________
   ShowerLightSource::ShowerLightSource() : LightSource("SHOWER"), EsafMsgSource(),
                                           fFluocalcul(0),fCrkcalcul(0) {
    //
    // ctor
    //
    fPh_in_atmo = new ListPhotonsInAtmosphere;
    if(!fPh_in_atmo) Msg(EsafMsg::Panic) << "Pb for memory allocation of fPh_in_atmo"<<MsgDispatch;
    Configure();
    Msg(EsafMsg::Info) << "ShowerLightSource built" << MsgDispatch;
}

//_____________________________________________________________________________________________
ShowerLightSource::~ShowerLightSource() {
    //
    // dtor
    //
    SafeDelete(fPh_in_atmo);
    SafeDelete(fFluocalcul);
    SafeDelete(fCrkcalcul);
}

//______________________________________________________________________________________________
 void ShowerLightSource::Configure() {
    //
    // configure fluorescence and cerenkov calculators 
    //

    // Get fluorescence calculator
    string fluoname = Conf()->GetStr("ShowerLightSource.FluoCalculator");
    fFluocalcul = LightSourceFactory::Get()->GetFluoCalculator( fluoname );
    Msg(EsafMsg::Info) << "Fluo calculator name " <<fFluocalcul->GetName()<< MsgDispatch;

    // Get Cerenkov calculator
    string crkname = Conf()->GetStr("ShowerLightSource.CrkCalculator");
    fCrkcalcul = LightSourceFactory::Get()->GetCrkCalculator( crkname );
    Msg(EsafMsg::Info) << "Cerenkov calculator name " <<fCrkcalcul->GetName()<< MsgDispatch;

    // Get Energy Distribution Name
    fEnergyDistributionName = Conf()->GetStr("ShowerLightSource.EnergyDistributionName");

    // Get Lateral Distribution Name
    fLateralDistributionName = Conf()->GetStr("ShowerLightSource.LateralDistributionName");

    // Get Angular Distribution Name
    fAngularDistributionName = Conf()->GetStr("ShowerLightSource.AngularDistributionName");
}

//________________________________________________________________________________________
 void ShowerLightSource::Reset() {
    //
    // reset internal list of photons
    //
    if(fPh_in_atmo) fPh_in_atmo->Reset();
    if(fFluocalcul) fFluocalcul->Reset();
    if(fCrkcalcul) fCrkcalcul->Reset();
}

//_________________________________________________________________________________________ 
 PhotonsInAtmosphere* ShowerLightSource::Get( const PhysicsData* data ) {
    //
    // generate photons in atmosphere from shower
    //
    Reset();

    if ( data->Type() != "shower" )
        Msg(EsafMsg::Panic) << "Wrong PhysicsData in ShowerLightSource. Must be shower"<<MsgDispatch;
    ShowerTrack *track = (ShowerTrack*)data;
    
    UInt_t nbshowstep = track->GetNumStep();
    if(nbshowstep == 0) return (PhotonsInAtmosphere*)0;

    // energy spectrum of charged particles 
    const char* ED_char = fEnergyDistributionName.c_str();
    TString EDname;
    EDname.Append(ED_char);

#ifdef DEBUG
    Msg(EsafMsg::Debug)<< "Energy Distribution Name "<< EDname << MsgDispatch;
#endif
    TF2* EnergyDistribution = NULL;
    if( !((fEnergyDistributionName == "NULL")||(fEnergyDistributionName == "histos")) )
                           EnergyDistribution = track->GetEnergyDistribution(EDname);

    // electron angular distribution  
    const char* AD_char = fAngularDistributionName.c_str();

    TString ADname;
    ADname.Append(AD_char);
#ifdef DEBUG
    Msg(EsafMsg::Debug)<< "Angular Distribution Name "<< ADname << MsgDispatch;
#endif
    TF2* AngularDistribution = NULL;
    if(!((fAngularDistributionName == "NULL")||(fAngularDistributionName == "histos")) ) 
                           AngularDistribution = track->GetAngularDistribution(ADname);

    // electron lateral distribution  
    const char* LD_char = fLateralDistributionName.c_str();
    TString LDname;
    LDname.Append(LD_char);
#ifdef DEBUG
    Msg(EsafMsg::Debug)<< "Lateral Distribution Name "<< LDname << MsgDispatch;
#endif
    TF2* LateralDistribution = NULL;
    if(!((fLateralDistributionName == "NULL")||(fLateralDistributionName == "histos")) ) 
                            LateralDistribution = track->GetLateralDistribution(LDname);

    // initialization of the photons track -- assess the mean depth of ShowerSteps (assumed cst)
    ConfigFileParser* pConfig = Config::Get()->GetCF("RadiativeTransfer","BunchRadiativeTransfer");
    Double_t depthstep = pConfig->GetNum("BunchRadiativeTransfer.DepthStep")*g/cm2;
    Double_t meanshowdepthstep = Atmosphere::Get()->Grammage(track->FirstPos(),track->LastPos()) / nbshowstep;
    UInt_t stepjump = (UInt_t) floor(depthstep/meanshowdepthstep);
    if(stepjump == 0) stepjump = 1;
    fPh_in_atmo->ClearTrack();
    if(nbshowstep % stepjump == 0) fPh_in_atmo->SetNbTrackSteps(nbshowstep/stepjump + 1);
    else fPh_in_atmo->SetNbTrackSteps(nbshowstep/stepjump + 2);
    
    // Estimate the total number of electrons
    Float_t nTotal(0),nTracked(0); 
    for (UInt_t i=0;i<nbshowstep;i++) {
        const ShowerStep& s = (*track)[i];
        if(i % stepjump == 0) fPh_in_atmo->FillTrack(s.GetXYZi());
        nTotal += s.GetNelectrons();
    }
    fPh_in_atmo->FillTrack((*track)[nbshowstep-1].GetXYZf());

    Bool_t next(0),subnext(0);
    Float_t left(0),right(10),subleft(0),subright(2.5);
    Msg(EsafMsg::Info) << "Processing:         0%" << MsgFlush;

    for (UInt_t i=0;i<nbshowstep;i++) {
        const ShowerStep& s = (*track)[i];
	// generate fluorescence bunch
        BunchOfPhotons* bfluo = MakeFluoStep(s,EnergyDistribution,LateralDistribution);
        fPh_in_atmo->Add(bfluo);

        // generate cerenkov bunch
        BunchOfPhotons* bcer = MakeCerenkovStep(s,EnergyDistribution,LateralDistribution,AngularDistribution);
        fPh_in_atmo->Add(bcer);

        nTracked += s.GetNelectrons();

        Float_t fraction = 100*i/nbshowstep;
        if (left<fraction && fraction <=right) 
            next = kFALSE;
        else if (fraction>right) {
            next = kTRUE;
            left = right;
            right += 10;
        }
        if (subleft<fraction  && fraction <=subright) {
            subnext = kFALSE;
        }
        if (fraction > subright) {
            subnext = kTRUE;
            subleft = subright;
            subright +=2;
        }
        if (next) Msg(EsafMsg::Info) << left << "%" << MsgFlush;
        if (subnext) Msg(EsafMsg::Info)<< "." << MsgFlush;	 
    } 

    Msg(EsafMsg::Info) << " -done. " << MsgDispatch;
    return fPh_in_atmo;
   
}
//_________________________________________________________________________________________ 
 MCTruth* ShowerLightSource::Truth() {
    return NULL;
}

//_________________________________________________________________________________________ 
 BunchOfPhotons* ShowerLightSource::MakeFluoStep(const ShowerStep& step,TF2* EnergyDistribution,
        TF2* LateralDistribution) {
    //
    // generate a fluorescence bunch of photons for this shower step 
    //

    //mean position in space 
    EarthVector posi = step.GetXYZi();
    EarthVector posf = step.GetXYZf();
#ifdef DEBUG
    //Msg(EsafMsg::Debug)<<" X "<< posi.X()/km <<" Y "<<posi.Y()/km<<" Z "<<posi.Z()/km<<MsgDispatch;
#endif
    EarthVector pos=0.5*(posi+posf);


    // fluorescence yield for the energy spectrum of charged particles
    EsafSpectrum spectrum(357*nm);  //initialisation
    Double_t age = 0.5*(step.GetAgef()+step.GetAgei());
    Double_t TotalYield = 0;

    if ( fEnergyDistributionName == "histos" ) {        
        const TH1F* ehisto = step.GetHistoEnergy();
        TotalYield = fFluocalcul->GetFluoYieldHisto(pos.Zv(),ehisto,&spectrum);  
#ifdef DEBUG
       // Msg(EsafMsg::Debug)<<"integration over TH1F - Yield Fluo " << TotalYield*m << MsgDispatch;
#endif
    }

    else if ( EnergyDistribution ) {
        TF12 EnergyDistributionStep("EDS_name",EnergyDistribution,age,"X");
        TotalYield = fFluocalcul->GetFluoYield(pos.Zv(),&EnergyDistributionStep,&spectrum);
#ifdef DEBUG
       // Msg(EsafMsg::Debug)<<"integration over TF12 - Yield Fluo " << TotalYield*m << MsgDispatch;
#endif
    }
    else {
        TotalYield = fFluocalcul->GetFluoYield(pos.Zv(),80*MeV,&spectrum);
#ifdef DEBUG
       // Msg(EsafMsg::Debug)<<" E= 80 MeV - Yield Fluo " << TotalYield*m << MsgDispatch;
#endif
    }

    // total weight of the bunch of photons
    Double_t dl = (step.GetXYZf()-step.GetXYZi()).Mag(); 
    Double_t nbPhotonsInBunch = step.GetNelectrons() * TotalYield * dl;
#ifdef DEBUG
   // Msg(EsafMsg::Debug)<< "nelec "<<step.GetNelectrons()<<" nbpib fluo "<<nbPhotonsInBunch << " dl= " << dl/m << MsgDispatch;
#endif

    // Create a new bunch of Photons with its ParentBunch
    BunchOfPhotons* b = new BunchOfPhotons(nbPhotonsInBunch,TotalYield,posi,posf,step.GetTimei(),
                        step.GetTimef(),spectrum,step.GetParentTrack()->GetDirVers(),Fluo);

    // Set the lateral distribution to the bunch if it exists
    if ( fLateralDistributionName == "histos" ) {
        const TH1F* lhisto = step.GetHistoLateral();
        if (lhisto) b->SetParentLateral(*lhisto);
    }
    else if ( LateralDistribution ) {
        if ( LateralDistribution->GetNpar() == 1 ) {
            // gives moliere radius as parameter in meter
            // Get Atmosphere for Density
            const Atmosphere* atmo = Atmosphere::Get();
            Double_t Rm = 9.6 * gram/cm2 / atmo->Air_Density( pos.Zv() ) / m; // in meters
            LateralDistribution->SetParameters(Rm,0);
        }
        TF12 LateralDistributionStep("LDS_name",LateralDistribution,age,"X");
        b->SetParentLateral(LateralDistributionStep);
    }
    return b;

}


//_________________________________________________________________________________________ 
 BunchOfPhotons* ShowerLightSource::MakeCerenkovStep(const ShowerStep& step, TF2* EnergyDistribution,
        TF2* LateralDistribution, TF2* AngularDistribution) {
    //
    // Generate a Cerenkov Bunch Of Photons for this shower step
    //

    //mean position in space 
    EarthVector posi = step.GetXYZi();
    EarthVector posf = step.GetXYZf();
    EarthVector pos=0.5*(posi+posf);

    // Cerenkov yield for the energy spectrum of charged particles
    Double_t age = 0.5*(step.GetAgef()+step.GetAgei());
    Double_t TotalYield;
    if ( fEnergyDistributionName == "histos" ) {
        const TH1F* ehisto = step.GetHistoEnergy();
        TotalYield = fCrkcalcul->GetCrkYield(pos.Zv(),ehisto);
#ifdef DEBUG
     //   Msg(EsafMsg::Debug)<<"integration over TH1F - Yield Cerenkov " << TotalYield*m << MsgDispatch; 
#endif
    }
    else if ( EnergyDistribution ) {
        TF12 EnergyDistributionStep("EDS_name",EnergyDistribution,age,"X");
        TotalYield = fCrkcalcul->GetCrkYield(pos.Zv(),&EnergyDistributionStep);
#ifdef DEBUG
      //  Msg(EsafMsg::Debug)<<"integration over TF12 - Yield Cerenkov " << TotalYield*m << MsgDispatch;
#endif
    }
    else {
        TotalYield = fCrkcalcul->GetCrkYield(pos.Zv(),80*MeV);
#ifdef DEBUG
     //   Msg(EsafMsg::Debug)<<"E=80MeV - Yield Cerenkov " << TotalYield*m << MsgDispatch;
#endif
    }

    // Cerenkov wavelenght spectrum 
    EsafSpectrum *spectrum = fCrkcalcul->GetCrkSpectrum();

    // weight of the bunch of photons
    Double_t dl = (step.GetXYZf()-step.GetXYZi()).Mag(); 
    Double_t nelec = step.GetNelectrons();
    Double_t nbPhotonsInBunch = nelec*TotalYield*dl;
#ifdef DEBUG
   // Msg(EsafMsg::Debug)<< "nelec "<<nelec<<" nbpib cer "<<nbPhotonsInBunch << " dl= " << dl/m << MsgDispatch;
#endif

    // Create a new bunch of Photons with its ParentBunch
    BunchOfPhotons* b = new BunchOfPhotons(nbPhotonsInBunch,TotalYield,posi,posf,step.GetTimei(),
                        step.GetTimef(),*spectrum,step.GetParentTrack()->GetDirVers(),Cerenkov);

    // Set the lateral distribution to the parent bunch
    if ( fLateralDistributionName == "histos" ) {
        const TH1F* lhisto = step.GetHistoLateral();
        if (lhisto) b->SetParentLateral(*lhisto);
    }
    else if ( LateralDistribution ) {
        if ( LateralDistribution->GetNpar() == 1 ) {
            // gives moliere radius as parameter in meter
            // Get Atmosphere for Density
            const Atmosphere* atmo = Atmosphere::Get();
            Double_t Rm = 9.6 * gram/cm2 / atmo->Air_Density( pos.Zv() ) / m; // in meters
            LateralDistribution->SetParameters(Rm,0);
        }
        TF12 LateralDistributionStep("LDS_name",LateralDistribution,age,"X");
        b->SetParentLateral(LateralDistributionStep);
    }

    // Set the angular distribution to the parent bunch
    if ( AngularDistribution ) {
        TF12 AngularDistributionStep("ADS_name",AngularDistribution,
                fCrkcalcul->GetEnergyThreshold(pos.Zv())/MeV,"X");
        b->SetParentAngular(AngularDistributionStep);
    }
    
    SafeDelete(spectrum);
    
    return b;

}


About Us | EUSO Official Website | Web pages created by Roberto Pesce and Alessandro Thea - Last Update 14-May-2005 21:31