• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rlalik / HelloFitty / 16525331218

25 Jul 2025 03:10PM UTC coverage: 84.992% (-0.4%) from 85.39%
16525331218

push

github

rlalik
Add fit_result struct

26 of 49 new or added lines in 3 files covered. (53.06%)

4 existing lines in 1 file now uncovered.

538 of 633 relevant lines covered (84.99%)

20.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.7
/include/hellofitty.hpp
1
/*
2
    Hello Fitty - a versatile histogram fitting tool for ROOT-based projects
3
    Copyright (C) 2015-2023  Rafał Lalik <rafallalik@gmail.com>
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
    (at your option) 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
#ifndef HELLOFITTY_HELLOFITTY_H
20
#define HELLOFITTY_HELLOFITTY_H
21

22
#include "HelloFitty/hellofitty_export.hpp"
23

24
#include <RtypesCore.h>
25
#include <TFitResultPtr.h>
26

27
#include <functional>
28
#include <memory>
29
#include <optional>
30
#include <stdexcept>
31
#include <string>
32

33
#if __cplusplus < 201402L
34
#    define CONSTEXPR
35
#else
36
#    define CONSTEXPR constexpr
37
#endif
38

39
class TF1;
40
class TGraph;
41
class TH1;
42

43
namespace hf
44
{
45

46
/// Exceptions
47

48
// Thrown when the entry line is ill-formed
49
class format_error : public std::runtime_error
50
{
51
public:
52
    using std::runtime_error::runtime_error;
8✔
53
};
54

55
class index_error : public std::out_of_range
56
{
57
public:
58
    using std::out_of_range::out_of_range;
2✔
59
};
60

61
class length_error : public std::length_error
62
{
63
public:
64
    using std::length_error::length_error;
1✔
65
};
66

67
// Incorrect fitting range
68
class range_error : public std::runtime_error
69
{
70
public:
71
    using std::runtime_error::runtime_error;
×
72
};
73

74
namespace detail
75
{
76
struct draw_opts_impl;
77
struct entry_impl;
78
struct fitter_impl;
79
} // namespace detail
80

81
class HELLOFITTY_EXPORT draw_opts final
32✔
82
{
83
public:
84
    draw_opts();
85
    draw_opts(const draw_opts& other);
86

87
    /// Make function visible
88
    /// @param vis visibility
89
    /// @return reference to itself
90
    auto set_visible(bool vis) -> draw_opts&;
91
    /// Line color
92
    /// @param color color
93
    /// @return reference to itself
94
    auto set_line_color(Color_t color) -> draw_opts&;
95
    /// Line width
96
    /// @param width line width
97
    /// @return reference to itself
98
    auto set_line_width(Width_t width) -> draw_opts&;
99
    /// Line style
100
    /// @param style line style
101
    /// @return reference to itself
102
    auto set_line_style(Style_t style) -> draw_opts&;
103
    /// Apply style to function
104
    /// @param function function
105
    auto apply(TF1* function) const -> void;
106
    /// Print style info
107
    auto print() const -> void;
108

109
private:
110
    std::unique_ptr<detail::draw_opts_impl> m_d;
111
};
112

113
/// Structure stores a set of values for a single function parameters like the the mean value,
114
/// lwoer or upper boundaries, free or fixed fitting mode.
115
struct param final
116
{
117
    /// Fitting mode.
118
    enum class fit_mode
119
    {
120
        free, ///< parameter is free for fitting
121
        fixed ///< parameter is fixed
122
    };
123

124
    Double_t value {0.0};           ///< param value
125
    Double_t min {0.0};             ///< lower limit
126
    Double_t max {0.0};             ///< upper limit
127
    fit_mode mode {fit_mode::free}; ///< Parameter fitting mode
128
    bool has_limits {false};        ///< Remembers whether hit limits were set
129
    int print_precision {8};        ///< Screen print precision
130
    int store_precision {8};        ///< File export precision
131

132
    constexpr param() = default;
365✔
133

134
    /// Accept param value and fit mode
135
    /// @param par_value initial parameter value
136
    /// @param par_mode parameter fitting mode, see @ref fit_mode
137
    constexpr explicit param(Double_t par_value, param::fit_mode par_mode)
58✔
138
        : value(par_value)
58✔
139
        , mode(par_mode)
58✔
140
    {
141
    }
×
142

143
    /// Accept param value, boundaries and fit mode
144
    /// @param par_value initial parameter value
145
    /// @param par_min value's lower fit boundary
146
    /// @param par_max value's upper fit boundary
147
    /// @param par_mode parameter fitting mode, see @ref fit_mode
148
    constexpr explicit param(Double_t par_value, Double_t par_min, Double_t par_max, param::fit_mode par_mode)
28✔
149
        : value(par_value)
28✔
150
        , min(par_min)
28✔
151
        , max(par_max)
28✔
152
        , mode(par_mode)
28✔
153
        , has_limits(true)
28✔
154
    {
155
    }
×
156

157
    /// Print param value line.
158
    auto print() const -> void;
159
};
160

161
class fitter;
162

163
namespace parser
164
{
165
struct v1;
166
struct v2;
167
} // namespace parser
168

169
/// Stores full description of a single fit entry - signal and background functions, and parameters.
170
class HELLOFITTY_EXPORT entry final
171
{
172
public:
173
    entry();
174
    explicit entry(Double_t range_lower, Double_t range_upper);
175

176
    entry(const entry& other);
177
    auto operator=(const entry&) -> entry&;
178

179
    explicit entry(entry&&) = default;
21✔
180
    auto operator=(entry&&) -> entry& = default;
181

182
    ~entry() noexcept;
183

184
    auto init() -> void;
185

186
    /// Add function of given body to functions collection
187
    /// @param formula the function body
188
    /// @return function id
189
    auto add_function(std::string formula) -> int;
190

191
    /// Get function body string
192
    /// @return function body as string
193
    /// @throw std::out_of_range if function_index incorrect
194
    auto get_function(int function_index) const -> const char*;
195

196
    auto set_param(int par_id, param par) -> void;
197
    auto set_param(int par_id, Double_t value, hf::param::fit_mode mode = hf::param::fit_mode::free) -> void;
198
    auto set_param(int par_id, Double_t value, Double_t min, Double_t max,
199
                   hf::param::fit_mode mode = hf::param::fit_mode::free) -> void;
200
    auto update_param(int par_id, Double_t value) -> void;
201

202
    auto get_param(int par_id) const -> hf::param;
203
    auto get_param(const char* name) const -> hf::param;
204

205
    auto param(int par_id) -> hf::param&;
206
    auto param(int par_id) const -> const hf::param&;
207

208
    auto param(const char* name) -> hf::param&;
209
    auto param(const char* name) const -> const hf::param&;
210

211
    auto set_fit_range(Double_t range_lower, Double_t range_upper) -> void;
212
    auto get_fit_range_min() const -> Double_t;
213
    auto get_fit_range_max() const -> Double_t;
214

215
    /// Return numbers of functions
216
    /// @return number of functions
217
    auto get_functions_count() const -> int;
218

219
    /// Return reference to given function
220
    /// @param function_index function id
221
    /// @return function reference
222
    /// @throw std::out_of_range
223
    auto get_function_object(int function_index) const -> const TF1&;
224

225
    /// Return reference to signal function
226
    /// @return function reference
227
    auto get_function_object(int function_index) -> TF1&;
228

229
    /// Return reference to total function
230
    /// @return function reference
231
    auto get_function_object() const -> const TF1&;
232

233
    /// Return reference to total function
234
    /// @return function reference
235
    auto get_function_object() -> TF1&;
236

237
    /// Clone function with new name. Function passes ownership of the clone.
238
    /// @param function_index function id
239
    /// @param new_name name for cloned function
240
    /// @return unique pointer to cloned function
241
    auto clone_function(int function_index, const char* new_name = nullptr) -> std::unique_ptr<TF1>;
242

243
    /// Clone total function with new name. Function passes ownership of the clone.
244
    /// @param new_name name for cloned function
245
    /// @return unique pointer to cloned function
246
    auto clone_function(const char* new_name = nullptr) -> std::unique_ptr<TF1>;
247

248
    /// Return numbers of params in total function.
249
    auto get_function_params_count() const -> int;
250

251
    auto get_flag_rebin() const -> Int_t;
252
    auto get_flag_disabled() const -> bool;
253

254
    auto is_valid() const -> bool;
255

256
    auto clear() -> void;
257

258
    auto export_entry() const -> std::string;
259

260
    /// Store current parameter in backup storage
261
    auto backup() -> void;
262
    /// Restore parameters from backup storage
263
    auto restore() -> void;
264
    /// Clear backup storage
265
    auto drop() -> void;
266

267
    auto set_function_style(int function_index) -> draw_opts&;
268
    auto set_function_style() -> draw_opts&;
269

270
    auto print(const std::string& name, bool detailed = false) const -> void;
271

272
    friend hf::fitter;
273
    friend hf::parser::v1;
274
    friend hf::parser::v2;
275

276
private:
277
    std::unique_ptr<detail::entry_impl> m_d;
278
};
279

280
/// Specifies the data file format
281
enum class format_version
282
{
283
    detect, ///< tries to detect the format, uses the same format for export
284
    v1,     ///< fixed two functions format
285
    v2,     ///< variable function number with params on the tail of line
286
};
287

288
using params_vector = std::vector<param>;
289

290
class HELLOFITTY_EXPORT fitter final
291
{
292
public:
293
    enum class priority_mode
294
    {
295
        reference,
296
        auxiliary,
297
        newer
298
    };
299

300
    enum class fit_status
301
    {
302
        ok,
303
        missing_entry,
304
        empty_range,
305
        failed,
306
        qa_worse_chi2,
307
    };
308

309
    enum class fit_qa_status
310
    {
311
        none,
312
        chi2_better,
313
        chi2_same,
314
        chi2_worse,
315
    };
316

317
    using fit_qa_checker = std::function<hf::fitter::fit_qa_status(const params_vector&, double, const params_vector&,
318
                                                                   double, const TFitResultPtr&)>;
319

320
    struct fit_result
19✔
321
    {
322
        fit_status status;
323
        entry* hfp {nullptr};
324
        fit_qa_status qa {fit_qa_status::none};
325
        TFitResultPtr result;
326

327
        operator bool() const { return status == fit_status::ok; }
4✔
328
    };
329

330
    fitter();
331

332
    explicit fitter(const fitter&) = delete;
333
    auto operator=(const fitter&) -> fitter& = delete;
334

335
    fitter(fitter&&);
336
    auto operator=(fitter&&) -> fitter&;
337

338
    ~fitter();
339

340
    auto clear() -> void;
341

342
    /// Load parameters from the reference input.
343
    /// @param input_file the input parameters
344
    /// @return the file was properly imported
345
    auto init_from_file(std::string input_file) -> bool;
346
    /// Load parameters from the reference input or the auxiliary input, depend on mode.
347
    /// @param input_file the input file for parameters
348
    /// @param aux_file the output file for parameters
349
    /// @param mode source selection mode
350
    /// @return the file was properly imported
351
    auto init_from_file(std::string input_file, std::string aux_file,
352
                        priority_mode mode = priority_mode::newer) -> bool;
353
    /// Force file exporting. If the output file was not set, the function does nothing.
354
    /// @return true if the file was written
355
    auto export_to_file(bool update_reference = false) -> bool;
356

357
    auto find_fit(TH1* hist) const -> entry*;
358
    auto find_fit(const char* name) const -> entry*;
359

360
    /// Find hfp by histogram name, or create from generic if not null.
361
    /// @param hist object to find hfp for
362
    /// @param generic object to use as a reference if name not found
363
    /// @return hfp found for name, or created from generic if not nullptr, or nullptr
364
    auto find_or_make(TH1* hist, entry* generic = nullptr) -> entry*;
365
    auto find_or_make(const char* name, entry* generic = nullptr) -> entry*;
366

367
    /// Fit the histogram using entry either located in the collection or using generic entry if provided.
368
    /// @param hist histogram to be fitted
369
    /// @param pars histogram fitting pars
370
    /// @param gpars histogram fit drawing pars
371
    /// @param generic histogram entry to be used if non present yet
372
    /// @return pair of bool (true if fit successful) and used entry
373
    auto fit(TH1* hist, const char* pars = "BQS", const char* gpars = "") -> fit_result;
374
    auto fit(TH1* hist, entry* generic, const char* pars = "BQS", const char* gpars = "") -> fit_result;
375
    auto fit(entry* custom, TH1* hist, const char* pars = "BQS", const char* gpars = "") -> fit_result;
376

377
    /// Fit the graph using entry either located in the collection or using generic entry if provided.
378
    /// @param name entry name (graphs are not named object)
379
    /// @param graph graph to be fitted
380
    /// @param pars graph fitting pars
381
    /// @param gpars graph fit drawing pars
382
    /// @param generic histogram entry to be used if non present yet
383
    /// @return pair of bool (true if fit successful) and used entry
384
    auto fit(const char* name, TGraph* graph, const char* pars = "BQS", const char* gpars = "") -> fit_result;
385
    auto fit(const char* name, TGraph* graph, entry* generic, const char* pars = "BQS",
386
             const char* gpars = "") -> fit_result;
387
    auto fit(entry* custom, const char* name, TGraph* graph, const char* pars = "BQS",
388
             const char* gpars = "") -> fit_result;
389

390
    auto print() const -> void;
391

392
    static auto set_verbose(bool verbose) -> void;
393

394
    /// Insert new pair of name,entry. If the entry for given name exists, update it with the
395
    /// new value.
396
    /// @param name histogram name
397
    /// @param hfp histogram fit entry
398
    /// @return pointer to the registered entry
399
    auto insert_parameter(std::string name, entry hfp) -> entry*;
400
    /// Insert new pair of name,entry. If the entry for given name exists, update it with the
401
    /// new value.
402
    /// @param hfp pair of histogram name and histogram fit entry
403
    /// @return pointer to the registered entry
404
    auto insert_parameter(std::pair<std::string, entry> hfp) -> entry*;
405

406
    auto set_name_decorator(std::string decorator) -> void;
407
    auto clear_name_decorator() -> void;
408

409
    auto set_function_decorator(std::string decorator) -> void;
410

411
    auto set_function_style(int function_index) -> draw_opts&;
412
    auto set_function_style() -> draw_opts&;
413

414
    auto get_function_style(int function_index) -> draw_opts&;
415
    auto get_function_style() -> draw_opts&;
416

417
    auto set_qa_checker(fit_qa_checker checker) -> void;
418

419
private:
420
    auto import_parameters(const std::string& filename) -> bool;
421
    auto export_parameters(const std::string& filename) -> bool;
422
    std::unique_ptr<detail::fitter_impl> m_d;
423
};
424

425
struct chi2checker
426
{
427
    auto operator()(const params_vector& /*old_pars*/, double old_chi2, const params_vector& /*new_pars*/,
