cepgen
is hosted by
Hepforge
,
IPPP Durham
CepGen
1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
GridHandler.cpp
Go to the documentation of this file.
1
/*
2
* CepGen: a central exclusive processes event generator
3
* Copyright (C) 2018-2024 Laurent Forthomme
4
*
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <gsl/gsl_errno.h>
20
#include <gsl/gsl_math.h>
21
22
#include <limits>
23
24
#include "
CepGen/Core/Exception.h
"
25
#include "
CepGen/Utils/GridHandler.h
"
26
27
//#define GRID_HANDLER_DEBUG 1
28
29
namespace
cepgen
{
30
template
<
size_t
D,
size_t
N>
31
GridHandler<D, N>::GridHandler
(
const
GridType
& grid_type) : grid_type_(grid_type) {
32
for
(
size_t
i = 0; i < D; ++i)
33
accel_
.emplace_back(gsl_interp_accel_alloc(), gsl_interp_accel_free);
34
}
35
36
template
<
size_t
D,
size_t
N>
37
typename
GridHandler<D, N>::values_t
GridHandler<D, N>::eval
(
coord_t
in_coords)
const
{
38
if
(!init_)
39
throw
CG_FATAL
(
"GridHandler"
) <<
"Grid extrapolator called but not initialised!"
;
40
41
values_t
out{};
42
coord_t
coord = in_coords;
43
switch
(grid_type_) {
44
case
GridType::logarithmic
: {
45
std::transform(coord.begin(), coord.end(), coord.begin(), [](
const
auto
& c) { return log10(c); });
46
}
break
;
47
case
GridType::square
: {
48
std::transform(coord.begin(), coord.end(), coord.begin(), [](
const
auto
& c) { return c * c; });
49
}
break
;
50
default
:
51
break
;
52
}
53
//--- dimension of the vector space coordinate to evaluate
54
switch
(D) {
55
case
1: {
56
for
(
size_t
i = 0; i < N; ++i) {
57
int
res = gsl_spline_eval_e(splines_1d_.at(i).get(), coord.at(0), accel_.at(0).get(), &out[i]);
58
if
(res != GSL_SUCCESS) {
59
out[i] = 0.;
60
CG_WARNING
(
"GridHandler"
) <<
"Failed to evaluate the value (N="
<< i <<
") "
61
<<
"for x = "
<< in_coords.at(0) <<
" in grid with boundaries "
<< boundaries()
62
<<
". GSL error: "
<< gsl_strerror(res);
63
}
64
}
65
}
break
;
66
case
2: {
67
#ifdef GSL_VERSION_ABOVE_2_1
68
const
double
x = coord.at(0), y = coord.at(1);
69
for
(
size_t
i = 0; i < N; ++i) {
70
int
res = gsl_spline2d_eval_e(splines_2d_.at(i).get(), x, y, accel_.at(0).get(), accel_.at(1).get(), &out[i]);
71
if
(res != GSL_SUCCESS) {
72
out[i] = 0.;
73
CG_WARNING
(
"GridHandler"
) <<
"Failed to evaluate the value (N="
<< i <<
") "
74
<<
"for x = "
<< x <<
" / y = "
<< y <<
" in grid with boundaries "
75
<< boundaries() <<
". GSL error: "
<< gsl_strerror(res);
76
}
77
}
78
#else
79
//--- retrieve the indices of the bin in the set
80
coord_t before(D), after(D);
81
findIndices(coord, before, after);
82
//--- find boundaries values
83
const
gridpoint_t &ext_11 = values_raw_.at({before[0], before[1]}),
84
&ext_12 = values_raw_.at({before[0], after[1]}),
85
&ext_21 = values_raw_.at({after[0], before[1]}),
86
&ext_22 = values_raw_.at({after[0], after[1]});
87
//--- now that we have the boundaries, we may interpolate
88
coord_t c_d(D);
89
for
(
size_t
i = 0; i < D; ++i)
90
c_d[i] = (after[i] != before[i]) ? (coord.at(i) - before[i]) / (after[i] - before[i]) : 0.;
91
const
gridpoint_t ext_1 = ext_11 * (1. - c_d[0]) + ext_21 * c_d[0];
92
const
gridpoint_t ext_2 = ext_12 * (1. - c_d[0]) + ext_22 * c_d[0];
93
out = ext_1 * (1. - c_d[1]) + ext_2 * c_d[1];
94
#endif
95
}
break
;
96
case
3: {
97
//--- retrieve the indices of the bin in the set
98
coord_t before(D), after(D);
99
findIndices(coord, before, after);
100
//--- find boundaries values
101
const
gridpoint_t &ext_111 = values_raw_.at({before[0], before[1], before[2]}),
102
&ext_112 = values_raw_.at({before[0], before[1], after[2]}),
103
&ext_121 = values_raw_.at({before[0], after[1], before[2]}),
104
&ext_122 = values_raw_.at({before[0], after[1], after[2]}),
105
&ext_211 = values_raw_.at({after[0], before[1], before[2]}),
106
&ext_212 = values_raw_.at({after[0], before[1], after[2]}),
107
&ext_221 = values_raw_.at({after[0], after[1], before[2]}),
108
&ext_222 = values_raw_.at({after[0], after[1], after[2]});
109
//--- now that we have the boundaries, we may interpolate
110
coord_t c_d(D);
111
for
(
size_t
i = 0; i < D; ++i)
112
c_d[i] = (after[i] != before[i]) ? (coord.at(i) - before[i]) / (after[i] - before[i]) : 0.;
113
const
gridpoint_t ext_11 = ext_111 * (1. - c_d[0]) + ext_211 * c_d[0];
114
const
gridpoint_t ext_12 = ext_112 * (1. - c_d[0]) + ext_212 * c_d[0];
115
const
gridpoint_t ext_21 = ext_121 * (1. - c_d[0]) + ext_221 * c_d[0];
116
const
gridpoint_t ext_22 = ext_122 * (1. - c_d[0]) + ext_222 * c_d[0];
117
const
gridpoint_t ext_1 = ext_11 * (1. - c_d[1]) + ext_21 * c_d[1];
118
const
gridpoint_t ext_2 = ext_12 * (1. - c_d[1]) + ext_22 * c_d[1];
119
out = ext_1 * (1. - c_d[2]) + ext_2 * c_d[2];
120
}
break
;
121
default
:
122
throw
CG_FATAL
(
"GridHandler"
) <<
"Unsupported number of dimensions: "
<< N <<
".\n\t"
123
<<
"Please contact the developers to add such a new feature."
;
124
}
125
return
out;
126
}
127
128
template
<
size_t
D,
size_t
N>
129
void
GridHandler<D, N>::insert
(
coord_t
coord,
values_t
value) {
130
auto
mod_coord = coord;
131
if
(grid_type_ !=
GridType::linear
)
132
for
(
auto
& c : mod_coord)
133
switch
(grid_type_) {
134
case
GridType::logarithmic
:
135
c = log10(c);
136
break
;
137
case
GridType::square
:
138
c *= c;
139
break
;
140
default
:
141
break
;
142
}
143
if
(values_raw_.count(mod_coord) != 0)
144
CG_WARNING
(
"GridHandler"
) <<
"Duplicate coordinate detected for x="
<< coord <<
"."
;
145
values_raw_[mod_coord] = value;
146
init_ =
false
;
147
}
148
149
template
<
size_t
D,
size_t
N>
150
void
GridHandler<D, N>::initialise
() {
151
if
(values_raw_.empty())
152
throw
CG_ERROR
(
"GridHandler"
) <<
"Empty grid."
;
153
gsl_set_error_handler_off();
154
//--- start by building grid coordinates from raw values
155
for
(
auto
& c : coords_)
156
c.clear();
157
for
(
const
auto
& val : values_raw_) {
158
unsigned
short
i = 0;
159
for
(
const
auto
& c : val.first) {
160
if
(std::find(coords_.at(i).begin(), coords_.at(i).end(), c) == coords_.at(i).end())
161
coords_.at(i).emplace_back(c);
162
++i;
163
}
164
}
165
for
(
auto
& c : coords_)
166
std::sort(c.begin(), c.end());
167
#ifdef GRID_HANDLER_DEBUG
168
CG_DEBUG
(
"GridHandler"
).log([&](
auto
& dbg) {
169
dbg <<
"Grid dump:"
;
170
// debugging of the grid coordinates
171
unsigned
short
i = 0;
172
for
(
const
auto
& cs : coords_) {
173
dbg <<
"\n>> coordinate "
<< (i++) <<
" has "
<<
utils::s
(
"member"
, cs.size(),
true
) <<
":"
;
174
unsigned
short
j = 0;
175
for
(
const
auto
& val : cs)
176
dbg << (j++ % 20 == 0 ?
"\n "
:
" "
) << val;
177
}
178
});
179
#endif
180
//--- particularise by dimension
181
switch
(D) {
182
case
1: {
//--- x |-> (f1,...)
183
const
gsl_interp_type* type = gsl_interp_cspline;
184
//const gsl_interp_type* type = gsl_interp_steffen;
185
#ifdef GSL_VERSION_ABOVE_2_1
186
const
unsigned
short
min_size = gsl_interp_type_min_size(type);
187
#else
188
const
unsigned
short
min_size = type->min_size;
189
#endif
190
if
(min_size >= values_raw_.size())
191
throw
CG_FATAL
(
"GridHandler"
) <<
"Not enough points for \""
<< type->name <<
"\" type of interpolation.\n\t"
192
<<
"Minimum required: "
<< min_size <<
", got "
<< values_raw_.size() <<
"!"
;
193
for
(
size_t
i = 0; i < N; ++i) {
194
values_[i].reset(
new
double
[values_raw_.size()]);
195
splines_1d_.emplace_back(gsl_spline_alloc(type, values_raw_.size()), gsl_spline_free);
196
}
197
// transform a map(coord -> values) to
198
// - 1 vector(coordinates)
199
// - N vectors(values)
200
std::vector<double> x_vec;
201
size_t
i = 0;
202
for
(
const
auto
& vals : values_raw_) {
203
x_vec.emplace_back(vals.first.at(0));
204
unsigned
short
j = 0;
205
for
(
const
auto
& val : vals.second)
206
values_[j++].get()[i] = val;
207
++i;
208
}
209
// initialise spline interpolation objects (one for each value)
210
for
(
size_t
j = 0; j < splines_1d_.size(); ++j)
211
gsl_spline_init(splines_1d_.at(j).get(), &x_vec[0], values_[j].get(), values_raw_.size());
212
}
break
;
213
case
2: {
//--- (x,y) |-> (f1,...)
214
#ifdef GSL_VERSION_ABOVE_2_1
215
if
(values_raw_.size() < gsl_interp2d_type_min_size(gsl_interp2d_bicubic))
216
CG_WARNING
(
"GridHandler"
) <<
"The grid size is too small ("
<< values_raw_.size() <<
" < "
217
<< gsl_interp2d_type_min_size(gsl_interp2d_bicubic)
218
<<
") for bicubic interpolation. Switching to a bilinear interpolation mode."
;
219
//const gsl_interp2d_type* type =
220
// (values_raw_.size() > gsl_interp2d_type_min_size(gsl_interp2d_bicubic) ? gsl_interp2d_bicubic
221
// : gsl_interp2d_bilinear);
222
const
gsl_interp2d_type* type = gsl_interp2d_bilinear;
223
splines_2d_.clear();
224
for
(
size_t
i = 0; i < N; ++i) {
225
values_[i].reset(
new
double
[coords_.at(0).size() * coords_.at(1).size()]);
226
splines_2d_.emplace_back(gsl_spline2d_alloc(type, coords_.at(0).size(), coords_.at(1).size()),
227
gsl_spline2d_free);
228
}
229
230
// second loop over all points to populate the grid
231
for
(
const
auto
& val : values_raw_) {
232
double
val_x = val.first.at(0), val_y = val.first.at(1);
233
// retrieve the index of the bin in the set
234
const
unsigned
short
id_x =
235
std::distance(coords_.at(0).begin(), std::lower_bound(coords_.at(0).begin(), coords_.at(0).end(), val_x));
236
const
unsigned
short
id_y =
237
std::distance(coords_.at(1).begin(), std::lower_bound(coords_.at(1).begin(), coords_.at(1).end(), val_y));
238
for
(
size_t
i = 0; i < splines_2d_.size(); ++i)
239
gsl_spline2d_set(splines_2d_.at(i).get(), values_[i].get(), id_x, id_y, val.second[i]);
240
}
241
242
// initialise spline interpolation objects (one for each value)
243
const
coord_t
&x_vec = coords_.at(0), &y_vec = coords_.at(1);
244
for
(
size_t
i = 0; i < splines_2d_.size(); ++i)
245
gsl_spline2d_init(
246
splines_2d_.at(i).get(), &x_vec[0], &y_vec[0], values_[i].get(), x_vec.size(), y_vec.size());
247
#else
248
CG_WARNING
(
"GridHandler"
) <<
"GSL version ≥ 2.1 is required for spline bilinear interpolation.\n\t"
249
<<
"Version "
<< GSL_VERSION <<
" is installed on this system!\n\t"
250
<<
"Will use a simple bilinear approximation instead."
;
251
#endif
252
}
break
;
253
default
:
254
break
;
255
}
256
init_ =
true
;
257
CG_DEBUG
(
"GridHandler"
).log([&](
auto
& log) {
258
log <<
"Grid evaluator initialised with boundaries: "
<< boundaries() <<
"."
;
259
#ifdef GRID_HANDLER_DEBUG
260
log <<
"\n"
261
<<
"Values handled:\n"
262
<< values_raw_;
263
#endif
264
});
265
}
266
267
template
<
size_t
D,
size_t
N>
268
std::array<Limits, D>
GridHandler<D, N>::boundaries
()
const
{
269
std::array<Limits, D> out;
270
const
auto
min_val = min(), max_val = max();
271
for
(
size_t
i = 0; i < D; ++i)
272
out[i] = {min_val[i], max_val[i]};
273
return
out;
274
}
275
276
template
<
size_t
D,
size_t
N>
277
std::array<double, D>
GridHandler<D, N>::min
()
const
{
278
std::array<double, D> out{};
279
size_t
i = 0;
280
for
(
const
auto
& c : coords_) {
// loop over all dimensions
281
const
auto
& min = std::min_element(c.begin(), c.end());
282
out[i++] = min != c.end() ? *min : std::numeric_limits<double>::infinity();
283
}
284
return
out;
285
}
286
287
template
<
size_t
D,
size_t
N>
288
std::array<double, D>
GridHandler<D, N>::max
()
const
{
289
std::array<double, D> out{};
290
size_t
i = 0;
291
for
(
const
auto
& c : coords_) {
// loop over all dimensions
292
const
auto
& max = std::max_element(c.begin(), c.end());
293
out[i++] = max != c.end() ? *max : std::numeric_limits<double>::infinity();
294
}
295
return
out;
296
}
297
298
template
<
size_t
D,
size_t
N>
299
void
GridHandler<D, N>::findIndices
(
const
coord_t& coord, coord_t& min, coord_t& max)
const
{
300
for
(
size_t
i = 0; i < D; ++i) {
301
const
auto
& c_i = coords_.at(i);
// extract all coordinates registered for this dimension
302
if
(coord.at(i) < *c_i.begin()) {
// under the range
303
CG_DEBUG_LOOP
(
"GridHandler:indices"
) <<
"Coordinate "
<< i <<
" in underflow range "
304
<<
"("
<< coord.at(i) <<
" < "
<< *c_i.begin() <<
")."
;
305
min[i] = max[i] = *c_i.begin();
306
}
else
if
(coord.at(i) > *c_i.rbegin()) {
// over the range
307
CG_DEBUG_LOOP
(
"GridHandler:indices"
) <<
"Coordinate "
<< i <<
" in overflow range "
308
<<
"("
<< coord.at(i) <<
" > "
<< *c_i.rbegin() <<
")."
;
309
min[i] = max[i] = *c_i.rbegin();
310
}
else
{
// in between two coordinates
311
auto
it_coord = std::lower_bound(c_i.begin(), c_i.end(), coord.at(i));
312
max[i] = *it_coord;
313
if
(it_coord != c_i.begin())
314
it_coord--;
315
min[i] = *it_coord;
316
}
317
}
318
}
319
320
//----------------------------------------------------------------------------
321
// grid manipulation utility
322
//----------------------------------------------------------------------------
323
324
template
<
size_t
D,
size_t
N>
325
typename
GridHandler<D, N>::gridpoint_t GridHandler<D, N>::gridpoint_t::operator*(
double
c)
const
{
326
gridpoint_t out = *
this
;
327
std::transform(out.begin(), out.end(), out.begin(), [&c](
const
auto
& a) { return a * c; });
328
return
out;
329
}
330
331
template
<
size_t
D,
size_t
N>
332
typename
GridHandler<D, N>::gridpoint_t GridHandler<D, N>::gridpoint_t::operator+(
const
gridpoint_t& rhs)
const
{
333
gridpoint_t out = *
this
;
334
for
(
size_t
i = 0; i < out.size(); ++i)
335
out[i] += rhs[i];
336
return
out;
337
}
338
339
template
class
GridHandler<1, 1>;
340
template
class
GridHandler<1, 2>;
341
template
class
GridHandler<2, 2>;
342
template
class
GridHandler<3, 1>;
343
}
// namespace cepgen
Exception.h
CG_FATAL
#define CG_FATAL(mod)
Definition
Exception.h:61
CG_ERROR
#define CG_ERROR(mod)
Definition
Exception.h:60
GridHandler.h
CG_WARNING
#define CG_WARNING(mod)
Definition
Message.h:228
CG_DEBUG_LOOP
#define CG_DEBUG_LOOP(mod)
Definition
Message.h:224
CG_DEBUG
#define CG_DEBUG(mod)
Definition
Message.h:220
cepgen::GridHandler
A generic class for grid interpolation.
Definition
GridHandler.h:44
cepgen::GridHandler::initialise
void initialise()
Initialise the grid and all useful interpolators/accelerators.
Definition
GridHandler.cpp:150
cepgen::GridHandler::insert
void insert(coord_t coord, values_t value)
Insert a new value in the grid.
Definition
GridHandler.cpp:129
cepgen::GridHandler::coord_t
std::vector< double > coord_t
Coordinates container.
Definition
GridHandler.h:46
cepgen::GridHandler::accel_
std::vector< std::unique_ptr< gsl_interp_accel, void(*)(gsl_interp_accel *)> > accel_
Definition
GridHandler.h:67
cepgen::GridHandler::boundaries
std::array< Limits, D > boundaries() const
Grid boundaries (collection of (min,max))
Definition
GridHandler.cpp:268
cepgen::GridHandler::max
std::array< double, D > max() const
Highest bound of the grid coordinates.
Definition
GridHandler.cpp:288
cepgen::GridHandler::eval
values_t eval(coord_t in_coords) const
Interpolate a point to a given coordinate.
Definition
GridHandler.cpp:37
cepgen::GridHandler::values_t
std::array< double, N > values_t
Value(s) at a given coordinate.
Definition
GridHandler.h:47
cepgen::GridHandler::min
std::array< double, D > min() const
Lowest bound of the grid coordinates.
Definition
GridHandler.cpp:277
cepgen::GridHandler::GridHandler
GridHandler(const GridType &grid_type)
Build a grid interpolator from a grid type.
Definition
GridHandler.cpp:31
cepgen::utils::s
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition
String.cpp:228
cepgen
Common namespace for this Monte Carlo generator.
Definition
CommandLineHandler.cpp:36
cepgen::GridType
GridType
Interpolation type for the grid coordinates.
Definition
GridHandler.h:39
cepgen::GridType::square
@ square
cepgen::GridType::logarithmic
@ logarithmic
cepgen::GridType::linear
@ linear
CepGen
Utils
GridHandler.cpp
Generated on Mon Jul 29 2024 for CepGen by
1.9.7