Skip to content
Snippets Groups Projects
EventGeneratorGEFReader.cc 21.44 KiB
/*****************************************************************************
 * 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;

  m_isTwoBody = false;
  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_Boost        =  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();

      if(blocks[i]->HasToken("GEFversion"))
      {
        it->m_GEFversion=blocks[i]->GetDouble("GEFversion","");
        if(it->m_GEFversion>=2023.32 && it->m_GEFversion<=2024.33) version_shift=0;
        else if (it->m_GEFversion>=2023.11 && it->m_GEFversion<=2023.12) version_shift=1;
        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;
        string comment="*";
        double data=0;

        while(comment=="*" || data==0)
        {
          getline(fInputDataFile,line);
          istringstream iss(line);
          //cout << "line : " << line << endl;

          iss >> data;
          comment=to_string(data);
          if(comment!="*" && data>0)
          {// Storing the first line to be read by GenerateEvent
            LastLine.push_back(data);
            while(iss >> data) LastLine.push_back(data);
            break;
          }
        }
      }

      if(blocks[i]->HasToken("Direction")){
        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("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"))
        it->m_SigmaZ=blocks[i]->GetDouble("SigmaZ","mm");

    }
    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;
  double Phi3 = Phi4 - 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;
    NPL::Particle *Ejectile;
    TVector3 FissioningSystemBoost;
    int it=0;

    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;
        //}

        if(DataLine.size()>=26 && DataLine.at(1)>50)
        {
          double Ex  = DataLine.at(25); // Excitation energy at fission
          if(m_isTwoBody){
            GetBoostFromTwoBodyReaction(Ex);
            Ejectile = m_TwoBodyReaction->GetParticle3();
          }
          FissioningSystemBoost = m_FissioningSystem->GetEnergyImpulsion().BoostVector();

          int Z_CN = DataLine.at(1);
          int A_CN = DataLine.at(2);

          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(3 + frag);
            int            Af = DataLine.at(7 + frag); // Post-scission
            double      ELabf = DataLine.at(13 + 3*frag);
            double cos_thetaf = DataLine.at(14 + 3*frag);
            double       Phif = DataLine.at(15 + 3*frag) *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(21 + 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);
          }
          CN_ExcitationEnergy = DataLine.at(25);

          if(DataLine.size()>26)
          {
            // Particle emission by the CN before fission
            string ParticleList = to_string(DataLine.at(26));
            int idx=0;
            for(char type: ParticleList)
              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(27 + idx*3);
                double cos_thetan = DataLine.at(28 + 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(27 + idx*3);
                double cos_thetap = DataLine.at(28 + 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;
          }
        }
        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++;

          }

        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++;
          }
      }
      if(fInputDataFile.eof())
      {
        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;

    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);

    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(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);
      }
    
    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)             ;
  }
  else // = 'x'
  {
    // 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;
}