cepgen
is hosted by
Hepforge
,
IPPP Durham
CepGen
1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
Hist1D.cpp
Go to the documentation of this file.
1
/*
2
* CepGen: a central exclusive processes event generator
3
* Copyright (C) 2021-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
21
#include <cmath>
22
23
#include "
CepGen/Core/Exception.h
"
24
#include "
CepGen/Core/ParametersList.h
"
25
#include "
CepGen/Utils/Histogram.h
"
26
#include "
CepGen/Utils/RandomGenerator.h
"
27
#include "
CepGen/Utils/String.h
"
28
29
namespace
cepgen
{
30
namespace
utils {
31
Hist1D::Hist1D
(
const
ParametersList
& params)
32
:
Drawable
(params.get<std::string>(
"name"
), params.get<std::string>(
"title"
)) {
33
if
(
const
auto
& xbins = params.
get
<std::vector<double> >(
"xbins"
); xbins.size() > 1)
34
buildFromBins(xbins);
35
else
if
(
const
auto
& xrange = params.
get
<
Limits
>(
"xrange"
); xrange.
valid
())
36
buildFromRange(params.
get
<
int
>(
"nbins"
) > 0 ? params.
get
<
int
>(
"nbins"
) : params.
get
<
int
>(
"nbinsX"
), xrange);
37
else
38
throw
CG_FATAL
(
"Hist1D"
) <<
"Failed to build a 1D histogram with user parameters: "
<< params <<
"."
;
39
}
40
41
Hist1D::Hist1D
(
size_t
num_bins_x,
const
Limits
& xrange,
const
std::string& name,
const
std::string& title)
42
:
Drawable
(name, title) {
43
if
(num_bins_x == 0)
44
throw
CG_ERROR
(
"Hist1D"
) <<
"Number of bins must be strictly positive!"
;
45
buildFromRange(num_bins_x, xrange);
46
}
47
48
Hist1D::Hist1D
(
const
std::vector<double>& xbins,
const
std::string& name,
const
std::string& title)
49
:
Drawable
(name, title) {
50
if
(xbins.empty())
51
throw
CG_ERROR
(
"Hist1D"
) <<
"Number of bins must be strictly positive!"
;
52
buildFromBins(xbins);
53
}
54
55
Hist1D::Hist1D
(
const
Hist1D
& oth)
56
:
Histogram
(oth),
57
Drawable
(oth),
58
hist_(gsl_histogram_clone(oth.hist_.get())),
59
hist_w2_(gsl_histogram_clone(oth.hist_w2_.get())),
60
underflow_(oth.underflow_),
61
overflow_(oth.overflow_) {}
62
63
void
Hist1D::buildFromBins(
const
std::vector<double>& bins) {
64
if
(
bins
.size() < 1)
65
throw
CG_ERROR
(
"Hist1D:buildFromBins"
) <<
"Building a 1D histogram requires at least 1 bin."
;
66
hist_.reset(gsl_histogram_alloc(
bins
.size() - 1));
67
CG_ASSERT
(hist_);
68
if
(
auto
ret = gsl_histogram_set_ranges(hist_.get(),
bins
.data(),
bins
.size()); ret != GSL_SUCCESS)
69
throw
CG_ERROR
(
"Hist1D:buildFromBins"
) << gsl_strerror(ret);
70
hist_w2_ = gsl_histogram_ptr(gsl_histogram_clone(hist_.get()));
71
CG_ASSERT
(hist_w2_);
72
CG_DEBUG
(
"Hist1D:buildFromBins"
) <<
"Booking a 1D histogram with "
<<
s
(
"bin"
,
bins
.size(),
true
) <<
" in range "
73
<<
bins
<<
"."
;
74
}
75
76
void
Hist1D::buildFromRange(
size_t
num_bins,
const
Limits
& range) {
77
if
(
range
.
range
() <= 0.)
78
throw
CG_ERROR
(
"Hist1D:buildFromRange"
) <<
"Invalid range for binning: "
<<
range
<<
"."
;
79
if
(num_bins < 1)
80
throw
CG_ERROR
(
"Hist1D:buildFromRange"
) <<
"Building a 1D histogram requires at least 1 bin."
;
81
hist_.reset(gsl_histogram_alloc(num_bins));
82
CG_ASSERT
(hist_);
83
if
(
auto
ret = gsl_histogram_set_ranges_uniform(hist_.get(),
range
.
min
(),
range
.
max
()); ret != GSL_SUCCESS)
84
throw
CG_ERROR
(
"Hist1D:buildFromRange"
) << gsl_strerror(ret);
85
hist_w2_ = gsl_histogram_ptr(gsl_histogram_clone(hist_.get()));
86
CG_ASSERT
(hist_w2_);
87
CG_DEBUG
(
"Hist1D:buildFromRange"
) <<
"Booking a 1D histogram with "
<<
s
(
"bin"
, num_bins,
true
) <<
" in range "
88
<<
range
<<
"."
;
89
}
90
91
void
Hist1D::clear
() {
92
CG_ASSERT
(hist_);
93
CG_ASSERT
(hist_w2_);
94
gsl_histogram_reset(hist_.get());
95
gsl_histogram_reset(hist_w2_.get());
96
}
97
98
void
Hist1D::fill
(
double
x,
double
weight) {
99
CG_ASSERT
(hist_);
100
CG_ASSERT
(hist_w2_);
101
{
// reduce the scope of 'ret'
102
auto
ret = gsl_histogram_accumulate(hist_.get(), x, weight);
103
if
(ret == GSL_SUCCESS) {
104
if
(
auto
ret2 = gsl_histogram_accumulate(hist_w2_.get(), x, weight * weight) != GSL_SUCCESS)
105
throw
CG_ERROR
(
"Hist1D:fill"
) <<
"(w2 histogram): "
<< gsl_strerror(ret2);
106
return
;
107
}
108
if
(ret != GSL_EDOM)
109
throw
CG_ERROR
(
"Hist1D:fill"
) << gsl_strerror(ret);
110
}
111
if
(x <
range
().min())
112
underflow_ += weight;
113
else
114
overflow_ += weight;
115
}
116
117
void
Hist1D::add
(
Hist1D
oth,
double
scaling) {
118
CG_ASSERT
(hist_);
119
CG_ASSERT
(hist_w2_);
120
CG_ASSERT
(oth.hist_);
121
CG_ASSERT
(oth.hist_w2_);
122
if
(oth.
integral
(
true
) == 0.) {
123
CG_WARNING
(
"Hist1D:add"
) <<
"Other histogram is empty."
;
124
return
;
125
}
126
const
double
scl = std::pow(oth.
integral
(), -2);
127
oth.
scale
(scaling);
128
gsl_histogram_scale(oth.hist_w2_.get(), scl);
129
if
(
auto
ret = gsl_histogram_add(hist_.get(), oth.hist_.get()); ret != GSL_SUCCESS)
130
throw
CG_ERROR
(
"Hist1D:add"
) << gsl_strerror(ret);
131
gsl_histogram_add(hist_w2_.get(), oth.hist_w2_.get());
132
underflow_ += oth.underflow_;
133
overflow_ += oth.overflow_;
134
}
135
136
void
Hist1D::scale
(
double
scaling) {
137
CG_ASSERT
(hist_);
138
if
(
auto
ret = gsl_histogram_scale(hist_.get(), scaling); ret != GSL_SUCCESS)
139
throw
CG_ERROR
(
"Hist1D:scale"
) << gsl_strerror(ret);
140
gsl_histogram_scale(hist_w2_.get(), scaling * scaling);
141
underflow_ *= scaling;
142
overflow_ *= scaling;
143
}
144
145
Drawable::axis_t
Hist1D::axis
()
const
{
146
axis_t
axis
;
147
for
(
size_t
bin
= 0;
bin
<
nbins
(); ++
bin
) {
148
const
auto
& range_i =
binRange
(
bin
);
149
axis
[
coord_t
{range_i.x(0.5), 0.5 * range_i.range(),
format
(
"[%7.2f,%7.2f)"
, range_i.min(), range_i.max())}] =
150
value
(
bin
);
151
}
152
return
axis
;
153
}
154
155
size_t
Hist1D::nbins
()
const
{
156
CG_ASSERT
(hist_);
157
return
gsl_histogram_bins(hist_.get());
158
}
159
160
Limits
Hist1D::range
()
const
{
161
CG_ASSERT
(hist_);
162
return
Limits
{gsl_histogram_min(hist_.get()), gsl_histogram_max(hist_.get())};
163
}
164
165
Limits
Hist1D::binRange
(
size_t
bin)
const
{
166
CG_ASSERT
(hist_);
167
Limits
range
;
168
if
(
auto
ret = gsl_histogram_get_range(hist_.get(),
bin
, &
range
.
min
(), &
range
.
max
()); ret != GSL_SUCCESS)
169
throw
CG_ERROR
(
"Hist1D:binRange"
) <<
"Bin "
<<
bin
<<
": "
<< gsl_strerror(ret);
170
return
range
;
171
}
172
173
std::vector<double>
Hist1D::bins
(
BinMode
mode)
const
{
174
const
auto
bins
=
extractBins
(mode,
nbins
(), std::bind(&
Hist1D::binRange
,
this
, std::placeholders::_1));
175
return
std::vector<double>(
bins
.begin(),
bins
.end());
176
}
177
178
size_t
Hist1D::bin
(
double
x)
const
{
179
size_t
bin_id;
180
if
(
auto
ret = gsl_histogram_find(hist_.get(), x, &bin_id); ret != GSL_SUCCESS)
181
throw
CG_ERROR
(
"Hist1D:bin"
) <<
"Failed to retrieve bin index for value "
<< x <<
": "
<< gsl_strerror(ret);
182
return
bin_id;
183
}
184
185
std::vector<Value>
Hist1D::values
()
const
{
186
std::vector<Value>
values
;
187
for
(
size_t
i = 0; i <
nbins
(); ++i)
188
values
.emplace_back(
value
(i));
189
return
values
;
190
}
191
192
Value
Hist1D::value
(
size_t
bin)
const
{
193
CG_ASSERT
(hist_);
194
CG_ASSERT
(hist_w2_);
195
return
Value
{gsl_histogram_get(hist_.get(),
bin
), std::sqrt(gsl_histogram_get(hist_w2_.get(),
bin
))};
196
}
197
198
void
Hist1D::setValue
(
size_t
bin,
Value
val) {
199
const
auto
bin_centre =
binRange
(
bin
).
x
(0.5);
200
const
auto
val_old =
value
(
bin
);
201
gsl_histogram_accumulate(hist_.get(), bin_centre, val - val_old);
202
gsl_histogram_accumulate(hist_w2_.get(),
203
bin_centre,
204
val.
uncertainty
() * val.
uncertainty
() - val_old.uncertainty() * val_old.uncertainty());
205
}
206
207
double
Hist1D::mean
()
const
{
208
CG_ASSERT
(hist_);
209
return
gsl_histogram_mean(hist_.get());
210
}
211
212
double
Hist1D::rms
()
const
{
213
CG_ASSERT
(hist_);
214
return
gsl_histogram_sigma(hist_.get());
215
}
216
217
double
Hist1D::minimum
()
const
{
218
CG_ASSERT
(hist_);
219
return
gsl_histogram_min_val(hist_.get());
220
}
221
222
double
Hist1D::maximum
()
const
{
223
CG_ASSERT
(hist_);
224
return
gsl_histogram_max_val(hist_.get());
225
}
226
227
double
Hist1D::integral
(
bool
include_out_of_range)
const
{
228
CG_ASSERT
(hist_);
229
auto
integr = gsl_histogram_sum(hist_.get());
230
if
(include_out_of_range)
231
integr += underflow_ + overflow_;
232
return
integr;
233
}
234
235
double
Hist1D::sample
(
RandomGenerator
& rng)
const
{
236
if
(!pdf_) {
237
pdf_.reset(gsl_histogram_pdf_alloc(
nbins
()));
238
if
(
const
auto
ret = gsl_histogram_pdf_init(pdf_.get(), hist_.get()); ret != GSL_SUCCESS)
239
throw
CG_ERROR
(
"Hist1D:sample"
) <<
"Failed to allocate the histogram PDF. GSL yielded: "
<< gsl_strerror(ret);
240
}
241
return
gsl_histogram_pdf_sample(pdf_.get(), rng.
uniform
());
242
}
243
244
double
Hist1D::chi2test
(
const
Hist1D
& oth,
size_t
& ndfval)
const
{
245
if
(
nbins
() != oth.
nbins
())
246
return
0.;
247
double
sum1{0.}, sum2{0.};
248
for
(
size_t
i = 0; i <
nbins
(); ++i) {
249
const
auto
ru1 =
value
(i).
relativeUncertainty
(), ru2 = oth.
value
(i).
relativeUncertainty
();
250
sum1 += ru1 > 0. ? 1. / ru1 / ru1 : 0.;
251
sum2 += ru2 > 0. ? 1. / ru2 / ru2 : 0.;
252
}
253
if
(sum1 == 0. || sum2 == 0.) {
254
ndfval = 0;
255
return
0.;
256
}
257
// perform the test
258
double
chi2val = 0.;
259
ndfval =
nbins
();
260
for
(
size_t
i = 0; i <
nbins
(); ++i) {
261
const
auto
ru1 =
value
(i).
relativeUncertainty
(), ru2 = oth.
value
(i).
relativeUncertainty
();
262
const
auto
cnt1 = ru1 > 0. ? 1. / ru1 / ru1 : 0., cnt2 = ru2 > 0. ? 1. / ru2 / ru2 : 0.;
263
if
(cnt1 == 0. && cnt2 == 0.) {
264
--ndfval;
265
continue
;
266
}
267
chi2val += std::pow(sum2 * cnt1 - sum1 * cnt2, 2) / (cnt1 + cnt2);
268
}
269
chi2val /= sum1 * sum2;
270
return
chi2val;
271
}
272
}
// namespace utils
273
}
// namespace cepgen
Exception.h
CG_FATAL
#define CG_FATAL(mod)
Definition
Exception.h:61
CG_ERROR
#define CG_ERROR(mod)
Definition
Exception.h:60
CG_ASSERT
#define CG_ASSERT(assertion)
Definition
Exception.h:62
Histogram.h
CG_WARNING
#define CG_WARNING(mod)
Definition
Message.h:228
CG_DEBUG
#define CG_DEBUG(mod)
Definition
Message.h:220
ParametersList.h
RandomGenerator.h
String.h
cepgen::Limits
Validity interval for a variable.
Definition
Limits.h:28
cepgen::Limits::x
double x(double v) const
Find the [0,1] value scaled between minimum and maximum.
Definition
Limits.cpp:97
cepgen::Limits::valid
bool valid() const
Is there a lower and upper limit?
Definition
Limits.cpp:85
cepgen::Limits::range
double range() const
Full variable range allowed.
Definition
Limits.cpp:65
cepgen::Limits::min
double min() const
Lower limit to apply on the variable.
Definition
Limits.h:52
cepgen::Limits::max
double max() const
Upper limit to apply on the variable.
Definition
Limits.h:54
cepgen::ParametersList
Definition
ParametersList.h:52
cepgen::ParametersList::get
T get(const std::string &key, const T &def=default_arg< T >::get()) const
Get a parameter value.
Definition
ParametersList.cpp:391
cepgen::Value
A scalar value with its uncertainty.
Definition
Value.h:26
cepgen::Value::relativeUncertainty
double relativeUncertainty() const
Relative uncertainty around the central value.
Definition
Value.cpp:28
cepgen::Value::uncertainty
double uncertainty() const
Absolute uncertainty around the central value.
Definition
Value.h:35
cepgen::utils::Drawable
A generic object which can be drawn in the standard output.
Definition
Drawable.h:31
cepgen::utils::Drawable::axis_t
std::map< coord_t, Value > axis_t
Metadata for an axis (coordinates and bins value)
Definition
Drawable.h:95
cepgen::utils::Hist1D
1D histogram container
Definition
Histogram.h:72
cepgen::utils::Hist1D::fill
void fill(double x, double weight=1.)
Increment the histogram with one value.
Definition
Hist1D.cpp:98
cepgen::utils::Hist1D::integral
double integral(bool=false) const override
Compute the histogram integral.
Definition
Hist1D.cpp:227
cepgen::utils::Hist1D::bin
size_t bin(double x) const
Retrieve the bin index for a x value.
Definition
Hist1D.cpp:178
cepgen::utils::Hist1D::setValue
void setValue(size_t bin, Value value)
Set the value + uncertainty for one bin.
Definition
Hist1D.cpp:198
cepgen::utils::Hist1D::scale
void scale(double) override
Rescale all histogram bins by a constant factor.
Definition
Hist1D.cpp:136
cepgen::utils::Hist1D::mean
double mean() const
Compute the mean histogram value over full range.
Definition
Hist1D.cpp:207
cepgen::utils::Hist1D::nbins
size_t nbins() const
Number of histogram bins.
Definition
Hist1D.cpp:155
cepgen::utils::Hist1D::add
void add(Hist1D, double scaling=1.)
Bin-to-bin addition of another histogram to this one.
Definition
Hist1D.cpp:117
cepgen::utils::Hist1D::axis
axis_t axis() const
Axis content.
Definition
Hist1D.cpp:145
cepgen::utils::Hist1D::minimum
double minimum() const override
Retrieve the maximum bin value.
Definition
Hist1D.cpp:217
cepgen::utils::Hist1D::rms
double rms() const
Compute the root-mean-square value over full range.
Definition
Hist1D.cpp:212
cepgen::utils::Hist1D::values
std::vector< Value > values() const
Retrieve the value + uncertainty for all bins.
Definition
Hist1D.cpp:185
cepgen::utils::Hist1D::value
Value value(size_t bin) const
Retrieve the value + uncertainty for one bin.
Definition
Hist1D.cpp:192
cepgen::utils::Hist1D::binRange
Limits binRange(size_t bin) const
Range for a single bin.
Definition
Hist1D.cpp:165
cepgen::utils::Hist1D::Hist1D
Hist1D(const ParametersList &)
Build a histogram from user-steeed parameters.
Definition
Hist1D.cpp:31
cepgen::utils::Hist1D::bins
std::vector< double > bins(BinMode) const
List of bins limits (nbins + 1 values if min-max, nbins values otherwise)
Definition
Hist1D.cpp:173
cepgen::utils::Hist1D::maximum
double maximum() const override
Retrieve the minimum bin value.
Definition
Hist1D.cpp:222
cepgen::utils::Hist1D::chi2test
double chi2test(const Hist1D &, size_t &ndf) const
Perform a chi^2 test between two histograms.
Definition
Hist1D.cpp:244
cepgen::utils::Hist1D::range
Limits range() const
Axis range.
Definition
Hist1D.cpp:160
cepgen::utils::Hist1D::sample
double sample(RandomGenerator &) const
Sample individual "events" from a distribution.
Definition
Hist1D.cpp:235
cepgen::utils::Hist1D::clear
void clear() override
Reset the histogram.
Definition
Hist1D.cpp:91
cepgen::utils::Histogram
Generic text-based plotting utility.
Definition
Histogram.h:41
cepgen::utils::Histogram::extractBins
std::set< double > extractBins(BinMode mode, size_t num_bins, const std::function< Limits(size_t)> &bins_extractor) const
Extract the list of bin limits.
Definition
Histogram.cpp:26
cepgen::utils::Histogram::BinMode
BinMode
Definition
Histogram.h:46
cepgen::utils::RandomGenerator
A random number generator.
Definition
RandomGenerator.h:31
cepgen::utils::RandomGenerator::uniform
virtual double uniform(double min=0., double max=1.)=0
cepgen::utils::format
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition
String.h:61
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::utils::Drawable::coord_t
Generic bin coordinate and its human-readable label.
Definition
Drawable.h:87
CepGen
Utils
Hist1D.cpp
Generated on Mon Jul 29 2024 for CepGen by
1.9.7