12#ifndef ALICEO2_MATHUTILS_MATHBASE_H_
13#define ALICEO2_MATHUTILS_MATHBASE_H_
25#include "TLinearFitter.h"
30#include "HFitInterface.h"
31#include "TFitResultPtr.h"
32#include "TFitResult.h"
33#include "Fit/Fitter.h"
34#include "Fit/BinData.h"
35#include "Math/WrappedMultiTF1.h"
36#include <Math/SMatrix.h>
37#include <Math/SVector.h>
59TFitResultPtr
fit(
const size_t nBins,
const T* arr,
const T xMin,
const T xMax,
TF1&
func, std::string_view option =
"")
62 ROOT::Fit::FitOptionsMake(ROOT::Fit::EFitObjectType::kHistogram, option.data(), fitOption);
64 ROOT::Fit::DataRange
range(xMin, xMax);
65 ROOT::Fit::DataOptions opt;
66 ROOT::Fit::BinData fitdata(opt,
range);
67 fitdata.Initialize(nBins, 1);
70 std::shared_ptr<TFitResult> tfr(
new TFitResult());
73 ROOT::Fit::Fitter fitter(tfr);
76 const double binWidth = double(xMax - xMin) / double(nBins);
78 for (Int_t ibin = 0; ibin < nBins; ibin++) {
79 const double x = double(xMin) + double(ibin + 0.5) * binWidth;
80 const double y = double(arr[ibin]);
81 const double ey = std::sqrt(
y);
82 fitdata.Add(
x,
y, ey);
85 const int special =
func.GetNumber();
86 const int npar =
func.GetNpar();
87 bool linear =
func.IsLinear();
88 if (special == 299 + npar) {
92 if (fitOption.Bound || fitOption.Like || fitOption.Errors || fitOption.Gradient || fitOption.More || fitOption.User || fitOption.Integral || fitOption.Minuit) {
96 if (special != 0 && !fitOption.Bound && !linear) {
98 ROOT::Fit::InitGaus(fitdata, &
func);
99 }
else if (special == 400) {
100 ROOT::Fit::InitGaus(fitdata, &
func);
101 }
else if (special == 200) {
102 ROOT::Fit::InitExpo(fitdata, &
func);
106 if ((linear || fitOption.Gradient)) {
107 fitter.SetFunction(ROOT::Math::WrappedMultiTF1(
func));
109 fitter.SetFunction(
static_cast<const ROOT::Math::IParamMultiFunction&
>(ROOT::Math::WrappedMultiTF1(
func)));
113 const bool fitok = fitter.Fit(fitdata, fitOption.ExecPolicy);
115 LOGP(warning,
"bad fit");
118 return TFitResultPtr(tfr);
132bool medmadGaus(
size_t nBins,
const T* arr,
const T xMin,
const T xMax, std::array<double, 3>&
param)
134 int bStart = 0, bEnd = -1;
135 double sum = 0, binW = double(xMax - xMin) / nBins, medVal = xMin;
136 for (
int i = 0;
i < (
int)nBins;
i++) {
150 double cum = 0, thresh = 0.5 *
sum, frac0 = 0;
151 int bid = bStart, prevbid = bid;
156 frac0 = 1. + (thresh - cum) /
float(arr[bid]);
157 medVal = xMin + binW * (bid + frac0);
158 int bdiff = bid - prevbid - 1;
160 medVal -= bdiff * binW * 0.5;
170 double edgeL = frac0 + bid, edgeR = edgeL, dist = 0., wL = 0, wR = 0;
173 int bL = edgeL, bR = edgeR;
174 if (edgeL > bStart) {
181 wR = 1. + bR - edgeR;
186 auto wdt = std::min(wL, wR);
188 wdt = std::max(wL, wR);
194 dist += wdt * (cum - thresh) / amp * 0.5;
202 constexpr double SQRT2PI = 2.5066283;
204 param[2] = dist * binW * 1.4826;
231Double_t
fitGaus(
const size_t nBins,
const T* arr,
const T xMin,
const T xMax, std::vector<T>&
param)
233 static TLinearFitter fitter(3,
"pol2");
234 static TMatrixD mat(3, 3);
235 static Double_t kTol = mat.GetTol();
236 fitter.StoreData(kFALSE);
237 fitter.ClearPoints();
242 T rms = TMath::RMS(nBins, arr);
243 T
max = TMath::MaxElement(nBins, arr);
244 T binWidth = (xMax - xMin) / T(nBins);
259 for (
size_t i = 0;
i < nBins;
i++) {
281 for (
size_t ibin = 0; ibin < nBins; ibin++) {
284 Double_t xcenter = xMin + (ibin + 0.5) * binWidth;
285 Double_t error = 1. / TMath::Sqrt(entriesI);
287 fitter.AddPoint(&xcenter,
val, error);
290 A(npoints, 1) = xcenter;
291 A(npoints, 2) = xcenter * xcenter;
293 meanCOG += xcenter * entriesI;
294 rms2COG += xcenter * entriesI * xcenter;
315 fitter.GetParameters(par);
316 fitter.GetCovarianceMatrix(mat);
317 chi2 = fitter.GetChisquare() / Double_t(npoints);
319 if (TMath::Abs(par[1]) < kTol) {
322 if (TMath::Abs(par[2]) < kTol) {
325 param[1] = T(par[1] / (-2. * par[2]));
326 param[2] = T(1. / TMath::Sqrt(TMath::Abs(-2. * par[2])));
327 Double_t lnparam0 = par[0] + par[1] *
param[1] + par[2] *
param[1] *
param[1];
328 if (lnparam0 > 307) {
331 param[0] = TMath::Exp(lnparam0);
342 param[2] = TMath::Sqrt(TMath::Abs(meanCOG * meanCOG - rms2COG));
349 param[2] = binWidth / TMath::Sqrt(12);
359double fitGaus(
size_t nBins,
const T* arr,
const T xMin,
const T xMax, std::array<double, 3>&
param,
361 int minVal = 2,
bool applyMAD =
true)
363 double binW = double(xMax - xMin) / nBins,
s0 = 0,
s1 = 0, s2 = 0, s3 = 0, s4 = 0, sy0 = 0, sy1 = 0, sy2 = 0, syy = 0;
365 int bStart = 0, bEnd = (
int)nBins;
366 const float nSigmaMAD = 2.;
368 std::array<double, 3> madPar;
369 if (!
medmadGaus(nBins, arr, xMin, xMax, madPar)) {
372 bStart = std::max(bStart,
int((madPar[1] - nSigmaMAD * madPar[2] - xMin) / binW));
373 bEnd = std::min(bEnd, 1 +
int((madPar[1] + nSigmaMAD * madPar[2] - xMin) / binW));
375 float x = xMin + (bStart - 0.5) * binW;
376 for (
int i = bStart;
i < bEnd;
i++) {
380 throw std::runtime_error(
"Log-normal fit is possible only with non-negative data");
385 double y = std::log(
v), err2i =
v, err2iX = err2i, err2iY = err2i *
y;
393 sy1 += (err2iY *=
x);
394 sy2 += (err2iY *=
x);
400 auto recover = [&
param, binW, np,
s0,
s1, s2, sy0]() {
403 param[2] = np == 1 ? binW / std::sqrt(12) : std::sqrt(std::abs(
param[1] *
param[1] - s2 /
s0));
413 m33(1, 1) = m33(2, 0) = s2;
417 auto m33i = m33.Inverse(
res);
420 LOG(error) << np <<
" points collected, matrix inversion failed " << m33;
429 double chi2 =
v(0) *
v(0) *
s0 +
v(1) *
v(1) * s2 +
v(2) *
v(2) * s4 + syy +
430 2. * (
v(0) *
v(1) *
s1 +
v(0) *
v(2) * s2 +
v(1) *
v(2) * s3 -
v(0) * sy0 -
v(1) * sy1 -
v(2) * sy2);
432 param[2] = 1. / std::sqrt(-2. *
v(2));
434 if (std::isnan(
param[0]) || std::isnan(
param[1]) || std::isnan(
param[2])) {
441 j33(0, 0) =
param[0];
443 j33(0, 2) = j33(0, 1) *
param[1];
444 j33(1, 1) = -0.5 /
v(2);
445 j33(1, 2) = -
param[1] /
v(2);
446 j33(2, 2) =
param[2] * j33(1, 1);
447 *covMat = ROOT::Math::Similarity(j33, m33i);
449 return np > 3 ? chi2 / (np - 3.) : 0.;
477 double binWidth = (xMax - xMin) / (
double)nBins;
483 for (
size_t ibin = 0; ibin < nBins; ++ibin) {
484 double entriesI = (double)arr[ibin];
485 double xcenter = xMin + (ibin + 0.5) * binWidth;
487 mean += xcenter * entriesI;
488 rms2 += xcenter * entriesI * xcenter;
503 data.mStdDev = binWidth / std::sqrt(12.);
505 data.mStdDev = std::sqrt(std::abs(rms2 - mean * mean));
518template <
typename T,
typename R =
double>
524 auto n =
v.size() / 2;
525 nth_element(
v.begin(),
v.begin() +
n,
v.end());
527 if (!(
v.size() & 1)) {
528 auto max_it = max_element(
v.begin(),
v.begin() +
n);
529 med =
R{(*max_it + med) / 2.0};
542 LOG(error) <<
"Vector with values must have same size as vector for indices";
545 std::iota(
index.begin(),
index.end(),
static_cast<size_t>(0));
546 std::sort(
index.begin(),
index.end(), [&](
size_t a,
size_t b) { return values[a] < values[b]; });
571 int nPoints =
data.size();
572 std::vector<float>
w(2 * nPoints);
573 int nKeep = nPoints * fracKeep;
574 if (nKeep > nPoints) {
585 for (
int i = 0;
i < nPoints;
i++) {
590 w[
i + nPoints] = sum2;
592 double maxRMS = sum2 + 1e6;
594 int limI = nPoints - nKeep + 1;
595 for (
int i = 0;
i < limI;
i++) {
596 const int limJ =
i + nKeep - 1;
597 sum1 =
static_cast<double>(
w[limJ]) -
static_cast<double>(
i ?
w[
i - 1] : 0.);
598 sum2 =
static_cast<double>(
w[nPoints + limJ]) -
static_cast<double>(
i ?
w[nPoints +
i - 1] : 0.);
599 const double mean = sum1 / nKeep;
600 const double rms2 = sum2 / nKeep - mean * mean;
612 LOG(error) <<
"Rounding error: RMS = " <<
params[2] <<
" < 0";
629 LOG(error) <<
"Reordering not possible if number of elements in index container different from the data container";
632 std::vector<T> tmp(
data);
633 for (
size_t i = 0;
i <
data.size(); ++
i) {
648bool LTMUnbinnedSig(
const std::vector<T>&
data, std::vector<size_t>&
index, std::array<float, 7>&
params,
float fracKeepMin,
float sigTgt,
bool sorted =
false)
650 int nPoints =
data.size();
651 std::vector<double> wx(nPoints);
652 std::vector<double> wx2(nPoints);
664 for (
int i = 0;
i < nPoints;
i++) {
671 int keepMax = nPoints;
672 int keepMin = fracKeepMin * nPoints;
673 if (keepMin > keepMax) {
676 float sigTgt2 = sigTgt * sigTgt;
679 double maxRMS = wx2.back() + 1e6;
680 int keepN = (keepMax + keepMin) / 2;
685 int limI = nPoints - keepN + 1;
686 for (
int i = 0;
i < limI; ++
i) {
687 const int limJ =
i + keepN - 1;
688 sum1 = wx[limJ] - (
i ? wx[
i - 1] : 0.);
689 sum2 = wx2[limJ] - (
i ? wx2[
i - 1] : 0.);
690 const double mean = sum1 / keepN;
691 const double rms2 = sum2 / keepN - mean * mean;
701 if (maxRMS < sigTgt2) {
706 if (keepMin >= keepMax - 1) {
725 int i,
j, mid,
ir = np - 1, l = 0;
729 if (
ir == l + 1 && arr[
ir] < arr[l]) {
730 std::swap(arr[l], arr[
ir]);
734 int mid = (l +
ir) >> 1,
i = l + 1;
735 std::swap(arr[mid], arr[
i]);
736 if (arr[
i] > arr[
ir]) {
737 std::swap(arr[
i], arr[
ir]);
739 if (arr[l] > arr[
ir]) {
740 std::swap(arr[l], arr[
ir]);
742 if (arr[
i] > arr[l]) {
743 std::swap(arr[
i], arr[l]);
750 }
while (arr[
i] <
a);
753 }
while (arr[
j] >
a);
757 std::swap(arr[
i], arr[
j]);
783 for (
int i = np;
i--;) {
float sum(float s, o2::dcs::DataPointValue v)
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLboolean GLboolean GLboolean b
GLenum const GLfloat * params
GLenum GLsizei GLsizei GLint * values
GLfloat GLfloat GLfloat GLfloat v3
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s0
bool medmadGaus(size_t nBins, const T *arr, const T xMin, const T xMax, std::array< double, 3 > ¶m)
void Reorder(std::vector< T > &data, const std::vector< size_t > &index)
TFitResultPtr fit(const size_t nBins, const T *arr, const T xMin, const T xMax, TF1 &func, std::string_view option="")
bool LTMUnbinnedSig(const std::vector< T > &data, std::vector< size_t > &index, std::array< float, 7 > ¶ms, float fracKeepMin, float sigTgt, bool sorted=false)
void SortData(std::vector< T > const &values, std::vector< size_t > &index)
StatisticsData getStatisticsData(const T *arr, const size_t nBins, const double xMin, const double xMax)
T MAD2Sigma(int np, T *y)
bool LTMUnbinned(const std::vector< T > &data, std::vector< size_t > &index, std::array< float, 7 > ¶ms, float fracKeep)
T selKthMin(int k, int np, T *arr)
R median(std::vector< T > v)
Double_t fitGaus(const size_t nBins, const T *arr, const T xMin, const T xMax, std::vector< T > ¶m)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
double mCOG
calculated centre of gravity
double mStdDev
standard deviation
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)