Skip to content
Snippets Groups Projects
EventGeneratorGEFReader.cc 23.9 KiB
Newer Older
/*****************************************************************************
 * Copyright (C) 2009-2016   this file is part of the NPTool Project         *
 *                                                                           *
 * For the licensing terms see $NPTOOL/Licence/NPTool_Licence                *
 * For the list of contributors see $NPTOOL/Licence/Contributors             *
 *****************************************************************************/

/*****************************************************************************
 * Original Author: Benoit MAUSS  contact address: benoit.mauss@cea.fr       *
 *                                                                           *
 * Creation Date  : October 2024                                             *
 * Last update    :                                                          *
 *---------------------------------------------------------------------------*
 * Decription:                                                               *
 *  This event Generator is used to simulate fission events based on         *
 *  data files generated by the GEF model code (General Description of       *
 *  Fission Observables)                                                     *
 *---------------------------------------------------------------------------*
 * Comment:                                                                  *
 *                                                                           *
 *                                                                           *
 *****************************************************************************/
// C++
#include<limits>
#include<iostream>
#include<sstream>

// G4 headers
#include "G4ParticleTable.hh"
#include "G4IonTable.hh"
// G4 headers including CLHEP headers
// for generating random numbers
#include "Randomize.hh"

// NPS headers
#include "EventGeneratorGEFReader.hh"

// NPL headers
#include "RootOutput.h"
#include "NPNucleus.h"
#include "NPOptionManager.h"
#include "NPFunction.h"
using namespace CLHEP;


//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
EventGeneratorGEFReader::EventGeneratorGEFReader(){
  m_ParticleStack = ParticleStack::getInstance();
  event_ID=0;

  HasInputDataFile = false;
  m_FissionConditions = new TFissionConditions();
}



//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
EventGeneratorGEFReader::~EventGeneratorGEFReader(){
}


