Skip to content

Commit b2b3a24

Browse files
committed
Update interface to remove fitter global generic entry
Now generic entry can be set per fit-level, thus it is possible to use multiple generic entries for different fit classes within single fitter.
1 parent 3385167 commit b2b3a24

File tree

7 files changed

+131
-116
lines changed

7 files changed

+131
-116
lines changed

README.md

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ The fitter allows to set default function which will be used for histograms not
8686
# Features
8787
HelloFitty provides following structures:
8888
* `hf::fitter` -- the main fitting manager responsible to read/write data from files and fit histograms
89-
* `hf::fit_entry` -- a structure holding full info about functions and parameters for a given histogram
89+
* `hf::entry` -- a structure holding full info about functions and parameters for a given histogram
9090
* `hf::param` -- a single parameter info: values and boundaries
9191
* `hf::draw_opts` -- partial and grand function drawing options
9292

@@ -118,22 +118,28 @@ By default it will update the auxiliary file unless `update_reference` is set to
118118
119119
You can search whether given histogram is present in the fitter (after loading from file), either using the histogram object or histogram name:
120120
```c++
121-
auto find_fit(TH1* hist) const -> fit_entry*;
122-
auto find_fit(const char* name) const -> fit_entry*;
121+
auto find_fit(TH1* hist) const -> entry*;
122+
auto find_fit(const char* name) const -> entry*;
123123
```
124-
You can finally fit the histogram using the histogram object with the fit entry stored in the fitter, or histogram object and providing additional fit entry object:
124+
or request to create from generic entry if not found with:
125125
```c++
126-
auto fit(TH1* hist, const char* pars = "BQ", const char* gpars = "") -> bool;
127-
auto fit(fit_entry* hfp, TH1* hist, const char* pars = "BQ", const char* gpars = "") -> bool;
126+
auto find_or_make(TH1* hist, entry* generic = nullptr) const -> entry*;
127+
auto find_or_make(const char* name, entry* generic = nullptr) const -> entry*;
128+
```
129+
130+
You can finally fit the histogram (or graphs assuimg you rpivide name for nameless graph) using the histogram object with the fit entry stored in the fitter or using generic object fit entry:
131+
```c++
132+
auto fit(TH1* hist, const char* pars = "BQ", const char* gpars = "", entry* generic = nullptr) -> std::pair<bool, entry*>;
133+
auto fit(const char* name, TGraph* graph, const char* pars = "BQ", const char* gpars = "", entry* generic = nullptr) -> std::pair<bool, entry*>;
128134
```
129135
In addition to importing from file, you can add additional fit entries to the fitter:
130136
```c++
131-
auto insert_parameter(std::pair<std::string, fit_entry> hfp) -> void;
132-
auto insert_parameter(const std::string& name, std::unique_ptr<fit_entry> hfp) -> void;
137+
auto insert_parameter(std::pair<std::string, entry> hfp) -> void;
138+
auto insert_parameter(const std::string& name, std::unique_ptr<entry> hfp) -> void;
133139
```
134140
To set default fitting function for histograms not present in the histogram entries collection, use
135141
```c++
136-
auto set_generic_entry(fit_entry generic) -> void;
142+
auto set_generic_entry(entry generic) -> void;
137143
```
138144
Use of generic function will create an entry in the auxiliary file, e.g.:
139145
```c++
@@ -169,14 +175,14 @@ The decorator could have form of text string with a character `*`, which will be
169175
* decorator `*_v1` on `hist_name` will give `hist_name_v1`
170176
* but decorator `_v1` on `hist_name` will give `_v1`
171177

172-
## `hf::fit_entry`
178+
## `hf::entry`
173179
The fit entry can be created by parsing the input file or created by user and provided to the fitter:
174180
```c++
175-
explicit fit_entry(Double_t range_lower, Double_t range_upper);
181+
explicit entry(Double_t range_lower, Double_t range_upper);
176182
```
177183
The fit entry can be read from file (as shown above) or created from the code level:
178184
```c++
179-
hf::fit_entry hfp(0, 10);
185+
hf::entry hfp(0, 10);
180186
auto fid1 = hfp.add_function("gaus(0)"); // function id = 0
181187
auto fid2 = hfp.add_function("expo(3)"); // function id = 1
182188
hfp.set_param(0, 10, 0, 20, hf::param::fit_mode::free); // gaus(0) par [0]
@@ -197,7 +203,7 @@ auto drop() -> void;
197203
```
198204
You can use this before fit and fit result is of worse quality then one can restore original parameters.
199205
```c++
200-
auto hfp = hf::fit_entry(0, 10);
206+
auto hfp = hf::entry(0, 10);
201207
hfp.add_function(...);
202208
// and more...
203209