8✔
428
                    double new_chi2, const TFitResultPtr&) -> fitter::fit_qa_status
429
    {
430
        if (new_chi2 < old_chi2) { return fitter::fit_qa_status::chi2_better; }
8✔
NEW
431
        if (new_chi2 == old_chi2) { return fitter::fit_qa_status::chi2_same; }
×
432
        return fitter::fit_qa_status::chi2_worse;
433
    }
434
};
435

436
namespace tools
437
{
438

439
auto HELLOFITTY_EXPORT format_name(const std::string& name, const std::string& decorator) -> std::string;
440

441
/// Detect format of the line. A simple check of the pattern characteristic is made. In case of ill-formed line it may
442
/// result in false detection.
443
/// @param line entry line to be tested
444
/// @return format name
445
auto HELLOFITTY_EXPORT detect_format(const std::string& line) -> format_version;
446

447
/// Parse the entry line according to given format, by default tries to detect the format.
448
/// @param line entry line to be parsed
449
/// @param version entry version
450
/// @return ownership of the parsed entry
451
auto HELLOFITTY_EXPORT parse_line_entry(const std::string& line, format_version version = hf::format_version::detect)
452
    -> std::pair<std::string, entry>;
453

454
/// Export the entry to the text line using given format. By default the newest v2 is used.
455
/// @param name the entry (histogram) name
456
/// @param entry fit entry
457
/// @param version entry version
458
/// @return the entry string
459
auto HELLOFITTY_EXPORT format_line_entry(const std::string& name, const hf::entry* entry,
460
                                         format_version version = hf::format_version::v2) -> std::string;
461

462
} // namespace tools
463