//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
EventGeneratorGEFReader::SourceParameters::SourceParameters(){

  m_x0           =  0  ;
  m_y0           =  0  ;
  m_z0           =  0  ;
  m_SigmaX       =  0  ;
  m_SigmaY       =  0  ;
  m_SigmaZ       =  0  ;
  m_direction    = 'z' ;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void EventGeneratorGEFReader::AttachFissionConditions(){
  if(RootOutput::getInstance()->GetTree()->FindBranch("FissionConditions"))
    RootOutput::getInstance()->GetTree()->SetBranchAddress("FissionConditions", &m_FissionConditions);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void EventGeneratorGEFReader::ReadConfiguration(NPL::InputParser parser){

  AttachFissionConditions();
  if(!RootOutput::getInstance()->GetTree()->FindBranch("FissionConditions")){
    RootOutput::getInstance()->GetTree()->Branch("FissionConditions", "TFissionConditions", &m_FissionConditions);
  }
  vector<NPL::InputBlock*> blocks = parser.GetAllBlocksWithToken("GEFReader");
  m_Parameters.reserve(blocks.size());
  if(NPOptionManager::getInstance()->GetVerboseLevel())
    cout << endl << "\033[1;35m//// GEFReader source found " << endl;

  vector<string> token = {"x0","y0","z0","Particle"};
  for(unsigned int i = 0 ; i < blocks.size() ; i++){
    if(blocks[i]->HasTokenList(token)){
      m_Parameters.push_back(SourceParameters());
      const vector<SourceParameters>::reverse_iterator it = m_Parameters.rbegin();

Benoit's avatar
Benoit committed
      if(blocks[i]->HasToken("GEFversion"))
      {
        it->m_GEFversion=blocks[i]->GetDouble("GEFversion","");
        if     (2023.11 <= it->m_GEFversion && it->m_GEFversion <= 2023.22) {
          version_shift=0;
          version_ff_shift=0;
        }
        else if(2023.31 <= it->m_GEFversion && it->m_GEFversion <= 2023.33) {
        else if(2024.11 <= it->m_GEFversion && it->m_GEFversion <= 2024.11){
        else {
          cout << "!!!!!!!!!!!!!!!!! ERROR: GEF version not verified !!!!!!!!!!!!!!!!!!" << endl;
          cout << "Check the column positions of your GEF file and" << endl;
          cout << "add the version to the correct shift in EventGeneratorGEFReader.cc" << endl;
          exit(1);
        }
      }
      if(blocks[i]->HasToken("InputDataFile")){
        vector<string> file = blocks[i]->GetVectorString("InputDataFile");
        fInputDataFile.open(file.at(0).c_str());
        HasInputDataFile = true;

        string line;
          //cout << "line : " << line << endl;
          if (line.find("*")==0) continue;
          
          count = std::distance(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>());
          {// Storing the first line to be read by GenerateEvent
            iss.clear();              
            iss.seekg(0, iss.beg);    
            double data;
            while(iss >> data) {
              //cout << "data = " << data << endl;
              LastLine.push_back(data);
            }
        it->m_direction=blocks[i]->GetString("Direction");
      it->m_x0                    = blocks[i]->GetDouble("x0","mm");
      it->m_y0                    = blocks[i]->GetDouble("y0","mm");
      it->m_z0                    = blocks[i]->GetDouble("z0","mm");
      vector<string> particleName = blocks[i]->GetVectorString("Particle");
      for(unsigned int j = 0 ; j < particleName.size() ; j++){
        if(particleName[j]=="proton"){ it->m_particleName.push_back("proton")  ;}
        else if(particleName[j]=="gamma") { it->m_particleName.push_back("gamma") ;}
        else if(particleName[j]=="neutron") {it->m_particleName.push_back("neutron") ;}
        else it->m_particleName.push_back(particleName[j]);
      }
      if(blocks[i]->HasToken("TwoBodyReaction")){
        string my_reaction = blocks[i]->GetString("TwoBodyReaction");
        m_TwoBodyReaction = new NPL::Reaction(my_reaction);
        m_isTwoBody = true;
      }

      //if(blocks[i]->HasToken("KineticEnergy_FS"))
      //it->m_Boost=blocks[i]->GetDouble("KineticEnergy_FS","MeV");
      if(blocks[i]->HasToken("FissioningSystem"))
      {
        it->m_FissioningSystemName=blocks[i]->GetString("FissioningSystem");
        m_FissioningSystem=new NPL::Particle(it->m_FissioningSystemName);
        m_FissioningSystem->SetKineticEnergy(0,0,0);
      if(blocks[i]->HasToken("BeamProfile"))
        it->m_BeamProfile=blocks[i]->GetString("BeamProfile");
      if(blocks[i]->HasToken("SigmaX"))
        it->m_SigmaX=blocks[i]->GetDouble("SigmaX","mm");
      if(blocks[i]->HasToken("SigmaY"))
        it->m_SigmaY=blocks[i]->GetDouble("SigmaY","mm");
      if(blocks[i]->HasToken("SigmaZ"))
audrey.chatillon's avatar
audrey.chatillon committed
        it->m_SigmaZ=blocks[i]->GetDouble("SigmaZ","um");  // attention in um
    }
    else{
      cout << "ERROR: check your input file formatting \033[0m" << endl;
      exit(1);
    }
  }
  for(auto& par : m_Parameters) {
    for(auto partName: par.m_particleName){
      AllowedParticles.push_back(partName);
    }
    cout << "///////// Warning: Only ";
    for(auto particle: AllowedParticles) cout << particle << ", " ;
    cout << "will be simulated" << endl;

    if(AllowedParticles.size()==0) cout << "//////// All particles of the file will be simulated" << endl;
  }
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void EventGeneratorGEFReader::GetBoostFromTwoBodyReaction(double Ex){
  double Theta3, E3;
  double Theta4, E4;
  double ThetaCM = RandFlat::shoot() * 2 * pi;
  m_TwoBodyReaction->SetExcitation4(Ex);
  m_TwoBodyReaction->SetThetaCM(ThetaCM);
  m_TwoBodyReaction->KineRelativistic(Theta3,E3,Theta4,E4);

  double Phi4 = RandFlat::shoot() * 2 * pi;
  m_FissioningSystem->SetKineticEnergy(E4,Theta4,Phi4);

  m_TwoBodyReaction->SetParticle3(E3,Theta3,Phi3);
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void EventGeneratorGEFReader::GenerateEvent(G4Event*){
  m_FissionConditions->Clear();
  for(auto& par : m_Parameters) {
    int fileParticleMultiplicity=-1;
    vector<double>                ELab;
    vector<double>                CosThetaLab;
    vector<double>                PhiLab;
    vector<G4ParticleDefinition*> vParticle;

    vector<int>    ZFrag;
    vector<int>    AFrag;
    vector<double> ELabFrag;
    vector<double> cos_thetaFrag;
    vector<double> PhiFrag;
    vector<int>    NneutronsEmission; // may be used to correct the energy of the fragments
    double         CN_ExcitationEnergy;

    TVector3 LightFragmentDirection(0,0,1.);
    TVector3 HeavyFragmentDirection(0,0,1.);
    TLorentzVector ImpulsionFrag[2];

    NPL::Particle *Neutron=new NPL::Particle("1n");
    NPL::Particle *Proton=new NPL::Particle("1H");
    NPL::Particle *Gamma=new NPL::Particle("gamma");
    NPL::Particle *Fragment;
    int it=0; 

    int index_Z_CN  =  0 + version_shift;                    // Zsad
    int index_A_CN  =  1 + version_shift;                    // Asad
    int index_Ex    = 24 + version_shift + version_ff_shift; // E@fission
    int data_length = 25 + version_shift + version_ff_shift; // data length of CN and FF, without particle-list info prior to fission
    
    int index_Zf[2];
    int index_Af[2];
    int index_ELabf[2];
    int index_nf[2];
    for(int frag=0; frag<2; frag++){
      index_Zf[frag] = 2 + frag + version_shift + version_ff_shift;
      index_Af[frag] = 6 + frag + version_shift + version_ff_shift;
      index_ELabf[frag] = 12 + 3*frag + version_shift + version_ff_shift;
      index_nf[frag] = 20 + frag + version_shift + version_ff_shift;
    }
    if(HasInputDataFile && !fInputDataFile.eof())
    {
      fileParticleMultiplicity=0;
      // for(int GEFline=0;GEFline<4;GEFline++)
      while(it==0 || LastLine.size()==1 || (LastLine.size()>0 && LastLine.at(1)<50))
        it++;
        string         line;
        getline(fInputDataFile,line);
        //cout << line << endl;

        istringstream  iss(line);
        double         data;
        vector<double> DataLine;

        //   cout << "it=" << it << " line=" << line << endl;

        DataLine = LastLine;
        LastLine.clear();

        while(iss >> data) LastLine.push_back(data);

        //cout << "line starts with " << DataLine.at(0) << " length : " << DataLine.size() << endl;
        //for (int d=0; d<DataLine.size(); d++){
        //	cout << d << " " << DataLine.at(d) << endl;
        //}


        // FIRST LINE OF THE FISSION EVENT : 
        // data on CN, FFl, FFh and possibly pre-fission emission
        if(DataLine.size()>=data_length && DataLine.at(index_Z_CN)>50)
          double Ex  = DataLine.at(index_Ex); // Excitation energy at fission
          if(m_isTwoBody){
            GetBoostFromTwoBodyReaction(Ex);
            Ejectile = m_TwoBodyReaction->GetParticle3();
          }
          FissioningSystemBoost = m_FissioningSystem->GetEnergyImpulsion().BoostVector();
          // Compound nucleus (after pre-fission emission)
          int Z_CN = DataLine.at(index_Z_CN);
Benoit's avatar
Benoit committed
          int A_CN = DataLine.at(index_A_CN);
          m_FissionConditions->SetZ_CN(Z_CN);
          m_FissionConditions->SetA_CN(A_CN);
          m_FissionConditions->SetEx_CN(Ex);
          m_FissionConditions->SetELab_CN(m_FissioningSystem->GetEnergy());
          m_FissionConditions->SetThetaLab_CN(m_FissioningSystem->GetEnergyImpulsion().Theta());

          // Fragment emission
          for(int frag=0;frag<2;frag++)
          {
            int            Zf = DataLine.at(index_Zf[frag]);
            int            Af = DataLine.at(index_Af[frag]); // Post-scission
            double      ELabf = DataLine.at(index_ELabf[frag]);
            double cos_thetaf = DataLine.at(index_ELabf[frag]+1);
            double       Phif = DataLine.at(index_ELabf[frag]+2) *M_PI/180;
            Fragment=new NPL::Particle(Zf,Af);
            Fragment->SetKineticEnergy(ELabf);
            Fragment->EnergyToEnergyImpulsion(ELabf,acos(cos_thetaf),Phif);

            ImpulsionFrag[frag] = Fragment->GetEnergyImpulsion();
            ImpulsionFrag[frag].Boost(FissioningSystemBoost);

            if(frag==0) LightFragmentDirection.SetMagThetaPhi(1.,acos(cos_thetaf),Phif);

            ELabf      = ImpulsionFrag[frag].E() - Fragment->Mass();
            cos_thetaf = ImpulsionFrag[frag].CosTheta();

            ZFrag            .push_back( Zf );
            AFrag            .push_back( Af );
            ELabFrag         .push_back( ELabf );
            cos_thetaFrag    .push_back( cos_thetaf);
            PhiFrag          .push_back( Phif);
            NneutronsEmission.push_back( DataLine.at(index_nf[frag]));
            //delete Fragment;

            // Filling fission conditions
            m_FissionConditions->SetFragmentZ(Zf);
            m_FissionConditions->SetFragmentA(Af);
            m_FissionConditions->SetFragmentKineticEnergy(ELabf);
            m_FissionConditions->SetFragmentBrho(Fragment->GetBrho());
            m_FissionConditions->SetFragmentTheta(acos(cos_thetaf));
            m_FissionConditions->SetFragmentPhi(Phif);
          } // end of Fragment emission
          CN_ExcitationEnergy = DataLine.at(index_Ex);
          // Particle emission before fission
          if(DataLine.size()>data_length)
            string ParticleList = to_string(DataLine.at(data_length));
            for(char type: ParticleList) // read one digit of the particle list 
              if((type=='1' || type=='3' || type=='5')
                  && (AllowedParticles.size()==0 || std::find(AllowedParticles.begin(), AllowedParticles.end(), "neutron") != AllowedParticles.end()))
              {// Pre-fission neutron treatment:

                double      ELabn = DataLine.at(data_length + 1 + idx*3);
                double cos_thetan = DataLine.at(data_length + 2 + idx*3);
                double       Phin = RandFlat::shoot() * 2 * pi;
                Neutron->SetKineticEnergy(ELabn,acos(cos_thetan),Phin);

                TLorentzVector ImpulsionNeutron = Neutron->GetEnergyImpulsion();
                ImpulsionNeutron.Boost(FissioningSystemBoost);
                ELabn      = ImpulsionNeutron.E() - Neutron->Mass();
                cos_thetan = ImpulsionNeutron.CosTheta();			  

                ELab       .push_back(ELabn);
                CosThetaLab.push_back(cos_thetan);
                PhiLab     .push_back(Phin);
                vParticle  .push_back(G4ParticleTable::GetParticleTable()->FindParticle("neutron"));

                fileParticleMultiplicity++;
                idx++;
              }
              else if((type=='2' || type=='4')
                  && (AllowedParticles.size()==0 || std::find(AllowedParticles.begin(), AllowedParticles.end(), "proton") != AllowedParticles.end()))
              {// Pre-fission proton treatment:
                double      ELabp = DataLine.at(data_length + idx*3);
                double cos_thetap = DataLine.at(data_length + idx*3);
                double       Phip = RandFlat::shoot() * 2 * pi;
                Proton->SetKineticEnergy(ELabp,acos(cos_thetap),Phip);

                TLorentzVector ImpulsionProton = Proton->GetEnergyImpulsion();
                ImpulsionProton.Boost(FissioningSystemBoost);
                ELabp      = ImpulsionProton.E() - Proton->Mass();
                cos_thetap = ImpulsionProton.CosTheta();			  

                ELab       .push_back(ELabp);
                CosThetaLab.push_back(cos_thetap);
                PhiLab     .push_back(RandFlat::shoot() * 2 * pi);
                vParticle  .push_back(G4ParticleTable::GetParticleTable()->FindParticle("proton"));

                fileParticleMultiplicity++;
                idx++;
              }
              else if(type=='0') break; // if digit is 0, end of particle emission
        // IF THE OPTIONS OF PROMPT-NEUTRON AND/OR PROMPT GAMMA EMISSION BY FF IS SWITCH ON IN GEF INPUT
        // NEUTRONS: first line has 0 at DataLine.(0) and gives the list of the post-scission neutrons  
        else if(DataLine.size()>0 && DataLine.at(0)==0 
            && (AllowedParticles.size()==0 || std::find(AllowedParticles.begin(), AllowedParticles.end(), "neutron") != AllowedParticles.end()))
          for(int it=0;it<(DataLine.size()-1)/3;it++)
          {// Promt fission neutron treatment
            double ELabn      = DataLine.at(1+3*it);
            double cos_thetan = DataLine.at(2+3*it);
            double Phin       = DataLine.at(3+3*it) *M_PI/180.;
            TVector3 NeutronLabAngle(0,0,1.);
            NeutronLabAngle.SetMagThetaPhi(1.,acos(cos_thetan),Phin);
            NeutronLabAngle.RotateUz(LightFragmentDirection);
            Neutron->SetKineticEnergy(ELabn,NeutronLabAngle.Theta(),NeutronLabAngle.Phi());
            TLorentzVector ImpulsionNeutron = Neutron->GetEnergyImpulsion();
            ImpulsionNeutron.Boost(FissioningSystemBoost);
            ELabn      = ImpulsionNeutron.E()-Neutron->Mass();
            cos_thetan = ImpulsionNeutron.CosTheta();
            Phin       = NeutronLabAngle.Phi();
            ELab       .push_back(ELabn);
            CosThetaLab.push_back(cos_thetan);
            PhiLab     .push_back(Phin);
            vParticle  .push_back(G4ParticleTable::GetParticleTable()->FindParticle("neutron"));
            fileParticleMultiplicity++;
        // GAMMA-RAYS: gamma from light (DataLine.at(0) in [3..5]) and heavy (DataLine.at(0) in[6..8])
        else if(DataLine.size()>0 && (DataLine.at(0)>=3 && DataLine.at(0)<=8)
            && (AllowedParticles.size()==0 || std::find(AllowedParticles.begin(), AllowedParticles.end(), "gamma") != AllowedParticles.end()))
          for(int it=0;it<(DataLine.size()-1);it++)
          {// Prompt fission gamma treatment

            if((DataLine.at(0)==5 || DataLine.at(0)==8) && (to_string(DataLine.at(it+1))=="GS" || to_string(DataLine.at(it+1)).at(0)=='M'))
            {
              cout << "DataLine.at(it+1)=" << DataLine.at(it+1) << endl;
              break;
            }

            double ELabg      = DataLine.at(it+1);
            double cos_thetag = RandFlat::shoot(-1.,1.);
            double Phig       = RandFlat::shoot() * 2 * pi;

            Gamma->SetKineticEnergy(ELabg,acos(cos_thetag),Phig);
            TLorentzVector ImpulsionGamma = Gamma->GetEnergyImpulsion();
            if(DataLine.at(0)<=5)
              ImpulsionGamma.Boost(ImpulsionFrag[0].BoostVector());
            else if(DataLine.at(0)<=8)
              ImpulsionGamma.Boost(ImpulsionFrag[1].BoostVector());

            ImpulsionGamma.Boost(FissioningSystemBoost);
            ELabg      = ImpulsionGamma.E();
            cos_thetag = ImpulsionGamma.CosTheta();		  

            ELab       .push_back( ELabg);
            CosThetaLab.push_back( cos_thetag); // Need to add the fragment boost to the gamma emission. 
            PhiLab     .push_back( Phig);
            vParticle  .push_back(G4ParticleTable::GetParticleTable()->FindParticle("gamma"));

            fileParticleMultiplicity++;
          }
        cout << "Problem with Input data file ? no more data to put in" << endl;
        return;
    }
    else
    {
      cout << "Problem with Input data file ? no data to put in" << endl;
      return;
    }

    G4double x0, y0, z0;
    TVector3 Momentum;
    if(par.m_BeamProfile=="Flat"){
      double rand_r     = par.m_SigmaX*sqrt(RandFlat::shoot());
      double rand_theta = RandFlat::shoot() * 2. * pi;
      x0 = par.m_x0 + rand_r * cos(rand_theta);
      y0 = par.m_y0 + rand_r * sin(rand_theta);
audrey.chatillon's avatar
audrey.chatillon committed
      z0 = RandFlat::shoot(par.m_z0*mm-par.m_SigmaZ*mm, par.m_z0*mm+par.m_SigmaZ*mm);
      //cout << "Circular Flat beam profile: x0 = " << x0 << ", y0 = " << y0 << ", z0 = " << z0 << endl;
    }
    else{ // by default gaussian beam profile is considered 
      x0 = RandGauss::shoot(par.m_x0,par.m_SigmaX);
      y0 = RandGauss::shoot(par.m_y0,par.m_SigmaY);
      z0 = RandGauss::shoot(par.m_z0,par.m_SigmaZ);
    if(AllowedParticles.size()==0 || std::find(AllowedParticles.begin(), AllowedParticles.end(), "fragments") != AllowedParticles.end())
      for(int i_m=0;i_m<2;i_m++)
	{
	  G4double theta                          = acos(cos_thetaFrag.at(i_m)) ;
	  G4double phi                            = PhiFrag.at(i_m)         ;
	  G4double particle_energy                = ELabFrag.at(i_m)           ;
	  G4ParticleDefinition* GeneratedParticle = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(ZFrag.at(i_m),AFrag.at(i_m),0.);

	  Momentum = ShootParticle(theta,phi,par.m_direction);
	  //cout << "particle_energy=" << particle_energy << endl;
	  NPS::Particle particle(GeneratedParticle, theta,particle_energy,G4ThreeVector(Momentum.x(), Momentum.y(), Momentum.z()),G4ThreeVector(x0, y0, z0));
	  m_ParticleStack->AddParticleToStack(particle);
	}

    for(int i_m=0;i_m<fileParticleMultiplicity;i_m++)
	G4double theta                          = acos(CosThetaLab.at(i_m)) ;
	G4double phi                            = PhiLab.at(i_m)            ;
	G4double particle_energy                = ELab.at(i_m)              ;
	G4ParticleDefinition* GeneratedParticle = vParticle.at(i_m)         ;

	Momentum = ShootParticle(theta,phi,par.m_direction);

	NPS::Particle particle(GeneratedParticle, theta,particle_energy,G4ThreeVector(Momentum.x(), Momentum.y(), Momentum.z()),G4ThreeVector(x0, y0, z0));
	if(particle_energy<=20.0) // NeutronHP crashes for neutrons of higher energies. Need to use a different physics list.
	  m_ParticleStack->AddParticleToStack(particle);
    if(m_isTwoBody){
      G4double theta                          = Ejectile->GetImpulsion().Theta();
      G4double phi                            = Ejectile->GetImpulsion().Phi();
      G4double particle_energy                = Ejectile->GetEnergy();
      G4ParticleDefinition* GeneratedParticle = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(Ejectile->GetZ(),Ejectile->GetA(),0.);

      Momentum = ShootParticle(theta,phi,par.m_direction);
      //cout << "particle_energy=" << particle_energy << endl;
      NPS::Particle particle(GeneratedParticle, theta,particle_energy,G4ThreeVector(Momentum.x(), Momentum.y(), Momentum.z()),G4ThreeVector(x0, y0, z0));
      m_ParticleStack->AddParticleToStack(particle);

    }
  }
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void EventGeneratorGEFReader::InitializeRootOutput(){

}

TVector3 EventGeneratorGEFReader::ShootParticle(double theta,double phi,TString direction){
  G4double momentum_x, momentum_y, momentum_z;
  if(direction == 'z')
  {
    // Direction of particle, energy and laboratory angle
    momentum_x = sin(theta) * cos(phi)  ;
    momentum_y = sin(theta) * sin(phi)  ;
    momentum_z = cos(theta)             ;
  else if(direction == 'y')
  {
    // Direction of particle, energy and laboratory angle
    momentum_z = sin(theta) * cos(phi)  ;
    momentum_x = sin(theta) * sin(phi)  ;
    momentum_y = cos(theta)             ;
  }
  {
    // Direction of particle, energy and laboratory angle
    momentum_y = sin(theta) * cos(phi)  ;
    momentum_z = sin(theta) * sin(phi)  ;
    momentum_x = cos(theta)             ;
  }

  TVector3 Momentum(momentum_x,momentum_y,momentum_z);

  return Momentum;
}