example/example1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ auto main() -> int
182182
fmt::print("{}", "\n");
183183

184184
hfp->backup();
185-
if (!ff.fit(hfp, hist, "BQ0")) hfp->restore();
185+
if (!ff.fit(hist, "BQ0", "", hfp).first) hfp->restore();
186186

187187
fmt::print("{}", "\nAfter fitting:\n");
188188
hfp->print("test_hist", true);

inc/details.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define HELLOFITTY_DETAILS_H
33

44
#include <TF1.h>
5+
#include <TFitResult.h>
56

67
#include <fmt/color.h>
78
#include <fmt/core.h>
@@ -177,7 +178,6 @@ struct fitter_impl
177178
std::string par_ref;
178179
std::string par_aux;
179180

180-
entry generic_parameters;
181181
std::map<std::string, entry> hfpmap;
182182

183183
std::string name_decorator{"*"};
@@ -208,6 +208,12 @@ struct fitter_impl
208208

209209
auto fit_res = dataobj->Fit(tfSum, pars, gpars, hfp->get_fit_range_min(), hfp->get_fit_range_max());
210210

211+
auto fit_status = fit_res.Get() ? fit_res->Status() : int(fit_res);
212+
213+
if (fit_status != 0) {
214+
return false;
215+
}
216+
211217
TF1* new_sig_func = dynamic_cast<TF1*>(dataobj->GetListOfFunctions()->At(0));
212218

213219
// TVirtualFitter * fitter = TVirtualFitter::GetFitter();

include/hellofitty.hpp

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ class length_error : public std::length_error
6464
using std::length_error::length_error;
6565
};
6666

67+
// Incorrect fitting range
68+
class range_error : public std::runtime_error
69+
{
70+
public:
71+
using std::runtime_error::runtime_error;
72+
};
73+
6774
namespace detail
6875
{
6976
struct draw_opts_impl;
@@ -307,15 +314,6 @@ class HELLOFITTY_EXPORT fitter final
307314

308315
auto clear() -> void;
309316

310-
/// For histograms which have no record in the entries collection, you can set a generic
311-
/// function and aparameters to be fit. It will not be used for disabled histograms.
312-
/// Pass an empty object to clear the generic entry.
313-
/// @param generic a generic histogram function object
314-
auto set_generic_entry(entry generic) -> void;
315-
/// Check if the generic entry is set.
316-
/// @return true if the generic entry exists.
317-
auto has_generic_entry() -> bool;
318-
319317
/// Load parameters from the reference input.
320318
/// @param input_file the input parameters
321319
/// @return the file was properly imported
@@ -334,42 +332,31 @@ class HELLOFITTY_EXPORT fitter final
334332
auto find_fit(TH1* hist) const -> entry*;
335333
auto find_fit(const char* name) const -> entry*;
336334

337-
auto find_or_make(TH1* hist) -> entry*;
338-
auto find_or_make(const char* name) -> entry*;
335+
/// Find hfp by histogram name, or create from generic if not null.
336+
/// @param hist object to find hfp for
337+
/// @param generic object to use as a reference if name not found
338+
/// @return hfp found for name, or created from geenric if not nullptr, or nullptr
339+
auto find_or_make(TH1* hist, entry* generic = nullptr) -> entry*;
340+
auto find_or_make(const char* name, entry* generic = nullptr) -> entry*;
339341

340342
/// Fit the histogram using entry either located in the collection or using generic entry if provided.
341343
/// @param hist histogram to be fitted
342344
/// @param pars histogram fitting pars
343345
/// @param gpars histogram fit drawing pars
346+
/// @param generic histogram entry to be used if non present yet
344347
/// @return pair of bool (true if fit successful) and used entry
345-
auto fit(TH1* hist, const char* pars = "BQ", const char* gpars = "") -> std::pair<bool, entry*>;
346-
/// Fit the histogram using provided entry. The fit entry is not automatically stored in the collection and must
347-
/// be add using @see hf::fitter::insert_parameter.
348-
/// @param hfp histogram entry to be used
349-
/// @param hist histogram to be fitted
350-
/// @param pars histogram fitting pars
351-
/// @param gpars histogram fit drawing pars
352-
/// @return true if fit was successful
353-
auto fit(entry* hfp, TH1* hist, const char* pars = "BQ", const char* gpars = "") -> bool;
348+
auto fit(TH1* hist, const char* pars = "BQ", const char* gpars = "", entry* generic = nullptr)
349+
-> std::pair<bool, entry*>;
354350

355351
/// Fit the graph using entry either located in the collection or using generic entry if provided.
356352
/// @param name entry name (graphs are not named object)
357353
/// @param graph graph to be fitted
358354
/// @param pars graph fitting pars
359355
/// @param gpars graph fit drawing pars
356+
/// @param generic histogram entry to be used if non present yet
360357
/// @return pair of bool (true if fit successful) and used entry
361-
auto fit(const char* name, TGraph* graph, const char* pars = "BQ", const char* gpars = "")
358+
auto fit(const char* name, TGraph* graph, const char* pars = "BQ", const char* gpars = "", entry* generic = nullptr)
362359
-> std::pair<bool, entry*>;
363-
/// Fit the graph using provided entry. The fit entry is not automatically stored in the collection and must
364-
/// be add using @see hf::fitter::insert_parameter.
365-
/// @param hfp graph entry to be used
366-
/// @param name entry name (graphs are not named object)
367-
/// @param graph graph to be fitted
368-
/// @param hist graph to be fitted
369-
/// @param pars graph fitting pars
370-
/// @param gpars graph fit drawing pars
371-
/// @return true if fit was successful
372-
auto fit(entry* hfp, const char* name, TGraph* graph, const char* pars = "BQ", const char* gpars = "") -> bool;
373360

374361
auto print() const -> void;
375362

source/entry.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ entry::entry() : m_d{make_unique<detail::entry_impl>()} {}
5151

5252
entry::entry(Double_t range_lower, Double_t range_upper) : m_d{make_unique<detail::entry_impl>()}
5353
{
54+
if (range_lower == range_upper) throw hf::range_error("fitting range cannot be empty");
55+
5456
m_d->range_min = range_lower;
5557
m_d->range_max = range_upper;
5658
}
@@ -149,6 +151,8 @@ auto entry::param(const char* name) -> hf::param&
149151

150152
auto entry::set_fit_range(Double_t range_lower, Double_t range_upper) -> void
151153
{
154+
if (range_lower == range_upper) throw hf::range_error("fitting range cannot be empty");
155+
152156
m_d->range_min = range_lower;
153157
m_d->range_max = range_upper;
154158

source/fitter.cpp

Lines changed: 22 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -238,94 +238,62 @@ auto fitter::find_fit(const char* name) const -> entry*
238238
return nullptr;
239239
}
240240

241-
auto fitter::find_or_make(TH1* hist) -> entry* { return find_or_make(hist->GetName()); }
241+
auto fitter::find_or_make(TH1* hist, entry* generic) -> entry* { return find_or_make(hist->GetName(), generic); }
242242

243-
auto fitter::find_or_make(const char* name) -> entry*
243+
auto fitter::find_or_make(const char* name, entry* generic) -> entry*
244244
{
245245
entry* hfp = find_fit(name);
246-
if (!hfp)
246+
if (!hfp and generic)
247247
{
248-
// fmt::print("HFP for histogram {:s} not found, trying from defaults.\n", name);
248+
if (detail::fitter_impl::verbose_flag)
249+
fmt::print("HFP for histogram {:s} not found, trying from generic.\n", name);
249250

250-
if (!m_d->generic_parameters.get_functions_count())
251-
throw std::logic_error("Generic Fit Entry has no functions.");
251+
if (!generic->get_functions_count()) throw std::logic_error("Generic Fit Entry has no functions.");
252252

253-
hfp = insert_parameter(std::string(name), m_d->generic_parameters);
254-
if (!m_d->generic_parameters.get_functions_count()) throw std::logic_error("Could not insert new parameter.");
253+
hfp = insert_parameter(std::string(name), *generic);
254+
if (!hfp) throw std::logic_error("Could not insert new parameter.");
255+
256+
if (detail::fitter_impl::verbose_flag) fmt::print("HFP for histogram {:s} created from generic.\n", name);
255257
}
256258

257259
return hfp;
258260
}
259261

260-
auto fitter::fit(TH1* hist, const char* pars, const char* gpars) -> std::pair<bool, entry*>
262+
auto fitter::fit(TH1* hist, const char* pars, const char* gpars, entry* generic) -> std::pair<bool, entry*>
261263
{
262-
entry* hfp = find_fit(hist->GetName());
263-
if (!hfp)
264-
{
265-
fmt::print("HFP for histogram {:s} not found, trying from defaults.\n", hist->GetName());
266-
267-
if (!m_d->generic_parameters.get_functions_count())
268-
throw std::logic_error("Generic Fit Entry has no functions.");
269-
270-
hfp = insert_parameter(std::string(hist->GetName()), m_d->generic_parameters);
271-
if (!m_d->generic_parameters.get_functions_count()) throw std::logic_error("Could not insert new parameter.");
272-
}
273-
264+
entry* hfp = find_or_make(hist->GetName(), generic);
274265
if (!hfp) return {false, hfp};
275266

276267
hfp->backup();
277-
bool status = fit(hfp, hist, pars, gpars);
278268

279-
if (!status) hfp->restore();
280-
281-
return {status, hfp};
282-
}
283-
284-
auto fitter::fit(entry* hfp, TH1* hist, const char* pars, const char* gpars) -> bool
285-
{
286269
Int_t bin_l = hist->FindBin(hfp->get_fit_range_min());
287270
Int_t bin_u = hist->FindBin(hfp->get_fit_range_max());
288271

289272
if (hfp->get_flag_rebin() != 0) { hist->Rebin(hfp->get_flag_rebin()); }
290273

291-
if (hist->Integral(bin_l, bin_u) == 0) return false;
274+
if (bin_u - bin_l == 0) return {false, hfp};
275+
// if (hist->Integral(bin_l, bin_u) == 0) return {false, hfp};
276+
277+
bool status = m_d->generic_fit(hfp, hfp->m_d.get(), hist->GetName(), hist, pars, gpars);
278+
if (!status) hfp->restore();
292279

293-
return m_d->generic_fit(hfp, hfp->m_d.get(), hist->GetName(), hist, pars, gpars);
280+
return {status, hfp};
294281
}
295282

296-
auto fitter::fit(const char* name, TGraph* graph, const char* pars, const char* gpars) -> std::pair<bool, entry*>
283+
auto fitter::fit(const char* name, TGraph* graph, const char* pars, const char* gpars, entry* generic)
284+
-> std::pair<bool, entry*>
297285
{
298-
entry* hfp = find_fit(name);
299-
if (!hfp)
300-
{
301-
fmt::print("HFP for graphs {:s} not found, trying from defaults.\n", name);
302-
303-
if (!m_d->generic_parameters.get_functions_count())
304-
throw std::logic_error("Generic Fit Entry has no functions.");
305-
306-
hfp = insert_parameter(std::string(name), m_d->generic_parameters);
307-
if (!m_d->generic_parameters.get_functions_count()) throw std::logic_error("Could not insert new parameter.");
308-
}
309-
286+
entry* hfp = find_or_make(name, generic);
310287
if (!hfp) return {false, hfp};
311288

312289
hfp->backup();
313-
bool status = fit(hfp, name, graph, pars, gpars);
314290

291+
bool status = m_d->generic_fit(hfp, hfp->m_d.get(), name, graph, pars, gpars);
315292
if (!status) hfp->restore();
316293

317294
return {status, hfp};
318295
}
319296

320-
auto fitter::fit(entry* hfp, const char* name, TGraph* graph, const char* pars, const char* gpars) -> bool
321-
{
322-
return m_d->generic_fit(hfp, hfp->m_d.get(), name, graph, pars, gpars);
323-
}
324-
325-
auto fitter::set_generic_entry(entry generic) -> void { m_d->generic_parameters = generic; }
326-
327-
auto fitter::has_generic_entry() -> bool { return m_d->generic_parameters.is_valid(); }
328-
329297
auto fitter::set_name_decorator(std::string decorator) -> void { m_d->name_decorator = std::move(decorator); }
330298
auto fitter::clear_name_decorator() -> void { m_d->name_decorator = "*"; }
331299

0 commit comments

Comments
 (0)