28#include <unordered_set>
31#include <Math/Functor.h>
32#include <Fit/Fitter.h>
42#include <Math/Minimizer.h>
54 return (active_bit < 32) ? (1u << active_bit) : 0;
62inline uint32_t
encode_bits(
const std::vector<uint8_t> &active_bits)
65 for (uint8_t bit : active_bits)
81 while ((mask & 1u) == 0)
96 std::vector<uint8_t> result;
102 mask &= ~(1u << bit);
119inline std::uniform_real_distribution<>
_rnd_(0.0, 1.0);
171inline uint32_t
get_global_index(
int device,
int chip,
int channel,
int tdc) {
return (device - 192) * 32 * 8 * 4 + chip * 32 * 4 + channel * 4 + tdc; }
193inline circle_fit_results fit_circle(std::vector<std::array<float, 2>> points, std::array<float, 3> initial_values,
bool fix_XY =
true, std::vector<int> exclude_points = {{}})
198 auto chi2_function = [&](
const double *parameters)
201 for (
int iPnt = 0; iPnt < points.size(); iPnt++)
203 if (std::find(exclude_points.begin(), exclude_points.end(), iPnt) != exclude_points.end())
205 double delta_x = points[iPnt][0] - parameters[0];
206 double delta_y = points[iPnt][1] - parameters[1];
207 double delta_r = parameters[2] - std::sqrt(delta_x * delta_x + delta_y * delta_y);
208 chi2 += delta_r * delta_r;
214 ROOT::Math::Functor fit_function(chi2_function, 3);
215 ROOT::Fit::Fitter fitter;
218 double internal_initial_values[3] = {initial_values[0], initial_values[1], initial_values[2]};
219 fitter.SetFCN(fit_function, internal_initial_values);
220 fitter.Config().ParSettings(0).SetName(
"x0");
221 fitter.Config().ParSettings(1).SetName(
"y0");
222 fitter.Config().ParSettings(2).SetName(
"R");
223 fitter.Config().ParSettings(2).SetLowerLimit(0);
226 fitter.Config().ParSettings(0).Fix();
227 fitter.Config().ParSettings(1).Fix();
231 if (!fitter.FitFCN())
236 const ROOT::Fit::FitResult &fit_result = fitter.Result();
239 for (
auto current_parameter : fit_result.Parameters())
242 result[iTer][0] = current_parameter;
243 result[iTer][1] = fit_result.Errors()[iTer];
247 double *test =
new double[3];
248 test[0] = result[0][0];
249 test[1] = result[1][0];
250 test[2] = result[2][0];
251 auto myChi2 = chi2_function(test);
272inline double logistic(
double variable,
double amplitude,
double center_1,
double sigma_1,
double center_2,
double sigma_2)
276 (1. / (1. + exp(-(variable - center_1) / sigma_1)) - 1. / (1. + exp(-(variable - center_2) / sigma_2)));
287inline double clip_phi(
double phi,
double low_bound,
double high_bound)
290 while (phi < low_bound || phi >= high_bound)
311 double result = baseline_sigma;
312 for (
auto current_logistic : input_values)
314 result +=
logistic(phi, current_logistic[0], current_logistic[1] - 0.5 * current_logistic[2], current_logistic[3], current_logistic[1] + 0.5 * current_logistic[2], current_logistic[3]);
328inline double ring_fit_function(std::array<double, 2> input_values, std::array<double, 6> parameters, std::vector<std::array<double, 4>> logistic_input_values = {})
331 auto current_radius = input_values[0];
332 auto current_phi = input_values[1];
335 auto ring_x_center = parameters[0];
336 auto ring_y_center = parameters[1];
337 auto ring_radius = parameters[2];
338 auto ring_sigma = parameters[3];
339 auto ring_photons = parameters[4];
340 auto bkg_level = parameters[5];
343 auto signal = ring_photons * (1. / (2 * TMath::Pi() * ring_radius)) * TMath::Gaus(current_radius, ring_radius,
ring_fit_function_sigma_function(current_phi, ring_sigma, logistic_input_values),
true);
345 auto background = bkg_level;
348 return signal + background;
358inline double ring_fit_function_xy(std::array<double, 2> input_values, std::array<double, 6> parameters, std::vector<std::array<double, 4>> logistic_input_values = {})
361 auto x_center = input_values[0];
362 auto y_center = input_values[1];
365 auto ring_x_center = parameters[0];
366 auto ring_y_center = parameters[1];
369 auto current_radius = hypot(x_center - ring_x_center, y_center - ring_y_center);
370 auto current_phi = atan2(y_center - ring_y_center, x_center - ring_x_center);
384inline double ring_fit_function_xy(std::array<double, 2> input_values,
const double *parameters,
int how_many_logistics = 0)
387 std::array<double, 6> array_parameters = {
388 static_cast<double>(parameters[0]),
389 static_cast<double>(parameters[1]),
390 static_cast<double>(parameters[2]),
391 static_cast<double>(parameters[3]),
392 static_cast<double>(parameters[4]),
393 static_cast<double>(parameters[5])};
395 std::vector<std::array<double, 4>> logistic_input_values;
396 for (
auto i_logistic = 0; i_logistic < how_many_logistics; i_logistic++)
397 logistic_input_values.emplace_back(
398 std::array<double, 4>{parameters[5 + i_logistic * 4 + 0],
399 parameters[5 + i_logistic * 4 + 1],
400 parameters[5 + i_logistic * 4 + 2],
401 parameters[5 + i_logistic * 4 + 3]});
427 auto chi2_function = [&](
const double *parameters)
430 for (
auto x_bin = 1; x_bin <= target_histogram->GetNbinsX(); x_bin++)
431 for (
auto y_bin = 1; y_bin <= target_histogram->GetNbinsY(); y_bin++)
434 double x_center = target_histogram->GetXaxis()->GetBinCenter(x_bin);
435 double y_center = target_histogram->GetYaxis()->GetBinCenter(y_bin);
436 double x_width = target_histogram->GetXaxis()->GetBinWidth(x_bin);
437 double y_width = target_histogram->GetYaxis()->GetBinWidth(y_bin);
438 double z_value = target_histogram->GetBinContent(x_bin, y_bin);
439 double z_error = target_histogram->GetBinError(x_bin, y_bin);
446 double current_function_value = x_width * y_width *
ring_fit_function_xy({x_center, y_center}, parameters);
447 chi2 += (z_value - current_function_value) * (z_value - current_function_value) / (z_error * z_error);
453 ROOT::Math::Functor fit_function(chi2_function, 6);
454 ROOT::Fit::Fitter fitter;
457 double internal_initial_values[6] = {initial_values[0], initial_values[1], initial_values[2], initial_values[3], initial_values[4], initial_values[5]};
458 fitter.SetFCN(fit_function, internal_initial_values);
459 fitter.Config().ParSettings(0).SetName(
"centerX");
460 fitter.Config().ParSettings(0).SetLimits(-5.0, 5.0);
461 fitter.Config().ParSettings(1).SetName(
"centerY");
462 fitter.Config().ParSettings(1).SetLimits(-5.0, 5.0);
463 fitter.Config().ParSettings(2).SetName(
"ring__R");
464 fitter.Config().ParSettings(2).SetLowerLimit(0);
465 fitter.Config().ParSettings(3).SetName(
"sigma_R");
466 fitter.Config().ParSettings(3).SetLimits(0., 7.5);
467 fitter.Config().ParSettings(4).SetName(
"N_gamma");
468 fitter.Config().ParSettings(4).SetLimits(0., 50.);
469 fitter.Config().ParSettings(5).SetName(
"bkg");
470 fitter.Config().ParSettings(5).SetLowerLimit(0.);
473 fitter.Config().ParSettings(0).Fix();
474 fitter.Config().ParSettings(1).Fix();
478 if (!fitter.FitFCN())
480 const ROOT::Fit::FitResult &fit_result = fitter.Result();
481 Error(
"fit_circle",
"Fit failed");
482 fit_result.Print(std::cout);
483 return {{{-2., 0.}, {-2., 0.}, {-2., 0.}, {0., 0.}, {0., 0.}, {0., 0.}}};
485 const ROOT::Fit::FitResult &fit_result = fitter.Result();
486 fit_result.Print(std::cout);
489 for (
auto current_parameter : fit_result.Parameters())
492 mist::logger::debug(
"par " + fit_result.GetParameterName(iTer) +
" : " + std::to_string(current_parameter) +
" +- " + std::to_string(fit_result.Errors()[iTer]));
495 result[iTer][0] = current_parameter;
496 result[iTer][1] = fit_result.Errors()[iTer];
510inline std::vector<TGraph *>
plot_ring_integral(
ring_fit_results fit_results, std::vector<float> sigma_values, std::vector<std::array<double, 4>> logistic_input_values = {},
int n_points = 500)
512 std::vector<TGraph *> result;
513 for (
auto current_sigma_value : sigma_values)
515 result.push_back(
new TGraph());
516 auto ¤t_graph = result.back();
517 for (
auto i_point = 0; i_point <= n_points; i_point++)
519 auto current_phi = -TMath::Pi() + 2 * TMath::Pi() * (1. * i_point) / n_points;
520 auto current_x = fit_results[0][0] + (fit_results[2][0] + current_sigma_value *
ring_fit_function_sigma_function(current_phi, fit_results[3][0], logistic_input_values)) * cos(current_phi);
521 auto current_y = fit_results[1][0] + (fit_results[2][0] + current_sigma_value *
ring_fit_function_sigma_function(current_phi, fit_results[3][0], logistic_input_values)) * sin(current_phi);
522 current_graph->SetPoint(i_point, current_x, current_y);
549 std::function<
void(std::string, std::string,
int,
bool,
int, std::string, std::string, std::string)> builder,
550 const std::string &data_repository,
551 const std::string &run_name,
553 bool force_rebuild =
false)
558 TFile *input_file = TFile::Open(filename.c_str(),
"READ");
559 if (input_file && !input_file->IsZombie())
563 std::cout <<
"[WARNING] File '" << filename <<
"' missing, corrupted or rebuild forced, creating it\n";
566 builder(data_repository, run_name, max_spill, force_rebuild, -1,
"",
"",
"");
568 TFile *input_file = TFile::Open(filename.c_str(),
"READ");
569 if (!input_file || input_file->IsZombie())
571 std::cerr <<
"[ERROR] Could not open file '" << filename <<
"' even after rebuilding\n";
590void inline draw_circle(std::array<float, 3> parameters,
int line_colour = kBlack,
int line_style = kSolid,
int line_width = 1)
592 auto result =
new TEllipse(parameters[0], parameters[1], parameters[2]);
593 result->SetFillStyle(0);
594 result->SetLineColor(line_colour);
595 result->SetLineStyle(line_style);
596 result->SetLineWidth(line_width);
597 result->DrawEllipse(parameters[0], parameters[1], parameters[2], 0, 0, 360, 0,
"same");
uint8_t count_trailing_zeros(uint32_t mask)
Count trailing zeros (portable C++17)
Definition utility.h:76
int get_pixel_from_global_tdc_index(int global_tdc_index)
Decode the pixel address from a global TDC index.
Definition utility.h:149
std::vector< uint8_t > decode_bits(uint32_t mask)
Decode a 32-bit mask into the indices of set bits.
Definition utility.h:94
double logistic(double variable, double amplitude, double center_1, double sigma_1, double center_2, double sigma_2)
Difference-of-logistic function used to model azimuthal acceptance gaps.
Definition utility.h:272
int get_column_from_global_tdc_index(int global_tdc_index)
Decode the column address from a global TDC index.
Definition utility.h:146
void draw_circle(std::array< float, 3 > parameters, int line_colour=kBlack, int line_style=kSolid, int line_width=1)
Draw a circle on the current ROOT canvas pad.
Definition utility.h:590
std::random_device _global_rd_
Seeding device for _global_gen_.
Definition utility.h:113
int get_device_index_from_global_tdc_index(int global_tdc_index)
Compute the per-device flat index from a global TDC index.
Definition utility.h:155
int get_device_from_global_tdc_index(int global_tdc_index)
Decode the readout device ID (192+) from a global TDC index.
Definition utility.h:134
int get_pdu_from_global_tdc_index(int global_tdc_index)
Decode the PDU number (1-based) from a global TDC index.
Definition utility.h:158
std::array< std::array< double, 2 >, 6 > ring_fit_results
Result type for ring fits: { {x0,σ}, {y0,σ}, {R,σ}, {sigma_R,σ}, {N,σ}, {bkg,σ} }.
Definition utility.h:408
double ring_fit_function(std::array< double, 2 > input_values, std::array< double, 6 > parameters, std::vector< std::array< double, 4 > > logistic_input_values={})
Evaluate the ring signal + flat background model in (R, φ) coordinates.
Definition utility.h:328
TFile * open_or_build_rootfile(const std::string &filename, std::function< void(std::string, std::string, int, bool, int, std::string, std::string, std::string)> builder, const std::string &data_repository, const std::string &run_name, int max_spill, bool force_rebuild=false)
Open a ROOT file for reading, rebuilding it if missing or corrupted.
Definition utility.h:548
ring_fit_results fit_ring_integral(TH2 *target_histogram, std::array< double, 6 > initial_values, bool fix_XY=true)
Fit a 2-D ring model to a histogram using chi-squared minimisation.
Definition utility.h:422
uint32_t encode_bits(const std::vector< uint8_t > &active_bits)
Encode multiple bits into a 32-bit mask.
Definition utility.h:62
int get_eo_channel_index_from_global_tdc_index(int global_tdc_index)
Decode the even/odd channel index from a global TDC index.
Definition utility.h:143
double ring_fit_function_sigma_function(double phi, double baseline_sigma, std::vector< std::array< double, 4 > > input_values={})
Azimuthally-varying ring-width model.
Definition utility.h:309
uint32_t get_global_index(int device, int chip, int channel, int tdc)
Pack device, chip, channel, and TDC sub-index into a global TDC index.
Definition utility.h:171
uint32_t encode_bit(uint8_t active_bit)
Encode a single bit into a 32-bit mask.
Definition utility.h:52
int get_calib_index_from_global_tdc_index(int global_tdc_index)
Compute the calibration look-up index from a global TDC index.
Definition utility.h:152
int get_fifo_from_global_tdc_index(int global_tdc_index)
Decode the FIFO number from a global TDC index.
Definition utility.h:137
int get_chip_from_global_tdc_index(int global_tdc_index)
Decode the chip number from a global TDC index.
Definition utility.h:140
std::vector< TGraph * > plot_ring_integral(ring_fit_results fit_results, std::vector< float > sigma_values, std::vector< std::array< double, 4 > > logistic_input_values={}, int n_points=500)
Generate ring-contour TGraphs at specified sigma levels from a fit result.
Definition utility.h:510
double clip_phi(double phi, double low_bound, double high_bound)
Clip an angle to a given range (placeholder — currently returns -1).
Definition utility.h:287
int get_hit_tdc_from_global_tdc_index(int global_tdc_index)
Extract the TDC sub-index (0–3) from a global TDC index.
Definition utility.h:131
int get_matrix_from_global_tdc_index(int global_tdc_index)
Decode the matrix number (1-based) from a global TDC index.
Definition utility.h:161
std::uniform_real_distribution _rnd_(0.0, 1.0)
Uniform float distribution in [0, 1).
std::array< std::array< float, 2 >, 3 > circle_fit_results
Result type: { {x0,σx0}, {y0,σy0}, {R,σR} }.
Definition utility.h:180
std::mt19937 _global_gen_(_global_rd_())
Mersenne-Twister 19937 engine seeded from _global_rd_.
circle_fit_results fit_circle(std::vector< std::array< float, 2 > > points, std::array< float, 3 > initial_values, bool fix_XY=true, std::vector< int > exclude_points={{}})
Fit a circle to a set of 2-D points.
Definition utility.h:193
double ring_fit_function_xy(std::array< double, 2 > input_values, std::array< double, 6 > parameters, std::vector< std::array< double, 4 > > logistic_input_values={})
Evaluate the ring model in Cartesian (x, y) coordinates.
Definition utility.h:358