/************************************************************************** * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$ */ ///////////////////////////////////////////////////////////////////////////// // // Contain parametrizations to generate atmospheric muons, and also // to generate single muons and muon bundles at surface level. // //Begin_Html /*

The responsible person for this module is Enrique Gamez.

*/
//End_Html
//
/////////////////////////////////////////////////////////////////////////////

#include 

#include 
#include 


#include "AliConst.h"
#include "AliGenCRT.h"
#include "AliRun.h"

ClassImp(AliGenCRT)

//_____________________________________________________________________________
AliGenCRT::AliGenCRT() : AliGenerator(-1)
{
  //
  // Default ctor.
  //
  fIpart = 0;

  fXwidth=0;
  fNx=1;
  fZwidth=0;
  fNz=1;
  fMuonGrid = kFALSE;


  // Set the origin above the vertex, on the surface.
  fOrigin[0] = 0.;
  fOrigin[1] = 0.;
  fOrigin[2] = 0.;

  fZenithMin = 0.; 
  fZenithMax = 0.;

  fAzimuthMin = 0.;
  fAzimuthMax = 0.;

  fPResolution = 1.;
  fPRange = 0.;

  fMomentumDist = 0;
  fZenithDist = 0;

  fPDist = 0;

  fAp = 0;
  fUnfoldedMomentumDist = 0;

  fCRModeName = 0;
}

//_____________________________________________________________________________
AliGenCRT::AliGenCRT(Int_t npart) 
  : AliGenerator(npart)
{
  //
  // Standard ctor.
  //
  fName = "CRT";
  fTitle = "Cosmic Muons generator";

  // Generate Muon- by default
  fIpart = kMuonMinus;

  fXwidth=0;
  fNx=1;
  fZwidth=0;
  fNz=1;
  fMuonGrid = kFALSE;

  // Set the origin above the vertex, on the surface.
  fOrigin[0] = 0.;
  fOrigin[1] = AliCRTConstants::fgDepth; // At the surface by default.
  fOrigin[2] = 0.;

  fZenithMin = 0.; // Generate veritcals by default.
  fZenithMax = 0.;

  fAzimuthMin = 0.;
  fAzimuthMax = 0.;

  fPResolution = 1.; // 1 GeV by default.
  fPRange = 0.;      // 0 GeV by default.

  fMomentumDist = 0;
  fZenithDist = 0;

  fPDist = 0;

  fAp = 0;
  fUnfoldedMomentumDist = 0;

  fCRModeName = 0;
}

//_____________________________________________________________________________
AliGenCRT::AliGenCRT(const AliGenCRT& gen) : AliGenerator()
{
  //
  // Copy ctor.
  //
  gen.Copy(*this);
}

//_____________________________________________________________________________
AliGenCRT& AliGenCRT::operator= (const AliGenCRT& gen)
{
  //
  // Asingment ctor.
  //
  gen.Copy(*this);
  return *this;
}

//_____________________________________________________________________________
AliGenCRT::~AliGenCRT()
{
  //
  // Default dtor.
  //
  if ( fAp )           delete fAp;
  if ( fMomentumDist ) delete fMomentumDist;
  if ( fUnfoldedMomentumDist ) delete fUnfoldedMomentumDist;
  if ( fZenithDist )   delete fZenithDist;
  if ( fPDist )        delete fPDist;
}