464
} // namespace hf
465

466
#ifdef FMT_RANGES_H_
467
template<>
468
struct fmt::formatter<hf::param>
469
{
470
    CONSTEXPR auto parse(format_parse_context& ctx) -> format_parse_context::iterator
7✔
471
    {
472
        // Parse the presentation format and store it in the formatter:
473
        auto it = ctx.begin(), end = ctx.end();
7✔
474
        if (it != end && *it != '}') { FMT_THROW(format_error("invalid format")); }
7✔
475

476
        // Check if reached the end of the range:
477
        // if (it != end && *it != '}') format_error("invalid format");
478

479
        // Return an iterator past the end of the parsed range:
480
        return it;
6✔
481
    }
482

483
    auto format(const hf::param& par, format_context& ctx) const -> format_context::iterator
6✔
484
    {
485
        char sep {0};
6✔
486

487
        switch (par.mode)
6✔
488
        {
489
            case hf::param::fit_mode::free:
4✔
490
                if (par.has_limits) { sep = ':'; }
4✔
491
                else { sep = ' '; }
3✔
492
                break;
493
            case hf::param::fit_mode::fixed:
2✔
494
                if (par.has_limits) { sep = 'F'; }
2✔
495
                else { sep = 'f'; }
1✔
496
                break;
497
            default:                                                // LCOV_EXCL_LINE
498
                throw std::runtime_error("Unknown hf::param mode"); // LCOV_EXCL_LINE
499
                break;                                              // LCOV_EXCL_LINE
500
        }
501

502
        if (par.mode == hf::param::fit_mode::free and par.has_limits == false)
6✔
503
        {
504
            fmt::format_to(ctx.out(), "{:g}", par.value);
3✔
505
        }
506
        else if (par.mode == hf::param::fit_mode::fixed and par.has_limits == false)
3✔
507
        {
508
            fmt::format_to(ctx.out(), "{:g} {:c}", par.value, sep);
1✔
509
        }
510
        else
511
        {
512
            fmt::format_to(ctx.out(), "{:g} {:c} {:g} {:g}", par.value, sep, par.min, par.max);
2✔
513

514
            return ctx.out();
2✔
515
        }
516

517
        return ctx.out();
4✔
518
    }
519
};
520
#endif // FMT_RANGES_H_
521

522
#endif // HELLOFITTY_HELLOFITTY_H
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc