Skip to content
Snippets Groups Projects
Forked from atlas / athena
57215 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Epos.cxx 11.65 KiB
/*
  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
*/

// ---------------------------------------------------------------------- 
// Generators/Epos.cxx
//  
// Description: Allows the user to generate epos events and store the result 
// in the Transient Store.
//
// AuthorList: 
//   Sami Kama:       Initial code.
//   Sebastian Piec:  Adaptation for Epos 1.99.crmc.r2790.
// ---------------------------------------------------------------------- 

#include "TruthUtils/GeneratorName.h"

#include "GaudiKernel/MsgStream.h"
#include "CLHEP/Random/RandFlat.h"
#include "AthenaKernel/IAtRndmGenSvc.h"

#include "AtlasHepMC/IO_HEPEVT.h"
#include "AtlasHepMC/GenEvent.h"
#include "AtlasHepMC/HeavyIon.h"
#include "AtlasHepMC/SimpleVector.h"


#include "Epos_i/Epos.h"

#ifdef HEPMC3
#include "CRMChepevt.h"
#endif

namespace{
  static std::string epos_rndm_stream = "EPOS_INIT";
  static IAtRndmGenSvc* p_AtRndmGenSvcEpos = 0;
}

extern "C" double atl_epos_rndm_( int* ) 
{
  CLHEP::HepRandomEngine* engine = p_AtRndmGenSvcEpos->GetEngine(epos_rndm_stream);
  return CLHEP::RandFlat::shoot(engine);
}

// ---------------------------------------------------------------------- 
// Epos Fortran bindings.
// ---------------------------------------------------------------------- 
extern "C" 
{
    // generator initialization
   void crmc_init_f_( double &m_degymx, int &iSeed, int &model, int &itab, int &itypout, const char *paramFile, const char *output , int &lout);

   void crmc_set_f_( int &nEvents,double &beamMomentum, double &targetMomentum, int &primaryParticle, int &targetParticle);

    // event generation
  void crmc_f_( int &iout, int &ievent, int &nParticles, double &impactParam, int &partPdg, 
		double &partPx, double &partPy, double &partPz, double &partEnergy, double &partMass, int &outstat );

    // cross section info 
  void crmc_xsection_f_(double &xsigtot, double &xsigine, double &xsigela, double &xsigdd, 
      double &xsigsd, double &xsloela, double &xsigtotaa, double &xsigineaa, double &xsigelaaa);

}

// ----------------------------------------------------------------------
Epos::Epos( const std::string &name, ISvcLocator *pSvcLocator ): 
  GenModule( name, pSvcLocator )
{
  m_interface = nullptr;
  epos_rndm_stream = "EPOS_INIT";
  
  declareProperty( "BeamMomentum",    m_beamMomentum    = -6500.0 );      // GeV
  declareProperty( "TargetMomentum",  m_targetMomentum  = 6500.0 );
  declareProperty( "Model",           m_model           = 7 );            // 0=EPOS 1.99 LHC, 1=EPOS 1.99
  declareProperty( "PrimaryParticle", m_primaryParticle = 1 );            // 1=p, 12=C, 120=pi+, 207=Pb 
  declareProperty( "TargetParticle",  m_targetParticle  = 1 );
  declareProperty( "ParamFile",       m_paramFile       = "crmc.param" );
  declareProperty( "LheOutput",       m_ilheout       = 0 );
  declareProperty( "LheFile",         m_lheout       = "epos.lhe" );
  declareProperty( "TabCreate",       m_itab       = 0 );
  declareProperty( "nEvents",         m_nEvents    = 5500 );
  declareProperty( "maxCMEnergy",     m_degymx     = 13000.0 ); // maximum center-of-mass energy which will be call in the run [GeV]
  
  m_events = 0; // current event number (counted by interface)
  m_ievent = 0;  // current event number counted by Epos
  m_iout = 0; // output type (output)

  // initialize internally used arrays
  ATH_MSG_INFO( "max number of Particles  " << kMaxParticles );
  m_partID.resize (kMaxParticles);
  m_partPx.resize (kMaxParticles);
  m_partPy.resize (kMaxParticles);
  m_partPz.resize (kMaxParticles);
  m_partEnergy.resize (kMaxParticles);
  m_partMass.resize (kMaxParticles);
  m_partStat.resize (kMaxParticles);
  for (size_t i = 0; i < kMaxParticles; ++i) {
    m_partID[i] = 0;
    m_partPx[i] = m_partPy[i] = m_partPz[i] = m_partEnergy[i] = m_partMass[i] = 0.0;
    m_partStat[i] = 0;
  }

}

// ----------------------------------------------------------------------
Epos::~Epos()
{}

