diff --git a/CepGen/IO/GridHandler.h b/CepGen/IO/GridHandler.h index 875ca87..4b918cf 100644 --- a/CepGen/IO/GridHandler.h +++ b/CepGen/IO/GridHandler.h @@ -1,296 +1,310 @@ #ifndef CepGen_IO_GridHandler_h #define CepGen_IO_GridHandler_h #include <gsl/gsl_version.h> #ifdef GSL_MAJOR_VERSION # if GSL_MAJOR_VERSION > 2 || ( GSL_MAJOR_VERSION == 2 && GSL_MINOR_VERSION >= 1 ) # include <gsl/gsl_interp2d.h> # include <gsl/gsl_spline2d.h> -//# define GOOD_GSL 1 +# define GOOD_GSL 1 # endif #endif #include <gsl/gsl_interp.h> #include <gsl/gsl_spline.h> #include <gsl/gsl_errno.h> #include <gsl/gsl_math.h> #include "CepGen/Core/Exception.h" -#include <set> +#include <vector> namespace CepGen { class StructureFunctions; enum struct GridType { linear = 0, logarithmic = 1, square = 2 }; /// A generic class for D-dimensional grid interpolation /// \param N Number of values handled per point - template <size_t D=2,size_t N=1> + template <size_t D,size_t N=1> class GridHandler { public: + typedef std::array<double,D> coord_t; + typedef std::array<double,N> values_t; /// A point and its associated value(s) struct point_t { - typedef std::array<double,D> coord_t; - typedef std::array<double,N> values_t; /// Coordinate(s) coord_t coord; /// (list of) value(s) for this point values_t value; }; public: explicit GridHandler( const GridType& grid_type ) : grid_type_( grid_type ), accel_{} { for ( size_t i = 0; i < D; ++i ) accel_.emplace_back( std::unique_ptr<gsl_interp_accel,void(*)( gsl_interp_accel* )>( gsl_interp_accel_alloc(), gsl_interp_accel_free ) ); } ~GridHandler() { #ifdef GOOD_GSL for ( size_t i = 0; i < D; ++i ) if ( values_[i] ) delete[] values_[i]; #endif } /// Interpolate a point to a given coordinate - std::array<double,N> eval( std::array<double,D> in_coords ) const { - std::array<double,N> out; - std::array<double,D> coord = in_coords; + values_t eval( coord_t in_coords ) const { + values_t out; + coord_t coord = in_coords; switch ( grid_type_ ) { case GridType::logarithmic: { for ( auto& c : coord ) c = log10( c ); } break; case GridType::square: { for ( auto& c : coord ) c *= c; } break; default: break; } //--- dimension of the vector space coordinate to evaluate switch ( D ) { case 1: { - const double x = coord.at( 0 ); for ( size_t i = 0; i < N; ++i ) { - int res = gsl_spline_eval_e( splines_1d_.at( i ).get(), x, accel_.at( 0 ).get(), &out[i] ); + int res = gsl_spline_eval_e( splines_1d_.at( i ).get(), coord.at( 0 ), accel_.at( 0 ).get(), &out[i] ); if ( res != GSL_SUCCESS ) { - out.fill( 0. ); + out[i] = 0.; CG_WARNING( "GridHandler" ) - << "Failed to evaluate the grid value " + << "Failed to evaluate the grid value (N=" << i << ") " << "for x = " << in_coords.at( 0 ) << ". " << "GSL error: " << gsl_strerror( res ); } } } break; case 2: { const double x = coord.at( 0 ), y = coord.at( 1 ); #ifdef GOOD_GSL for ( size_t i = 0; i < N; ++i ) { - int res = gsl_spline2d_eval_e( splines_2d_.at( i ).get(), - x, y, - accel_.at( 0 ).get(), accel_.at( 1 ).get(), - &out[i] ); + int res = gsl_spline2d_eval_e( splines_2d_.at( i ).get(), x, y, accel_.at( 0 ).get(), accel_.at( 1 ).get(), &out[i] ); if ( res != GSL_SUCCESS ) { - out.fill( 0. ); + out[i] = 0.; CG_WARNING( "GridHandler" ) - << "Failed to evaluate the grid value " + << "Failed to evaluate the grid value (N=" << i << ") " << "for x = " << in_coords.at( 0 ) << " / y = " << in_coords.at( 1 ) << ". " << "GSL error: " << gsl_strerror( res ); } } #else //--- retrieve the indices of the bin in the set - std::array<unsigned short,D> id; - for ( size_t i = 0; i < D; ++i ) - id[i] = std::distance( coords_.at( i ).begin(), coords_.at( i ).lower_bound( coord.at( i ) ) ); - const double x_1 = *std::next( coords_.at( 0 ).begin(), id[0] ), x_2 = *std::next( coords_.at( 0 ).begin(), id[0]+1 ); - const double y_1 = *std::next( coords_.at( 1 ).begin(), id[1] ), y_2 = *std::next( coords_.at( 1 ).begin(), id[1]+1 ); + coord_t min, max; + findIndices( coord, min, max ); //--- find boundaries values - coord_t ext_11, ext_12, ext_21, ext_22; + gridpoint_t ext_11, ext_12, ext_21, ext_22; for ( const auto& val : values_raw_ ) { - if ( x_1 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) ) ext_11 = val.value; - else if ( x_1 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) ) ext_12 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) ) ext_21 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) ) ext_22 = val.value; + if ( min[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) ) ext_11 = val.value; + else if ( min[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) ) ext_12 = val.value; + else if ( max[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) ) ext_21 = val.value; + else if ( max[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) ) ext_22 = val.value; } //--- now that we have the boundaries, we may interpolate - const double xd = ( x-x_1 )/( x_2-x_1 ), yd = ( y-y_1 )/( y_2-y_1 ); - const coord_t ext_1 = ext_11*( 1.-xd ) + ext_21*xd; - const coord_t ext_2 = ext_12*( 1.-xd ) + ext_22*xd; - out = ext_1*( 1.-yd )+ext_2*yd; + coord_t c_d; + for ( size_t i = 0; i < D; ++i ) + c_d[i] = ( coord.at( i )-min[i] )/( max[i]-min[i] ); + const gridpoint_t ext_1 = ext_11*( 1.-c_d[0] ) + ext_21*c_d[0]; + const gridpoint_t ext_2 = ext_12*( 1.-c_d[0] ) + ext_22*c_d[0]; + out = ext_1*( 1.-c_d[1] )+ext_2*c_d[1]; #endif } break; case 3: { - const double x = coord.at( 0 ), y = coord.at( 1 ), z = coord.at( 2 ); //--- retrieve the indices of the bin in the set - std::array<unsigned short,D> id; - for ( size_t i = 0; i < D; ++i ) - id[i] = std::distance( coords_.at( i ).begin(), coords_.at( i ).lower_bound( coord.at( i ) ) ); - const double x_1 = *std::next( coords_.at( 0 ).begin(), id[0] ), x_2 = *std::next( coords_.at( 0 ).begin(), id[0]+1 ); - const double y_1 = *std::next( coords_.at( 1 ).begin(), id[1] ), y_2 = *std::next( coords_.at( 1 ).begin(), id[1]+1 ); - const double z_1 = *std::next( coords_.at( 2 ).begin(), id[2] ), z_2 = *std::next( coords_.at( 2 ).begin(), id[2]+1 ); + coord_t min, max; + findIndices( coord, min, max ); //--- find boundaries values - coord_t ext_111, ext_112, ext_121, ext_122, ext_211, ext_212, ext_221, ext_222; + gridpoint_t ext_111, ext_112, ext_121, ext_122, ext_211, ext_212, ext_221, ext_222; for ( const auto& val : values_raw_ ) { - if ( x_1 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) && z_1 == val.coord.at( 2 ) ) ext_111 = val.value; - else if ( x_1 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) && z_2 == val.coord.at( 2 ) ) ext_112 = val.value; - else if ( x_1 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) && z_1 == val.coord.at( 2 ) ) ext_121 = val.value; - else if ( x_1 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) && z_2 == val.coord.at( 2 ) ) ext_122 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) && z_1 == val.coord.at( 2 ) ) ext_211 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_1 == val.coord.at( 1 ) && z_2 == val.coord.at( 2 ) ) ext_212 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) && z_1 == val.coord.at( 2 ) ) ext_221 = val.value; - else if ( x_2 == val.coord.at( 0 ) && y_2 == val.coord.at( 1 ) && z_2 == val.coord.at( 2 ) ) ext_222 = val.value; + if ( min[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) && min[2] == val.coord.at( 2 ) ) ext_111 = val.value; + else if ( min[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) && max[2] == val.coord.at( 2 ) ) ext_112 = val.value; + else if ( min[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) && min[2] == val.coord.at( 2 ) ) ext_121 = val.value; + else if ( min[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) && max[2] == val.coord.at( 2 ) ) ext_122 = val.value; + else if ( max[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) && min[2] == val.coord.at( 2 ) ) ext_211 = val.value; + else if ( max[0] == val.coord.at( 0 ) && min[1] == val.coord.at( 1 ) && max[2] == val.coord.at( 2 ) ) ext_212 = val.value; + else if ( max[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) && min[2] == val.coord.at( 2 ) ) ext_221 = val.value; + else if ( max[0] == val.coord.at( 0 ) && max[1] == val.coord.at( 1 ) && max[2] == val.coord.at( 2 ) ) ext_222 = val.value; } //--- now that we have the boundaries, we may interpolate - const double xd = ( x-x_1 )/( x_2-x_1 ), yd = ( y-y_1 )/( y_2-y_1 ), zd = ( z-z_1 )/( z_2-z_1 ); - const coord_t ext_11 = ext_111*( 1.-xd ) + ext_211*xd; - const coord_t ext_12 = ext_112*( 1.-xd ) + ext_212*xd; - const coord_t ext_21 = ext_121*( 1.-xd ) + ext_221*xd; - const coord_t ext_22 = ext_122*( 1.-xd ) + ext_222*xd; - const coord_t ext_1 = ext_11*( 1.-yd ) + ext_21*yd; - const coord_t ext_2 = ext_12*( 1.-yd ) + ext_22*yd; - out = ext_1*( 1.-zd )+ext_2*zd; + coord_t c_d; + for ( size_t i = 0; i < D; ++i ) + c_d[i] = ( coord.at( i )-min[i] )/( max[i]-min[i] ); + const gridpoint_t ext_11 = ext_111*( 1.-c_d[0] ) + ext_211*c_d[0]; + const gridpoint_t ext_12 = ext_112*( 1.-c_d[0] ) + ext_212*c_d[0]; + const gridpoint_t ext_21 = ext_121*( 1.-c_d[0] ) + ext_221*c_d[0]; + const gridpoint_t ext_22 = ext_122*( 1.-c_d[0] ) + ext_222*c_d[0]; + const gridpoint_t ext_1 = ext_11*( 1.-c_d[1] ) + ext_21*c_d[1]; + const gridpoint_t ext_2 = ext_12*( 1.-c_d[1] ) + ext_22*c_d[1]; + out = ext_1*( 1.-c_d[2] )+ext_2*c_d[2]; } break; default: throw CG_FATAL( "GridHandler" ) << "Unsupported number of dimensions: " << N; } return out; } /// Insert a new value in the grid void insert( const point_t& point ) { auto mod_coord = point.coord; if ( grid_type_ != GridType::linear ) for ( auto& c : mod_coord ) switch ( grid_type_ ) { case GridType::logarithmic: c = log10( c ); break; case GridType::square: c *= c; break; default: break; } values_raw_.emplace_back( point_t{ mod_coord, point.value } ); } /// Return the list of values handled in the grid std::vector<point_t> values() const { return values_raw_; } /// Initialise the grid and all useful interpolators/accelerators void init() { if ( values_raw_.empty() ) CG_ERROR( "GridHandler" ) << "Empty grid."; gsl_set_error_handler_off(); //--- start by building grid coordinates from raw values for ( auto& c : coords_ ) c.clear(); for ( const auto& val : values_raw_ ) { unsigned short i = 0; - for ( const auto& c : val.coord ) - coords_.at( i++ ).insert( c ); + for ( const auto& c : val.coord ) { + if ( std::find( coords_.at( i ).begin(), coords_.at( i ).end(), c ) == coords_.at( i ).end() ) + coords_.at( i ).emplace_back( c ); + ++i; + } } + for ( auto& c : coords_ ) + std::sort( c.begin(), c.end() ); { //--- debugging of the grid coordinates std::ostringstream os; unsigned short i = 0; for ( const auto& cs : coords_ ) { - os << "coordinate " << (i++) << " has " << cs.size() << " member(s):\n"; + os << "coordinate " << (i++) << " has " << cs.size() << " member(s):"; + unsigned short j = 0; for ( const auto& val : cs ) - os << " " << val; + os << ( j++ % 20 == 0 ? "\n " : " " ) << val; os << "\n"; } CG_DEBUG( "GridHandler" ) << "Grid dump:\n" << os.str(); } //--- particularise by dimension switch ( D ) { case 1: { //--- x |-> (f1,...) const gsl_interp_type* type = gsl_interp_cspline; //const gsl_interp_type* type = gsl_interp_steffen; if ( gsl_interp_type_min_size( type ) >= values_raw_.size() ) throw CG_FATAL( "GridHandler" ) << "Not enough points for \"" << type->name << "\" type of interpolation.\n\t" << "Minimum required: " << gsl_interp_type_min_size( type ) << ", got " << values_raw_.size() << "!"; for ( size_t i = 0; i < N; ++i ) { values_[i] = new double[values_raw_.size()]; splines_1d_.emplace_back( gsl_spline_alloc( type, values_raw_.size() ), gsl_spline_free ); } std::vector<double> x_vec; for ( unsigned short i = 0; i < values_raw_.size(); ++i ) { const auto& val = values_raw_.at( i ); x_vec.emplace_back( val.coord.at( 0 ) ); for ( size_t j = 0; j < N; ++j ) values_[j][i] = val.value.at( j ); } for ( unsigned short i = 0; i < splines_1d_.size(); ++i ) gsl_spline_init( splines_1d_.at( i ).get(), &x_vec[0], values_.at( i ), values_raw_.size() ); } break; case 2: { //--- (x,y) |-> (f1,...) #ifdef GOOD_GSL const gsl_interp2d_type* type = gsl_interp2d_bilinear; splines_2d_.clear(); for ( size_t i = 0; i < N; ++i ) { values_[i] = new double[coords_.at( 0 ).size() * coords_.at( 1 ).size()]; splines_2d_.emplace_back( gsl_spline2d_alloc( type, coords_.at( 0 ).size(), coords_.at( 1 ).size() ), gsl_spline2d_free ); } // second loop over all points to populate the grid for ( const auto& val : values_raw_ ) { double val_x = val.coord.at( 0 ), val_y = val.coord.at( 1 ); // retrieve the index of the bin in the set - const unsigned short id_x = std::distance( coords_.at( 0 ).begin(), coords_.at( 0 ).lower_bound( val_x ) ); - const unsigned short id_y = std::distance( coords_.at( 1 ).begin(), coords_.at( 1 ).lower_bound( val_y ) ); + const unsigned short id_x = std::distance( coords_.at( 0 ).begin(), std::lower_bound( coords_.at( 0 ).begin(), coords_.at( 0 ).end(), val_x ) ); + const unsigned short id_y = std::distance( coords_.at( 1 ).begin(), std::lower_bound( coords_.at( 1 ).begin(), coords_.at( 1 ).end(), val_y ) ); for ( unsigned short i = 0; i < splines_2d_.size(); ++i ) gsl_spline2d_set( splines_2d_.at( i ).get(), values_[i], id_x, id_y, val.value[i] ); } // initialise splines objects std::vector<double> x_vec( coords_.at( 0 ).begin(), coords_.at( 0 ).end() ), y_vec( coords_.at( 1 ).begin(), coords_.at( 1 ).end() ); for ( unsigned short i = 0; i < splines_2d_.size(); ++i ) gsl_spline2d_init( splines_2d_.at( i ).get(), &x_vec[0], &y_vec[0], values_.at( i ), x_vec.size(), y_vec.size() ); #else CG_WARNING( "GridHandler" ) << "GSL version ≥ 2.1 is required for spline bilinear interpolation.\n\t" << "Version " << GSL_VERSION << " is installed on this system!\n\t" << "Will use a linear approximation instead."; #endif } break; } } protected: GridType grid_type_; /// List of coordinates and associated value(s) in the grid std::vector<point_t> values_raw_; std::vector<std::unique_ptr<gsl_interp_accel,void(*)( gsl_interp_accel* )> > accel_; std::vector<std::unique_ptr<gsl_spline,void(*)( gsl_spline* )> > splines_1d_; #ifdef GOOD_GSL std::vector<std::unique_ptr<gsl_spline2d,void(*)( gsl_spline2d* )> > splines_2d_; #endif - std::array<std::set<double>,D> coords_; + std::array<std::vector<double>,D> coords_; std::array<double*,N> values_; private: - struct coord_t : std::array<double,N> { - coord_t() : std::array<double,N>() {} - coord_t( const std::array<double,N>& arr ) : std::array<double,N>( arr ) {} - coord_t operator*( double c ) const { - coord_t out = *this; + void findIndices( const coord_t& coord, coord_t& min, coord_t& max ) const { + for ( size_t i = 0; i < D; ++i ) { + if ( coord.at( i ) < *coords_.at( i ).begin() ) + min[i] = max[i] = *coords_.at( i ).begin(); + else if ( coord.at( i ) > *coords_.at( i ).rbegin() ) + min[i] = max[i] = *coords_.at( i ).rbegin(); + else { + auto it_coord = std::lower_bound( coords_.at( i ).begin(), coords_.at( i ).end(), coord.at( i ) ); + const unsigned short id = std::distance( coords_.at( i ).begin(), it_coord ); + min[i] = coords_.at( i ).at( id ); + max[i] = coords_.at( i ).at( id < coords_.at( i ).size()-1 ? id+1 : id ); + } + } + } + + struct gridpoint_t : values_t + { + gridpoint_t() : values_t() {} + gridpoint_t( const values_t& arr ) : values_t( arr ) {} + gridpoint_t operator*( double c ) const { + gridpoint_t out = *this; for ( auto& a : out ) a *= c; return out; } - coord_t operator+( const coord_t& rhs ) const { - coord_t out = *this; + gridpoint_t operator+( const gridpoint_t& rhs ) const { + gridpoint_t out = *this; for ( size_t i = 0; i < out.size(); ++i ) out[i] += rhs[i]; return out; } }; }; } #endif diff --git a/CepGen/Physics/GluonGrid.cpp b/CepGen/Physics/GluonGrid.cpp index f1cfa14..821b92e 100644 --- a/CepGen/Physics/GluonGrid.cpp +++ b/CepGen/Physics/GluonGrid.cpp @@ -1,57 +1,56 @@ #include "CepGen/Physics/GluonGrid.h" #include "CepGen/Core/Exception.h" #include <fstream> - -#include <gsl/gsl_errno.h> -#include <gsl/gsl_math.h> +#include <set> namespace kmr { GluonGrid& GluonGrid::get( const char* filename ) { Parameterisation p; p.grid_path = filename; static GluonGrid instance( p ); return instance; } GluonGrid::GluonGrid( const Parameterisation& param ) : CepGen::GridHandler<3,1>( CepGen::GridType::linear ), params( param ) { std::set<double> kt2_vals, x_vals, mu2_vals; { // file readout part std::ifstream file( params.grid_path, std::ios::in ); if ( !file.is_open() ) throw CG_FATAL( "GluonGrid" ) << "Impossible to load grid file \"" << params.grid_path << "\"!"; std::string x_tmp, kt2_tmp, mu2_tmp, fg_tmp; while ( file >> x_tmp >> kt2_tmp >> mu2_tmp >> fg_tmp ) { const double x = stod( x_tmp ), kt2 = stod( kt2_tmp ), mu2 = stod( mu2_tmp ), fg = stod( fg_tmp ); kt2_vals.insert( kt2 ); x_vals.insert( x ); mu2_vals.insert( mu2 ); insert( CepGen::GridHandler<3,1>::point_t{ { kt2, x, mu2 }, { fg } } ); } file.close(); } init(); CG_INFO( "GluonGrid" ) << "KMR grid evaluator built!\n\t" << " kt² in range [" << *kt2_vals.begin() << ":" << *kt2_vals.rbegin() << "]\n\t" << " x in range [" << *x_vals.begin() << ":" << *x_vals.rbegin() << "]\n\t" << " µ² in range [" << *mu2_vals.begin() << ":" << *mu2_vals.rbegin() << "]."; } double GluonGrid::operator()( double kt2, double x, double mu2 ) const { + std::cout << kt2 << "|" << x << "|" << mu2 << std::endl; return CepGen::GridHandler<3,1>::eval( { kt2, x, mu2 } ).at( 0 ); } } diff --git a/CepGen/StructureFunctions/MSTWGrid.cpp b/CepGen/StructureFunctions/MSTWGrid.cpp index 1207c33..8a91601 100644 --- a/CepGen/StructureFunctions/MSTWGrid.cpp +++ b/CepGen/StructureFunctions/MSTWGrid.cpp @@ -1,115 +1,113 @@ #include "CepGen/StructureFunctions/MSTWGrid.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include <fstream> - -#include <gsl/gsl_errno.h> -#include <gsl/gsl_math.h> +#include <set> namespace MSTW { const unsigned int Grid::good_magic = 0x5754534d; // MSTW in ASCII Grid& Grid::get( const char* filename ) { Parameterisation p; p.grid_path = filename; static Grid instance( p ); return instance; } Grid::Grid( const Parameterisation& param ) : CepGen::StructureFunctions( CepGen::SF::Type::MSTWgrid ), CepGen::GridHandler<2,2>( CepGen::GridType::logarithmic ), params( param ) { std::set<double> q2_vals, xbj_vals; { // file readout part std::ifstream file( params.grid_path, std::ios::binary | std::ios::in ); if ( !file.is_open() ) throw CG_FATAL( "Grid" ) << "Impossible to load grid file \"" << params.grid_path << "\"!"; file.read( reinterpret_cast<char*>( &header_ ), sizeof( header_t ) ); // first checks on the file header if ( header_.magic != good_magic ) throw CG_FATAL( "Grid" ) << "Wrong magic number retrieved: " << header_.magic << ", expecting " << good_magic << "."; if ( header_.nucleon != header_t::proton ) throw CG_FATAL( "Grid" ) << "Only proton structure function grids can be retrieved for this purpose!"; // retrieve all points and evaluate grid boundaries sfval_t val; while ( file.read( reinterpret_cast<char*>( &val ), sizeof( sfval_t ) ) ) { q2_vals.insert( val.q2 ); xbj_vals.insert( val.xbj ); insert( CepGen::GridHandler<2,2>::point_t{ { val.q2, val.xbj }, { val.f2, val.fl } } ); } file.close(); } if ( q2_vals.size() < 2 || xbj_vals.size() < 2 ) throw CG_FATAL( "Grid" ) << "Invalid grid retrieved!"; init(); CG_INFO( "Grid" ) << "MSTW@" << header_.order << " grid evaluator built " << "for " << header_.nucleon << " structure functions (" << header_.cl << ")\n\t" << " Q² in range [" << *q2_vals.begin() << ":" << *q2_vals.rbegin() << "]\n\t" << "xBj in range [" << *xbj_vals.begin() << ":" << *xbj_vals.rbegin() << "]."; } Grid& Grid::operator()( double q2, double xbj ) { const std::array<double,2> val = CepGen::GridHandler<2,2>::eval( { q2, xbj } ); F2 = val[0]; FL = val[1]; return *this; } std::ostream& operator<<( std::ostream& os, const sfval_t& val ) { return os << Form( "Q² = %.5e GeV²\txbj = %.4f\tF₂ = % .6e\tFL = % .6e", val.q2, val.xbj, val.f2, val.fl ); } std::ostream& operator<<( std::ostream& os, const Grid::header_t::order_t& order ) { switch ( order ) { case Grid::header_t::lo: return os << "LO"; case Grid::header_t::nlo: return os << "nLO"; case Grid::header_t::nnlo: return os << "nnLO"; } return os; } std::ostream& operator<<( std::ostream& os, const Grid::header_t::cl_t& cl ) { switch ( cl ) { case Grid::header_t::cl68: return os << "68% C.L."; case Grid::header_t::cl95: return os << "95% C.L."; } return os; } std::ostream& operator<<( std::ostream& os, const Grid::header_t::nucleon_t& nucl ) { switch ( nucl ) { case Grid::header_t::proton: return os << "proton"; case Grid::header_t::neutron: return os << "neutron"; } return os; } }