diff --git a/CepGen/Core/Generator.cpp b/CepGen/Core/Generator.cpp index 7d97c71..b56e13b 100644 --- a/CepGen/Core/Generator.cpp +++ b/CepGen/Core/Generator.cpp @@ -1,139 +1,140 @@ #include "CepGen/Generator.h" #include "CepGen/Parameters.h" #include "CepGen/Core/Integrator.h" #include "CepGen/Core/Exception.h" +#include "CepGen/Processes/GenericProcess.h" #include "CepGen/Event/Event.h" #include <fstream> namespace CepGen { Generator::Generator() : parameters( std::unique_ptr<Parameters>( new Parameters ) ), cross_section_( -1. ), cross_section_error_( -1. ), has_cross_section_( false ) { if ( Logger::get().level > Logger::Nothing ) { Debugging( "Generator initialized" ); try { printHeader(); } catch ( Exception& e ) { e.dump(); } } srand( time( 0 ) ); // Random number initialization } Generator::Generator( Parameters* ip ) : parameters( ip ) {} Generator::~Generator() { if ( parameters->generation.enabled && parameters->process() && parameters->process()->numGeneratedEvents()>0 ) { Information( Form( "Mean generation time / event: %.3f ms", parameters->process()->totalGenerationTime()*1.e3/parameters->process()->numGeneratedEvents() ) ); } } size_t Generator::numDimensions() const { if ( !parameters->process() ) return 0; return parameters->process()->numDimensions( parameters->kinematics.mode ); } void Generator::clearRun() { integrator_.reset(); parameters->integrator.first_run = true; has_cross_section_ = false; // force the recreation of the integrator instance cross_section_ = cross_section_error_ = -1.; } void Generator::setParameters( Parameters& ip ) { parameters = std::unique_ptr<Parameters>( new Parameters( ip ) ); // copy constructor } void Generator::printHeader() { std::string tmp; std::ostringstream os; os << std::endl; std::ifstream hf( "README" ); if ( !hf.good() ) throw Exception( __PRETTY_FUNCTION__, "Failed to open README file", JustWarning ); while ( true ) { if ( !hf.good() ) break; getline( hf, tmp ); os << "\n " << tmp; } hf.close(); Information( os.str().c_str() ); } double Generator::computePoint( double* x ) { prepareFunction(); double res = f( x, numDimensions(), (void*)parameters.get() ); std::ostringstream os; for ( unsigned int i=0; i<numDimensions(); i++ ) { os << x[i] << " "; } Debugging( Form( "Result for x[%zu] = ( %s):\n\t%10.6f", numDimensions(), os.str().c_str(), res ) ); return res; } void Generator::computeXsection( double& xsec, double& err ) { // first destroy and recreate the integrator instance if ( !integrator_ ) { integrator_ = std::unique_ptr<Integrator>( new Integrator( numDimensions(), f, parameters.get() ) ); } else if ( integrator_->dimensions() != numDimensions() ) { integrator_.reset( new Integrator( numDimensions(), f, parameters.get() ) ); } if ( Logger::get().level>=Logger::Debug ) { std::ostringstream topo; topo << parameters->kinematics.mode; Debugging( Form( "New integrator instance created\n\t" "Considered topology: %s case\n\t" "Will proceed with %d-dimensional integration", topo.str().c_str(), numDimensions() ) ); } Information( "Starting the computation of the process cross-section" ); try { prepareFunction(); } catch ( Exception& e ) { e.dump(); } has_cross_section_ = ( integrator_->integrate( cross_section_, cross_section_error_ ) == 0 ); xsec = cross_section_; err = cross_section_error_; Information( Form( "Total cross section: %f +/- %f pb", xsec, err ) ); } Event* Generator::generateOneEvent() { bool good = false; if ( !has_cross_section_ ) { computeXsection( cross_section_, cross_section_error_ ); } while ( !good ) { good = integrator_->generateOneEvent(); } last_event = this->parameters->generation.last_event; return last_event.get(); } void Generator::prepareFunction() { if ( !parameters->process() ) { throw Exception( __PRETTY_FUNCTION__, "No process defined!", FatalError ); } Kinematics kin = parameters->kinematics; parameters->process()->addEventContent(); parameters->process()->setKinematics( kin ); Debugging( "Function prepared to be integrated!" ); } } diff --git a/CepGen/Core/Integrand.cpp b/CepGen/Core/Integrand.cpp index 05af43c..e618bc7 100644 --- a/CepGen/Core/Integrand.cpp +++ b/CepGen/Core/Integrand.cpp @@ -1,136 +1,137 @@ #include "CepGen/Core/Timer.h" #include "CepGen/Core/Exception.h" #include "CepGen/Event/Event.h" #include "CepGen/Event/Particle.h" #include "CepGen/Physics/Kinematics.h" +#include "CepGen/Processes/GenericProcess.h" #include "CepGen/Parameters.h" #include <sstream> namespace CepGen { double f( double* x, size_t ndim, void* params ) { std::ostringstream os; Parameters* p = static_cast<Parameters*>( params ); std::shared_ptr<Event> ev = p->process()->event(); if ( p->process()->hasEvent() ) { p->process()->clearEvent(); const Particle::Momentum p1( 0., 0., p->kinematics.inp.first ), p2( 0., 0., -p->kinematics.inp.second ); p->process()->setIncomingKinematics( p1, p2 ); // at some point introduce non head-on colliding beams? DebuggingInsideLoop( Form( "Function f called -- some parameters:\n\t" " pz(p1) = %5.2f pz(p2) = %5.2f\n\t" " remnant mode: %d", p->kinematics.inp.first, p->kinematics.inp.second, p->kinematics.structure_functions ) ); if ( p->integrator.first_run ) { if ( Logger::get().level >= Logger::Debug ) { std::ostringstream oss; oss << p->kinematics.mode; Debugging( Form( "Process mode considered: %s", oss.str().c_str() ) ); } Particle& op1 = ev->getOneByRole( Particle::OutgoingBeam1 ), &op2 = ev->getOneByRole( Particle::OutgoingBeam2 ); //--- add outgoing protons or remnants switch ( p->kinematics.mode ) { case Kinematics::ElectronProton: default: { InError( Form( "Process mode %d not yet handled!", (int)p->kinematics.mode ) ); } case Kinematics::ElasticElastic: break; // nothing to change in the event case Kinematics::ElasticInelastic: op2.setPdgId( Particle::uQuark, 1 ); break; case Kinematics::InelasticElastic: // set one of the outgoing protons to be fragmented op1.setPdgId( Particle::uQuark, 1 ); break; case Kinematics::InelasticInelastic: // set both the outgoing protons to be fragmented op1.setPdgId( Particle::uQuark, 1 ); op2.setPdgId( Particle::uQuark, 1 ); break; } //--- prepare the function to be integrated p->process()->prepareKinematics(); //--- add central system Particles& central_system = ev->getByRole( Particle::CentralSystem ); if ( central_system.size() == p->kinematics.central_system.size() ) { unsigned short i = 0; for ( Particles::iterator part = central_system.begin(); part != central_system.end(); ++part ) { if ( p->kinematics.central_system[i] == Particle::invalidParticle ) continue; part->setPdgId( p->kinematics.central_system[i] ); part->computeMass(); i++; } } p->process()->clearRun(); p->integrator.first_run = false; } } // event is not empty p->process()->setPoint( ndim, x ); if ( Logger::get().level >= Logger::DebugInsideLoop ) { std::ostringstream oss; for ( unsigned int i=0; i<ndim; i++ ) { oss << x[i] << " "; } DebuggingInsideLoop( Form( "Computing dim-%d point ( %s)", ndim, oss.str().c_str() ) ); } //--- from this step on, the phase space point is supposed to be set by 'GenericProcess::setPoint()' p->process()->beforeComputeWeight(); Timer tmr; // start the timer double integrand = p->process()->computeWeight(); if ( integrand < 0. ) return 0.; //--- only fill in the process' Event object if storage is requested // or if taming functions are to be applied if ( !p->taming_functions.empty() || p->storage() ) p->process()->fillKinematics(); //--- once the kinematics variables have been populated, // can apply the collection of taming functions double taming = 1.0; if ( p->taming_functions.has( "m_central" ) || p->taming_functions.has( "pt_central" ) ) { const Particle::Momentum central_system( ev->getByRole( Particle::CentralSystem )[0].momentum() + ev->getByRole( Particle::CentralSystem )[1].momentum() ); taming *= p->taming_functions.eval( "m_central", central_system.mass() ); taming *= p->taming_functions.eval( "pt_central", central_system.pt() ); } if ( p->taming_functions.has( "q2" ) ) { taming *= p->taming_functions.eval( "q2", ev->getOneByRole( Particle::Parton1 ).momentum().mass() ); taming *= p->taming_functions.eval( "q2", ev->getOneByRole( Particle::Parton2 ).momentum().mass() ); } integrand *= taming; //--- full event content (+ hadronisation) if generating events if ( p->storage() ) { ev->time_generation = tmr.elapsed(); ev->time_total = tmr.elapsed(); p->process()->addGenerationTime( ev->time_total ); Debugging( Form( "Generation time: %5.6f sec\n\t" "Total time (gen+hadr): %5.6f sec", ev->time_generation, ev->time_total ) ); p->generation.last_event = ev; } // generating events if ( Logger::get().level>=Logger::DebugInsideLoop ) { os.str( "" ); for ( unsigned int i=0; i<ndim; i++ ) { os << Form( "%10.8f ", x[i] ); } Debugging( Form( "f value for dim-%d point ( %s): %4.4e", ndim, os.str().c_str(), integrand ) ); } return integrand; } } diff --git a/CepGen/Core/Integrator.cpp b/CepGen/Core/Integrator.cpp index 6605f5d..61fc5aa 100644 --- a/CepGen/Core/Integrator.cpp +++ b/CepGen/Core/Integrator.cpp @@ -1,329 +1,330 @@ #include "Integrator.h" #include "CepGen/Parameters.h" #include "CepGen/Core/Exception.h" +#include "CepGen/Event/Event.h" #include <fstream> namespace CepGen { Integrator::Integrator( const unsigned int dim, double f_( double*, size_t, void* ), Parameters* param ) : ps_bin_( 0 ), input_params_( param ), function_( std::unique_ptr<gsl_monte_function>( new gsl_monte_function ) ) { //--- function to be integrated function_->f = f_; function_->dim = dim; function_->params = (void*)param; //--- initialise the random number generator gsl_rng_env_setup(); rng_ = gsl_rng_alloc( gsl_rng_default ); unsigned long seed = ( param->integrator.seed > 0 ) ? param->integrator.seed : time( nullptr ); // seed with time gsl_rng_set( rng_, seed ); Debugging( Form( "Number of integration dimensions: %d\n\t" "Number of iterations: %d\n\t" "Number of function calls: %d", dim, input_params_->integrator.itvg, input_params_->integrator.ncvg ) ); } Integrator::~Integrator() { if ( rng_ ) gsl_rng_free( rng_ ); } int Integrator::integrate( double& result, double& abserr ) { int res = -1; gsl_monte_vegas_state* veg_state; gsl_monte_miser_state* mis_state; const Integrator::Type algorithm = input_params_->integrator.type; //--- integration bounds std::vector<double> x_low( function_->dim, 0. ), x_up( function_->dim, 1. ); //--- prepare integrator if ( algorithm == Vegas ) veg_state = gsl_monte_vegas_alloc( function_->dim ); else if ( algorithm == MISER ) mis_state = gsl_monte_miser_alloc( function_->dim ); if ( algorithm == Vegas ) { //----- Vegas warmup (prepare the grid) if ( !grid_.grid_prepared ) { res = gsl_monte_vegas_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, 10000, rng_, veg_state, &result, &abserr ); grid_.grid_prepared = true; } //----- integration for ( unsigned short i = 0; i < input_params_->integrator.itvg; i++ ) { res = gsl_monte_vegas_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, 0.2 * input_params_->integrator.ncvg, rng_, veg_state, &result, &abserr ); PrintMessage( Form( ">> Iteration %2d: average = %10.6f sigma = %10.6f chi2 = %4.3f", i+1, result, abserr, gsl_monte_vegas_chisq( veg_state ) ) ); } } //----- integration else if ( algorithm == MISER ) res = gsl_monte_miser_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, input_params_->integrator.ncvg, rng_, mis_state, &result, &abserr ); //--- clean integrator if ( algorithm == Vegas ) gsl_monte_vegas_free( veg_state ); else if ( algorithm == MISER ) gsl_monte_miser_free( mis_state ); return res; } void Integrator::generate() { std::ofstream of; std::string fn; if ( !grid_.gen_prepared ) setGen(); Information( Form( "%d events will be generated", input_params_->generation.maxgen ) ); unsigned int i = 0; while ( i < input_params_->generation.maxgen ) { if ( generateOneEvent() ) i++; } Information( Form( "%d events generated", i ) ); } bool Integrator::generateOneEvent() { if ( !grid_.gen_prepared ) setGen(); const unsigned int ndim = function_->dim, max = pow( mbin_, ndim ); std::vector<double> x( ndim, 0. ); //--- correction cycles if ( ps_bin_ != 0 ) { bool has_correction = false; while ( !correctionCycle( x, has_correction ) ) {} if ( has_correction ) return storeEvent( x ); } double weight; double y = -1.; //--- normal generation cycle //----- select a Integrator bin and reject if fmax is too small do { do { // ... ps_bin_ = uniform() * max; y = uniform() * grid_.f_max_global; grid_.nm[ps_bin_] += 1; } while ( y > grid_.f_max[ps_bin_] ); // Select x values in this Integrator bin int jj = ps_bin_; for ( unsigned int i=0; i<ndim; i++ ) { int jjj = jj / mbin_; grid_.n[i] = jj - jjj * mbin_; x[i] = ( uniform() + grid_.n[i] ) / mbin_; jj = jjj; } // Get weight for selected x value weight = F( x ); } while ( y > weight ); if ( weight <= grid_.f_max[ps_bin_] ) ps_bin_ = 0; // Init correction cycle if weight is higher than fmax or ffmax else if ( weight <= grid_.f_max_global ) { grid_.f_max_old = grid_.f_max[ps_bin_]; grid_.f_max[ps_bin_] = weight; grid_.f_max_diff = weight-grid_.f_max_old; grid_.correc = ( grid_.nm[ps_bin_] - 1. ) * grid_.f_max_diff / grid_.f_max_global - 1.; } else { grid_.f_max_old = grid_.f_max[ps_bin_]; grid_.f_max[ps_bin_] = weight; grid_.f_max_diff = weight-grid_.f_max_old; grid_.f_max_global = weight; grid_.correc = ( grid_.nm[ps_bin_] - 1. ) * grid_.f_max_diff / grid_.f_max_global * weight / grid_.f_max_global - 1.; } Debugging( Form( "Correction applied: %f, phase space bin = %d", grid_.correc, ps_bin_ ) ); // Return with an accepted event if ( weight > 0. ) return storeEvent( x ); return false; } bool Integrator::correctionCycle( std::vector<double>& x, bool& has_correction ) { double weight; const unsigned int ndim = function_->dim; Debugging( Form( "Correction cycles are started.\n\t" "j = %f" "correc = %f" "corre2 = %f", ps_bin_, grid_.correc2 ) ); if ( grid_.correc >= 1. ) grid_.correc -= 1.; if ( uniform() < grid_.correc ) { grid_.correc = -1.; std::vector<double> xtmp( ndim, 0. ); // Select x values in phase space bin for ( unsigned int k=0; k<ndim; k++ ) { xtmp[k] = ( uniform() + grid_.n[k] ) * inv_mbin_; } // Compute weight for x value weight = F( xtmp ); // Parameter for correction of correction if ( weight > grid_.f_max[ps_bin_] ) { if ( weight > grid_.f_max2 ) grid_.f_max2 = weight; grid_.correc2 -= 1.; grid_.correc += 1.; } // Accept event if ( weight >= grid_.f_max_diff*uniform() + grid_.f_max_old ) { // FIXME!!!! //Error("Accepting event!!!"); //return storeEvent(x); x = xtmp; has_correction = true; return true; } return false; } // Correction if too big weight is found while correction // (All your bases are belong to us...) if ( grid_.f_max2 > grid_.f_max[ps_bin_] ) { grid_.f_max_old = grid_.f_max[ps_bin_]; grid_.f_max[ps_bin_] = grid_.f_max2; grid_.f_max_diff = grid_.f_max2-grid_.f_max_old; if ( grid_.f_max2 < grid_.f_max_global ) { grid_.correc = ( grid_.nm[ps_bin_] - 1. ) * grid_.f_max_diff / grid_.f_max_global - grid_.correc2; } else { grid_.f_max_global = grid_.f_max2; grid_.correc = ( grid_.nm[ps_bin_] - 1. ) * grid_.f_max_diff / grid_.f_max_global * grid_.f_max2 / grid_.f_max_global - grid_.correc2; } grid_.correc2 = 0.; grid_.f_max2 = 0.; return false; } return true; } bool Integrator::storeEvent( const std::vector<double>& x ) { input_params_->setStorage( true ); F( x ); input_params_->generation.ngen += 1; input_params_->setStorage( false ); if ( input_params_->generation.ngen % input_params_->generation.gen_print_every == 0 ) { Debugging( Form( "Generated events: %d", input_params_->generation.ngen ) ); input_params_->generation.last_event->dump(); } return true; } void Integrator::setGen() { Information( Form( "Preparing the grid for the generation of unweighted events: %d points", input_params_->integrator.npoints ) ); // Variables for debugging std::ostringstream os; if ( Logger::get().level >= Logger::Debug ) { Debugging( Form( "MaxGen = %d", input_params_->generation.maxgen ) ); } const unsigned int ndim = function_->dim, max = pow( mbin_, ndim ), npoin = input_params_->integrator.npoints; const double inv_npoin = 1./npoin; if ( ndim > max_dimensions_ ) { FatalError( Form( "Number of dimensions to integrate exceed the maximum number, %d", max_dimensions_ ) ); } grid_.nm = std::vector<int>( max, 0 ); grid_.f_max = std::vector<double>( max, 0. ); grid_.n = std::vector<int>( ndim, 0 ); std::vector<double> x( ndim, 0. ); input_params_->generation.ngen = 0; // ... double sum = 0., sum2 = 0., sum2p = 0.; //--- main loop for ( unsigned int i=0; i<max; i++ ) { int jj = i; for ( unsigned int j=0; j<ndim; j++ ) { int jjj = jj*inv_mbin_; grid_.n[j] = jj-jjj*mbin_; jj = jjj; } double fsum = 0., fsum2 = 0.; for ( unsigned int j=0; j<npoin; j++ ) { for ( unsigned int k=0; k<ndim; k++ ) { x[k] = ( uniform() + grid_.n[k] ) * inv_mbin_; } const double z = F( x ); grid_.f_max[i] = std::max( grid_.f_max[i], z ); fsum += z; fsum2 += z*z; } const double av = fsum*inv_npoin, av2 = fsum2*inv_npoin, sig2 = av2 - av*av; sum += av; sum2 += av2; sum2p += sig2; grid_.f_max_global = std::max( grid_.f_max_global, grid_.f_max[i] ); if ( Logger::get().level >= Logger::DebugInsideLoop ) { const double sig = sqrt( sig2 ); const double eff = ( grid_.f_max[i] != 0. ) ? grid_.f_max[i]/av : 1.e4; os.str(""); for ( unsigned int j=0; j<ndim; j++ ) { os << grid_.n[j]; if ( j != ndim-1 ) os << ", "; } DebuggingInsideLoop( Form( "In iteration #%d:\n\t" "av = %f\n\t" "sig = %f\n\t" "fmax = %f\n\t" "eff = %f\n\t" "n = (%s)", i, av, sig, grid_.f_max[i], eff, os.str().c_str() ) ); } } // end of main loop sum = sum/max; sum2 = sum2/max; sum2p = sum2p/max; if ( Logger::get().level >= Logger::Debug ) { const double sig = sqrt( sum2-sum*sum ), sigp = sqrt( sum2p ); double eff1 = 0.; for ( unsigned int i=0; i<max; i++ ) eff1 += ( grid_.f_max[i] / ( max*sum ) ); const double eff2 = grid_.f_max_global/sum; Debugging( Form( "Average function value = sum = %f\n\t" "Average function value**2 = sum2 = %f\n\t" "Overall standard deviation = sig = %f\n\t" "Average standard deviation = sigp = %f\n\t" "Maximum function value = ffmax = %f\n\t" "Average inefficiency = eff1 = %f\n\t" "Overall inefficiency = eff2 = %f\n\t", sum, sum2, sig, sigp, grid_.f_max_global, eff1, eff2 ) ); } grid_.gen_prepared = true; Information( "Grid prepared! Now launching the production." ); } std::ostream& operator<<( std::ostream& os, const Integrator::Type& type ) { switch ( type ) { case Integrator::Vegas: return os << "Vegas"; case Integrator::MISER: return os << "MISER"; } return os; } } diff --git a/CepGen/Core/Parameters.cpp b/CepGen/Core/Parameters.cpp index a4b2f55..bb2d2a6 100644 --- a/CepGen/Core/Parameters.cpp +++ b/CepGen/Core/Parameters.cpp @@ -1,114 +1,122 @@ #include "CepGen/Parameters.h" #include "CepGen/Core/Exception.h" +#include "CepGen/Processes/GenericProcess.h" namespace CepGen { Parameters::Parameters() : store_( false ) {} Parameters::Parameters( Parameters& param ) : kinematics( param.kinematics ), integrator( param.integrator ), generation( param.generation ), taming_functions( param.taming_functions ), process_( std::move( param.process_ ) ), store_( param.store_ ) {} Parameters::Parameters( const Parameters& param ) : kinematics( param.kinematics ), integrator( param.integrator ), generation( param.generation ), taming_functions( param.taming_functions ), store_( param.store_ ) {} Parameters::~Parameters() {} void Parameters::setThetaRange( float thetamin, float thetamax ) { kinematics.central_cuts[Cuts::eta_single].in( Particle::thetaToEta( thetamax ), Particle::thetaToEta( thetamin ) ); if ( Logger::get().level >= Logger::Debug ) { std::ostringstream os; os << kinematics.central_cuts[Cuts::eta_single]; Debugging( Form( "eta in range: %s => theta(min) = %5.2f, theta(max) = %5.2f", os.str().c_str(), thetamin, thetamax ) ); } } + std::string + Parameters::processName() const + { + if ( process_ ) return process_->name(); + return "no process"; + } + void Parameters::dump( std::ostream& out, bool pretty ) const { std::ostringstream os; const int wb = 75, wt = 32; os.str( "" ); os << "Parameters dump" << std::left << std::endl << std::endl << std::setfill('_') << std::setw( wb ) << "_/¯ RUN INFORMATION ¯\\_" << std::setfill( ' ' ) << std::endl << std::right << std::setw( wb ) << std::left << std::endl << std::setw( wt ) << "Process to generate"; if ( process_ ) { os << ( pretty ? boldify( process_->name().c_str() ) : process_->name() ) << std::endl << std::setw( wt ) << "" << process_->description(); } else os << ( pretty ? boldify( "no process!" ) : "no process!" ); os << std::endl << std::setw( wt ) << "Events generation? " << ( pretty ? yesno( generation.enabled ) : std::to_string( generation.enabled ) ) << std::endl << std::setw( wt ) << "Number of events to generate" << ( pretty ? boldify( generation.maxgen ) : std::to_string( generation.maxgen ) ) << std::endl << std::setw( wt ) << "Verbosity level " << Logger::get().level << std::endl << std::endl << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Integration parameters " ) : "Integration parameters" ) << std::setfill( ' ' ) << std::endl << std::endl; std::ostringstream int_algo; int_algo << integrator.type; os << std::setw( wt ) << "Integration algorithm" << ( pretty ? boldify( int_algo.str().c_str() ) : int_algo.str() ) << std::endl << std::setw( wt ) << "Maximum number of iterations" << ( pretty ? boldify( integrator.itvg ) : std::to_string( integrator.itvg ) ) << std::endl << std::setw( wt ) << "Number of function calls" << integrator.ncvg << std::endl << std::setw( wt ) << "Number of points to try per bin" << integrator.npoints << std::endl << std::setw( wt ) << "Random number generator seed" << integrator.seed << std::endl << std::endl << std::setfill('_') << std::setw( wb ) << "_/¯ EVENTS KINEMATICS ¯\\_" << std::setfill( ' ' ) << std::endl << std::endl << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Incoming particles " ) : "Incoming particles" ) << std::setfill( ' ' ) << std::endl << std::endl; std::ostringstream proc_mode; proc_mode << kinematics.mode; std::ostringstream ip1, ip2, op; ip1 << kinematics.inpdg.first; ip2 << kinematics.inpdg.second; for ( std::vector<Particle::ParticleCode>::const_iterator cp = kinematics.central_system.begin(); cp != kinematics.central_system.end(); ++cp ) op << ( cp != kinematics.central_system.begin() ? ", " : "" ) << *cp; std::ostringstream q2range; q2range << kinematics.initial_cuts.at( Cuts::q2 ); os << std::setw( wt ) << "Subprocess mode" << ( pretty ? boldify( proc_mode.str().c_str() ) : proc_mode.str() ) << std::endl << std::setw( wt ) << "Incoming particles" << ( pretty ? boldify( ip1.str().c_str() ) : ip1.str() ) << ", " << ( pretty ? boldify( ip2.str().c_str() ) : ip2.str() ) << std::endl << std::setw( wt ) << "Momenta (GeV/c)" << kinematics.inp.first << ", " << kinematics.inp.second << std::endl << std::setw( wt ) << "Structure functions" << kinematics.structure_functions << std::endl << std::endl << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Incoming partons " ) : "Incoming partons" ) << std::setfill( ' ' ) << std::endl << std::endl << std::setw( wt ) << "Virtuality range" << ( pretty ? boldify( q2range.str().c_str() ) : q2range.str().c_str() ) << " GeV**2" << std::endl << std::endl << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Outgoing central system " ) : "Outgoing central system" ) << std::setfill( ' ' ) << std::endl << std::endl << std::setw( wt ) << "Central particles" << ( pretty ? boldify( op.str().c_str() ) : op.str() ) << std::endl; for ( std::map<Cuts::Central, Kinematics::Limits>::const_iterator lim = kinematics.central_cuts.begin(); lim != kinematics.central_cuts.end(); ++lim ) { os << std::setw( wt ) << lim->first << lim->second << std::endl; } /*std::ostringstream ptrange; ptrange << kinematics.pt_single_central; std::ostringstream erange; erange << kinematics.e_single_central; std::ostringstream etarange; etarange << kinematics.eta_single_central; std::ostringstream mxrange; mxrange << kinematics.mass_remnants; os << std::setw( wt ) << "Lepton(s)' pT range" << ( pretty ? boldify( ptrange.str().c_str() ) : ptrange.str().c_str() ) << " GeV/c" << std::endl << std::setw( wt ) << "Lepton(s)' energy range" << ( pretty ? boldify( erange.str().c_str() ) : erange.str().c_str() ) << " GeV" << std::endl << std::setw( wt ) << "Pseudorapidity range" << ( pretty ? boldify( etarange.str().c_str() ) : etarange.str().c_str() ) << std::endl //<< std::setw( wt ) << "Polar angle theta in range [deg]" << "[" << std::setw(3) << mintheta << ", " << std::setw( 3 ) << maxtheta << "]" << std::endl << std::endl << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Outgoing remnants" ) : "Outgoing remnants" ) << std::endl << std::endl << std::setfill( ' ' ); os << std::setw( wt ) << "Mass range" << ( pretty ? boldify( mxrange.str().c_str() ) : mxrange.str().c_str() ) << " GeV/c**2" << std::endl;*/ if ( pretty ) { Information( os.str() ); } else out << os.str(); } } diff --git a/CepGen/Parameters.h b/CepGen/Parameters.h index 3b93449..aba23c6 100644 --- a/CepGen/Parameters.h +++ b/CepGen/Parameters.h @@ -1,102 +1,104 @@ #ifndef CepGen_Parameters_h #define CepGen_Parameters_h -#include "CepGen/Processes/GenericProcess.h" #include "CepGen/Core/TamingFunction.h" #include "CepGen/Core/Integrator.h" +#include "CepGen/Physics/Kinematics.h" +#include "CepGen/Processes/GenericProcess.h" #include <memory> namespace CepGen { - class Kinematics; + class Event; /// List of parameters used to start and run the simulation job - class Parameters { + class Parameters + { public: Parameters(); /// Copy constructor (transfers ownership to the process!) Parameters( Parameters& ); /// Const copy constructor (all but the process) Parameters( const Parameters& ); ~Parameters(); /// Set the polar angle range for the produced leptons /// \param[in] thetamin The minimal value of \f$\theta\f$ for the outgoing leptons /// \param[in] thetamax The maximal value of \f$\theta\f$ for the outgoing leptons void setThetaRange( float thetamin, float thetamax ); /// Dump the input parameters in the console void dump( std::ostream& os=Logger::get().outputStream, bool pretty=true ) const; //----- process to compute /// Process for which the cross-section will be computed and the events will be generated Process::GenericProcess* process() { return process_.get(); } /// Name of the process considered - std::string processName() const { return ( process_ ) ? process_->name() : "no process"; } + std::string processName() const; /// Set the process to study void setProcess( Process::GenericProcess* proc ) { process_.reset( proc ); } //----- events kinematics /// Events kinematics for phase space definition Kinematics kinematics; //----- VEGAS /// Collection of integrator parameters struct IntegratorParameters { IntegratorParameters() : type( Integrator::Vegas ), ncvg( 100000 ), itvg( 10 ), npoints( 100 ), first_run( true ), seed( 0 ) {} Integrator::Type type; /// Number of function calls to be computed for each point unsigned int ncvg; // ?? /// Number of iterations for the integration unsigned int itvg; /// Number of points to "shoot" in each integration bin by the algorithm unsigned int npoints; /// Is it the first time the integrator is run? bool first_run; /// Random number generator seed unsigned long seed; }; /// Integrator parameters IntegratorParameters integrator; //----- events generation /// Collection of events generation parameters struct Generation { Generation() : enabled( false ), maxgen( 0 ), symmetrise( false ), ngen( 0 ), gen_print_every( 1 ) {} /// Are we generating events ? (true) or are we only computing the cross-section ? (false) bool enabled; /// Maximal number of events to generate in this run unsigned int maxgen; /// Pointer to the last event produced in this run std::shared_ptr<Event> last_event; /// Do we want the events to be symmetrised with respect to the \f$z\f$-axis ? bool symmetrise; /// Number of events already generated in this run unsigned int ngen; /// Frequency at which the events are displayed to the end-user unsigned int gen_print_every; }; /// Events generation parameters Generation generation; /// Specify if the generated events are to be stored void setStorage( bool store ) { store_ = store; } /// Are the events generated in this run to be stored in the output file ? bool storage() const { return store_; } //----- taming functions /// Functionals to be used to account for rescattering corrections (implemented within the process) TamingFunctionsCollection taming_functions; private: std::unique_ptr<Process::GenericProcess> process_; bool store_; }; } #endif diff --git a/test/test_physics_processes.cpp b/test/test_physics_processes.cpp index c813961..ac61062 100644 --- a/test/test_physics_processes.cpp +++ b/test/test_physics_processes.cpp @@ -1,140 +1,147 @@ #include "CepGen/Generator.h" #include "CepGen/Parameters.h" #include "CepGen/Core/Timer.h" #include "CepGen/Processes/GamGamLL.h" #include "CepGen/Processes/PPtoLL.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "abort.h" #include <unordered_map> #include <assert.h> +using namespace std; + int main( int argc, char* argv[] ) { - typedef std::vector<std::pair<std::string,std::pair<double,double> > > KinematicsMap; - typedef std::vector<std::pair<float, KinematicsMap> > ValuesAtCutMap; + typedef vector<pair<string,pair<double,double> > > KinematicsMap; + typedef vector<pair<float, KinematicsMap> > ValuesAtCutMap; AbortHandler ctrl_c; // values defined at pt(single lepton)>15 GeV, |eta(single lepton)|<2.5, mX<1000 GeV // process -> { pt cut -> { kinematics -> ( sigma, delta(sigma) ) } } - std::vector<std::pair<std::string,ValuesAtCutMap> > values_map = { + vector<pair<string,ValuesAtCutMap> > values_map = { //--- LPAIR values at sqrt(s) = 13 TeV { "lpair", { { 3.0, { // pt cut { "elastic", { 2.0871703e1, 3.542e-2 } }, { "singlediss", { 1.5042536e1, 3.256e-2 } }, { "doublediss", { 1.38835e1, 4.03018e-2 } } } }, { 15.0, { // pt cut { "elastic", { 4.1994803e-1, 8.328e-4 } }, { "singlediss", { 4.8504819e-1, 1.171e-3 } }, { "doublediss", { 6.35650e-1, 1.93968e-3 } } } }, } }, //--- PPTOLL values { "pptoll", { { 3.0, { // pt cut { "elastic", { 2.0936541e1, 1.4096e-2 } }, { "singlediss_su", { 1.4844881e1, 2.0723e-2 } }, // SU, qt<50 { "doublediss_su", { 1.3580637e1, 2.2497e-2 } }, // SU, qt<50 } }, { 15.0, { // pt cut { "elastic", { 4.2515888e-1, 3.0351e-4 } }, { "singlediss_su", { 4.4903253e-1, 5.8970e-4 } }, // SU, qt<50 { "doublediss_su", { 5.1923819e-1, 9.6549e-4 } }, // SU, qt<50 /*{ "2_singlediss", { 4.6710287e-1, 6.4842e-4 } }, // SU, qt<500 { "3_doublediss", { 5.6316353e-1, 1.1829e-3 } }, // SU, qt<500*/ } }, } }, }; const double num_sigma = 3.0; - if ( argc == 1 || strcmp( argv[1], "debug" ) != 0 ) { + if ( argc < 3 || strcmp( argv[2], "debug" ) != 0 ) { CepGen::Logger::get().level = CepGen::Logger::Nothing; } Timer tmr; CepGen::Generator mg; + if ( argc > 1 && strcmp( argv[1], "vegas" ) == 0 ) mg.parameters->integrator.type = CepGen::Integrator::Vegas; + if ( argc > 1 && strcmp( argv[1], "miser" ) == 0 ) mg.parameters->integrator.type = CepGen::Integrator::MISER; + //{ ostringstream os; os << mg.parameters->integrator.type; Information( Form( "Testing with %s", os.str().c_str() ) ); } + { cout << "Testing with " << mg.parameters->integrator.type << endl; } + mg.parameters->kinematics.setSqrtS( 13.e3 ); mg.parameters->kinematics.central_cuts[CepGen::Cuts::eta_single].in( -2.5, 2.5 ); mg.parameters->kinematics.remnant_cuts[CepGen::Cuts::mass].max() = 1000.; //mg.parameters->integrator.ncvg = 50000; mg.parameters->integrator.itvg = 5; Information( Form( "Initial configuration time: %.3f ms", tmr.elapsed()*1.e3 ) ); tmr.reset(); unsigned short num_tests = 0, num_tests_passed = 0; - std::vector<std::string> failed_tests, passed_tests; + vector<string> failed_tests, passed_tests; try { for ( const auto& values_vs_generator : values_map ) { // loop over all generators if ( values_vs_generator.first == "lpair" ) mg.parameters->setProcess( new CepGen::Process::GamGamLL ); else if ( values_vs_generator.first == "pptoll" ) { mg.parameters->setProcess( new CepGen::Process::PPtoLL ); mg.parameters->kinematics.initial_cuts[CepGen::Cuts::qt].max() = 50.0; } else { InError( Form( "Unrecognized generator mode: %s", values_vs_generator.first.c_str() ) ); break; } for ( const auto& values_vs_cut : values_vs_generator.second ) { // loop over the single lepton pT cut mg.parameters->kinematics.central_cuts[CepGen::Cuts::pt_single].min() = values_vs_cut.first; for ( const auto& values_vs_kin : values_vs_cut.second ) { // loop over all possible kinematics - if ( values_vs_kin.first.find( "elastic" ) != std::string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::ElasticElastic; - else if ( values_vs_kin.first.find( "singlediss" ) != std::string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::InelasticElastic; - else if ( values_vs_kin.first.find( "doublediss" ) != std::string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::InelasticInelastic; + if ( values_vs_kin.first.find( "elastic" ) != string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::ElasticElastic; + else if ( values_vs_kin.first.find( "singlediss" ) != string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::InelasticElastic; + else if ( values_vs_kin.first.find( "doublediss" ) != string::npos ) mg.parameters->kinematics.mode = CepGen::Kinematics::InelasticInelastic; else { InError( Form( "Unrecognized kinematics mode: %s", values_vs_kin.first.c_str() ) ); break; } - if ( values_vs_kin.first.find( "_su" ) != std::string::npos ) mg.parameters->kinematics.structure_functions = CepGen::StructureFunctions::SzczurekUleshchenko; + if ( values_vs_kin.first.find( "_su" ) != string::npos ) mg.parameters->kinematics.structure_functions = CepGen::StructureFunctions::SzczurekUleshchenko; else mg.parameters->kinematics.structure_functions = CepGen::StructureFunctions::SuriYennie; Information( Form( "Process: %s/%s\n\tConfiguration time: %.3f ms", values_vs_generator.first.c_str(), values_vs_kin.first.c_str(), tmr.elapsed()*1.e3 ) ); tmr.reset(); mg.clearRun(); const double xsec_ref = values_vs_kin.second.first, err_xsec_ref = values_vs_kin.second.second; double xsec_cepgen, err_xsec_cepgen; mg.computeXsection( xsec_cepgen, err_xsec_cepgen ); const double sigma = ( fabs( xsec_ref-xsec_cepgen ) ) / sqrt( err_xsec_cepgen*err_xsec_cepgen + err_xsec_ref*err_xsec_ref ); Information( Form( "Computed cross section:\n\tRef. = %.3e +/- %.3e\n\tCepGen = %.3e +/- %.3e\n\tPull: %.6f", xsec_ref, err_xsec_ref, xsec_cepgen, err_xsec_cepgen, sigma ) ); Information( Form( "Computation time: %.3f ms", tmr.elapsed()*1.e3 ) ); tmr.reset(); - std::string test_res = values_vs_generator.first+":"+ + string test_res = values_vs_generator.first+":"+ Form( "pt-gt-%.1f", values_vs_cut.first )+":"+ values_vs_kin.first+":" "ref="+Form( "%.3e", xsec_ref )+":" "got="+Form( "%.3e", xsec_cepgen )+":" "pull="+Form( "%.3f", sigma ); if ( fabs( sigma )<num_sigma ) { passed_tests.emplace_back( test_res ); num_tests_passed++; } else { failed_tests.emplace_back( test_res ); } num_tests++; - std::cout << "Test " << num_tests_passed << "/" << num_tests << " passed!" << std::endl; + cout << "Test " << num_tests_passed << "/" << num_tests << " passed!" << endl; } } } } catch ( CepGen::Exception& e ) {} if ( failed_tests.size() != 0 ) { - std::ostringstream os_failed, os_passed; - for ( const auto& fail : failed_tests ) os_failed << " (*) " << fail << std::endl; - for ( const auto& pass : passed_tests ) os_passed << " (*) " << pass << std::endl; + ostringstream os_failed, os_passed; + for ( const auto& fail : failed_tests ) os_failed << " (*) " << fail << endl; + for ( const auto& pass : passed_tests ) os_passed << " (*) " << pass << endl; throw CepGen::Exception( __PRETTY_FUNCTION__, Form( "Some tests failed!\n%s\nPassed tests:\n%s", os_failed.str().c_str(), os_passed.str().c_str() ), CepGen::FatalError ); } else Information( "ALL TESTS PASSED!" ); return 0; }