// ----------------------------------------------------------------------
StatusCode Epos::genInitialize() 
{
  ATH_MSG_INFO( " CRMC INITIALISING.\n" );
  ATH_MSG_INFO( "signal_rocess_id 101-ND, 105-DD, 102-CD, 103 AB->XB, 104 AB->AX \n");

  static const bool CREATEIFNOTTHERE = true;
  
  StatusCode RndmStatus = service("AtRndmGenSvc", p_AtRndmGenSvcEpos, CREATEIFNOTTHERE);
  if ( !RndmStatus.isSuccess() || 0 == p_AtRndmGenSvcEpos ) {
    ATH_MSG_ERROR( " Could not initialize Random Number Service!" );
    return RndmStatus;
  }
   
  CLHEP::HepRandomEngine *engine = p_AtRndmGenSvcEpos->GetEngine(epos_rndm_stream);
  const long *sip = engine->getSeeds();
  long int si1 = sip[0];
  long int si2 = sip[1];

  int iSeed = si1%1000000000;     // FIXME ?
  int lout = 50;     //lenght of the output string (useful only for LHE output)
  // initialise Epos and set up initial values 

    crmc_init_f_( m_degymx, iSeed, m_model, m_itab, m_ilheout, (m_paramFile + " ").c_str(), m_lheout.c_str() , lout);
    crmc_set_f_(m_nEvents,m_beamMomentum, m_targetMomentum, m_primaryParticle, m_targetParticle);


    // ... and set them back to the stream for proper save
  p_AtRndmGenSvcEpos->CreateStream( si1, si2, epos_rndm_stream );

  epos_rndm_stream = "EPOS";
    // setup HepMC
#ifdef HEPMC3
    /// Not needed anymore
#else    
    HepMC::HEPEVT_Wrapper::set_sizeof_int(sizeof( int ));
    HepMC::HEPEVT_Wrapper::set_sizeof_real( 8 );
    HepMC::HEPEVT_Wrapper::set_max_number_entries(kMaxParticles);
#endif

  m_events = 0;

  //  m_ascii_out = new HepMC::IO_GenEvent(m_eposEventInfo);
 
 return StatusCode::SUCCESS;
}

// ---------------------------------------------------------------------- 
StatusCode Epos::callGenerator() 
{
  // ATH_MSG_INFO( " EPOS Generating." );

    // save the random number seeds in the event
    CLHEP::HepRandomEngine* engine = p_AtRndmGenSvcEpos->GetEngine( epos_rndm_stream );
   const long *s = engine->getSeeds();
  
   m_seeds.clear();
   m_seeds.push_back(s[0]);
   m_seeds.push_back(s[1]);

   ++m_events;
  
    // as in crmchep.h
  int nParticles = 0;
  double impactParameter = -1.0;
 
    // generate event 
  crmc_f_( m_iout, m_ievent ,nParticles, impactParameter, m_partID[0], m_partPx[0], m_partPy[0], m_partPz[0], 
	   m_partEnergy[0], m_partMass[0], m_partStat[0]  );




  return StatusCode::SUCCESS;
}

// ---------------------------------------------------------------------- 
StatusCode Epos::genFinalize() 
{
  ATH_MSG_INFO("EPOS finalizing.");

  std::cout << "MetaData: generator = Epos " << std::endl;

    // retrieve information about the total cross-section from Epos
  double xsigtot, xsigine, xsigela, xsigdd, xsigsd, xsloela, xsigtotaa, xsigineaa, xsigelaaa;
  xsigtot = xsigine = xsigela = xsigdd = xsigsd = xsloela = xsigtotaa = xsigineaa = xsigelaaa = 0.0;
   
  crmc_xsection_f_(xsigtot, xsigine, xsigela, xsigdd, xsigsd, xsloela, xsigtotaa, xsigineaa, xsigelaaa);
  
  xsigtot *= 1000000;         // [mb] to [nb] conversion
  std::cout << "MetaData: cross-section (nb) = " << xsigtot << std::endl;
  xsigine *= 1000000;        //[mb] to [nb] conversion
  std::cout << "MetaData: cross-section inelastic (cut + projectile diffraction)[nb] = " << xsigine << std::endl;
     xsigela *= 1000000;         // [mb] to [nb] conversion
  std::cout << "MetaData: cross-section elastic (includes target diffraction)[nb] = " << xsigela << std::endl;
  xsigdd *= 1000000;         // [mb] to [nb] conversion
  std::cout << "MetaData: cross-section dd (nb) = " << xsigdd << std::endl;
  xsigsd *= 1000000;         // [mb] to [nb] conversion
  std::cout << "MetaData: cross-section sd (nb) = " << xsigsd << std::endl;

  //  m_eposEventInfo.close();

  return StatusCode::SUCCESS;
}