//_____________________________________________________________________________
void AliGenCRT::Generate()
{
  //
  // Generate on one trigger
  //

  Float_t polar[3]= {0,0,0}; // Polarization parameters
  //
  Float_t origin[3];
  Float_t p[3];
  Int_t i, j, nt;
  Float_t pmom, pt;
  Float_t zenith, azimuth;
  //
  Float_t random[6];


  // Check if you need to use a distribution function for the momentum
  if ( fMomentumDist ) {
    pmom = - this->GetMomentum(); // Always downwards.

  } else {
    pmom = -fPMin;

  }
  
  zenith = this->GetZenithAngle(pmom);  // In degrees
  
  // Take the azimuth random.
  Rndm(random, 2);
  azimuth = (fAzimuthMin + (fAzimuthMax-fAzimuthMin)*random[0]); // In degrees
  
  origin[0] = AliCRTConstants::fgDepth*TMath::Tan(zenith*kDegrad)*
    TMath::Sin(azimuth*kDegrad);
  origin[1] = AliCRTConstants::fgDepth;
  origin[2] = AliCRTConstants::fgDepth*TMath::Tan(zenith*kDegrad)*
    TMath::Cos(azimuth*kDegrad);
  
  if ( fVertexSmear == kPerEvent ) {
    Rndm(random,6);
    for (j=0;j<3;j++) {
      if ( j == 1 ) {
	// Don't smear the vertical position.
	origin[j] = AliCRTConstants::fgDepth;
      } else {
	origin[j]+=fOsigma[j]*TMath::Cos(2*random[2*j]*TMath::Pi())*
	  TMath::Sqrt(-2*TMath::Log(random[2*j+1]));
      }
    }
  }


  if ( fCRMode == kSingleMuons ) {

    //
    // Generate kinematics a la AliGenBox
    //

    for(i=0;i 0) {
      dx=fXwidth/fNx;
    } else {
      dx=1e10;
    }
    
    if (fNz > 0) {
      dz=fZwidth/fNz;
    } else {
      dz=1e10;
    }

    for (Int_t ix=0; ixInitMomentumGeneration();
    this->InitZenithalAngleGeneration();
    
  } else {
    Fatal("Generate", "Generation Mode unknown!\n");

  }

}

//____________________________________________________________________________
void AliGenCRT::SetGridRange(Int_t nx,Float_t xwidth, Int_t nz, Float_t zwidth)
{
  //
  // Define the grid
  // This data shuold be used for Muon bundles generation.
  //
  fXwidth=xwidth;
  fNx=nx;
  fZwidth=zwidth;
  fNz=nz;

  // Print a message  about the use, if the Mode has not been set, or
  // it has to a different Mode.
  if ( fCRMode != kMuonBundle ) {
    Warning("SetRange","You have been specified a grid to generate muon bundles, but seems that you haven't choose this generation mode, or you have already select a different one");
    fMuonGrid = kTRUE;
  }
}

//____________________________________________________________________________
void AliGenCRT::InitApWeightFactors()
{
  //
  // This factors will be  to correct the zenithal angle distribution
  // acording the momentum

  //
  // Fill the array for the flux zenith angle dependence.
  // at the index 0 of fAp[] will be the "factor" if we have a muon
  // of 0 GeV.
  Float_t a[6] = {-1.61, -1.50, -1.28, -0.94, -0.61, -0.22};
  Float_t p[6] = { 0., 10., 30., 100., 300., 1000.};

  // Get the information from the momentum
  Int_t pEnd  = TMath::Abs(TMath::Nint(fPMax/fPResolution)) + 1;
  // Initialize the Array of floats to hold the a(p) factors.
  fAp = new TArrayF(pEnd);
  
  Int_t index = 0;

  for (Int_t i = 0; i < pEnd; i++ ) {
    Float_t currentP = ((Float_t)i)*fPResolution;
    if ( currentP < p[1] )                          index = 0;
    else if ( currentP >= p[1] && currentP < p[2] ) index = 1;
    else if ( currentP >= p[2] && currentP < p[3] ) index = 2;
    else if ( currentP >= p[3] && currentP < p[4] ) index = 3;
    else if ( currentP >= p[4] )                    index = 4;

    Float_t ap = (currentP -p[index])*(a[index+1] - a[index])/
                 (p[index+1] - p[index]) + a[index];
    fAp->AddAt(ap, i);
  }

}

//___________________________________________________________________________
void AliGenCRT::InitMomentumGeneration()
{
  //
  // Initialize a funtion to generate the momentum randomly
  // acording this function.
  //

  // Check if we nned to initialize the function
  if ( fPMin != fPMax ) {

    // Check also if the function have been defined yet.
    if ( !fMomentumDist ) {

      // If not, use this function
      const char* y      = "log10(x)";
      
      const char* h1Coef = "[0]*( %s*%s*%s/2 - (5*%s*%s/2) + 3*%s )";
      const char* h2Coef = "[1]*( (-2*%s*%s*%s/3) + (3*%s*%s) - 10*%s/3 + 1 )";
      const char* h3Coef = "[2]*( %s*%s*%s/6 - %s*%s/2 + %s/3 )";
      const char* s2Coef = "[3]*( %s*%s*%s/3 - 2*%s*%s + 11*%s/3 - 2 )";
      
      const char* h = "%s + %s + %s + %s";
      const char* flux = "pow(10., %s)";
      const char* normalizedFlux = "0.86*x*x*x*pow(10., %s)";
      const char* paramNames[4] = {"H1", "H2", "H3", "S1"};
      
      char buffer1[1024];
      char buffer2[1024];
      char buffer3[1024];
      char buffer4[1024];
      char buffer5[1024];
      char buffer6[1024];
      char buffer7[1024];

      sprintf(buffer1, h1Coef, y, y, y, y, y, y);
      sprintf(buffer2, h2Coef, y, y, y, y, y, y);
      sprintf(buffer3, h3Coef, y, y, y, y, y, y);
      sprintf(buffer4, s2Coef, y, y, y, y, y, y);
      
      sprintf(buffer5, h, buffer1, buffer2, buffer3, buffer4);
      
      sprintf(buffer6, flux, buffer5);
      
      fMomentumDist = new TF1("fMomentumDist", buffer6, fPMin, fPMax);
      sprintf(buffer7, normalizedFlux, buffer5);
      fUnfoldedMomentumDist = new TF1("fUnfoldedMomentumDist", buffer7, fPMin, fPMax);
      for (Int_t i = 0; i < 4; i++ ) {
	fMomentumDist->SetParName(i, paramNames[i]);
	fUnfoldedMomentumDist->SetParName(i, paramNames[i]);
      }
      
      fMomentumDist->SetParameter(0, 0.133);
      fMomentumDist->SetParameter(1, -2.521);
      fMomentumDist->SetParameter(2, -5.78);
      fMomentumDist->SetParameter(3, -2.11);

      fUnfoldedMomentumDist->SetParameter(0, 0.133);
      fUnfoldedMomentumDist->SetParameter(1, -2.521);
      fUnfoldedMomentumDist->SetParameter(2, -5.78);
      fUnfoldedMomentumDist->SetParameter(3, -2.11);
      
    }

  }

}

//____________________________________________________________________________
void AliGenCRT::InitZenithalAngleGeneration()
{
  //
  // Initalize a distribution function for the zenith angle.
  // This angle will be obtained randomly acording this function.
  // The generated angles  will been in degrees.

  // Check if we need to create the function.
  if ( fZenithMin != fZenithMax ) {

    // Check also if another function have been defined.
    if ( !fZenithDist ) {
      
      // initialize the momentum dependent coefficients, a(p) 
      InitApWeightFactors();
      
      // Define the standard function.
      char* zenithalDisributionFunction = "1 + [0]*(1 - cos(x*3.14159265358979312/180))";

      Int_t pEnd  = TMath::Abs(TMath::Nint(fPMax/fPResolution)) + 1;
      fPDist = new TClonesArray("TF1", pEnd);
      TClonesArray &angle = *fPDist;
      for ( Int_t i = 0; i < pEnd; i++ ) {
	// Fill the distribution
	TF1* zenith = new(angle[i]) TF1("zenith",zenithalDisributionFunction, fZenithMin, fZenithMax);

	// Fix the momentum dependent coefficients
	zenith->SetParName(0, "a(p)");
	zenith->SetParameter(0, fAp->At(i));

      }

    } 

  }

}

//____________________________________________________________________________
const Float_t AliGenCRT::GetZenithAngle(Float_t mom)
{

  Float_t zenith = 0.;
  // Check if you need to generate a constant zenith angle.
  if ( !fZenithDist ) {
    // Check if you have defined an array of momentum functions
    if ( fPDist ) {
      Int_t pIndex = TMath::Abs(TMath::Nint(mom));
      TF1* zenithAngle = (TF1*)fPDist->UncheckedAt(pIndex);
      zenith = zenithAngle->GetRandom();
      return zenith;
    } else {

      if ( fCRMode != kMuonFlux ) {
	// If you aren't generating muons obeying any ditribution
	// only generate a flat zenith angle, acording the input settings
	Float_t random[2];
	Rndm(random, 2);
	zenith = fZenithMin + (fZenithMax - fZenithMin)*random[0];

      } else {
	// Even if you are generating muons acording some distribution,
	// but you don't want to ...
	zenith = fZenithMin;

      }

    }
  } else {
    zenith = fZenithDist->GetRandom();
  }
     
  return zenith;
  
}

//____________________________________________________________________________