// ---------------------------------------------------------------------- 
StatusCode Epos::fillEvt( HepMC::GenEvent* evt ) 
{
#ifdef HEPMC3
  CRMChepevt<HepMC3::GenParticlePtr, HepMC3::GenVertexPtr, HepMC3::FourVector, HepMC3::GenEvent> hepevtconverter;
  hepevtconverter.convert(*evt);
#else
  /// We use the old approach for HepMC2, as the CRMC 2.0.1 has a bug that prevents us from using the same approach as for HepMC3.
  /// This should be changed once the bug is fixed.
  HepMC::IO_HEPEVT hepio;
  hepio.set_trust_mothers_before_daughters(0);
  hepio.set_print_inconsistency_errors(0);
  hepio.fill_next_event(evt);
#endif
  evt->set_event_number(m_events);

  HepMC::set_random_states(evt, m_seeds );

  evt->weights().push_back(1.0); 
  //correct units, for hepMC printing uncomment lines below
#ifdef HEPMC3
    evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
//    std::cout << " print::listing Epos " << std::endl;
//    HepMC3::Print::listing(std::cout, *evt);
#else
    GeVToMeV(evt);
//    std::cout << " print::printing Epos " << std::endl;
//    evt->print();
#endif
  
  std::vector<HepMC::GenParticlePtr> beams;

  for (auto p: *evt) {
    if (p->status() == 4) {
      beams.push_back(p);
   }
  }

  if (beams.size() >= 2) {
  evt->set_beam_particles(beams[0], beams[1]); 
  } else {
    ATH_MSG_INFO( "EPOS event has only " << beams.size() << " beam particles" );
  }

  // Heavy Ion and Signal ID from Epos to HepMC

#ifdef HEPMC3
     HepMC::GenHeavyIonPtr ion= std::make_shared<HepMC::GenHeavyIon>();
                      ion->Ncoll_hard=cevt_.kohevt;
                      ion->Npart_proj=cevt_.npjevt;
                      ion->Npart_targ=cevt_.ntgevt;
                      ion->Ncoll=cevt_.kolevt;
                      ion->spectator_neutrons=cevt_.npnevt + cevt_.ntnevt;
                      ion->spectator_protons=cevt_.nppevt + cevt_.ntpevt;
                      ion->N_Nwounded_collisions=-1;
                      ion->Nwounded_N_collisions=-1;
                      ion->Nwounded_Nwounded_collisions=-1;
                      ion->impact_parameter= cevt_.bimevt;
                      ion->event_plane_angle=cevt_.phievt;
                      ion->eccentricity=-1;  //c2evt_.fglevt,  //correct name but not defined
                      ion->sigma_inel_NN=1e9*hadr5_.sigine;
#else
     HepMC::HeavyIon ion(cevt_.kohevt,
                      cevt_.npjevt,
                      cevt_.ntgevt,
                      cevt_.kolevt,
                      cevt_.npnevt + cevt_.ntnevt,
                      cevt_.nppevt + cevt_.ntpevt,
                      -1,
                      -1,
                      -1,
                      cevt_.bimevt,
                      cevt_.phievt,
                      -1,  //c2evt_.fglevt,  //correct name but not defined
                      1e9*hadr5_.sigine);
#endif

		      evt->set_heavy_ion(ion);  

  //an integer ID uniquely specifying the signal process (i.e. MSUB in Pythia)
  // Epos 1-ND, 2-DD, 3-CD, 4 AB->XB, -4 AB->AX translated into signal_proces_id 101-ND, 105 - DD, 102 - CD, 103 -AB->XB, 104 AB->AX
   int sig_id = -1;
   switch (int(c2evt_.typevt))
    {
    case  1: sig_id = 101; break;
    case -1: sig_id = 101; break;
    case  2: sig_id = 105; break;
    case -2: sig_id = 105; break;
    case  3: sig_id = 102; break;
    case -3: sig_id = 102; break;
    case  4: sig_id = 103; break;
    case -4: sig_id = 104; break;
    default: ATH_MSG_INFO( "Signal ID not recognised for setting HEPEVT \n");
    }

  HepMC::set_signal_process_id(evt,sig_id);

  double xsigtot, xsigine, xsigela, xsigdd, xsigsd, xsloela, xsigtotaa, xsigineaa, xsigelaaa;
  xsigtot = xsigine = xsigela = xsigdd = xsigsd = xsloela = xsigtotaa = xsigineaa = xsigelaaa = 0.0;
  crmc_xsection_f_(xsigtot, xsigine, xsigela, xsigdd, xsigsd, xsloela, xsigtotaa, xsigineaa, xsigelaaa);
  xsigtot *= 1000000;         // [mb] to [nb] conversion
#ifdef HEPMC3
  std::shared_ptr<HepMC3::GenCrossSection> xsec = std::make_shared<HepMC3::GenCrossSection>();
  xsec->set_cross_section(xsigine, 0.0);
#else
  HepMC::GenCrossSection xsec;
  xsec.set_cross_section(xsigine, 0.0);
#endif
  evt->set_cross_section(xsec);

 return StatusCode::SUCCESS;
}