2022-01-24 11:26:56 +01:00

479 lines
18 KiB
C++

// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef ENERGYCALIBRATION_H
#define ENERGYCALIBRATION_H
#ifdef __CINT__
#define MYROOT
#endif
#ifdef G__ROOT
#define MYROOT
#endif
#ifdef __MAKECINT__
#define MYROOT
#endif
#ifdef ROOT_VERSION
#define MYROOT
#endif
#define MYROOT
#ifdef MYROOT
#include <TF1.h>
#include <TROOT.h>
class TH1F;
class TH2F;
class TGraphErrors;
#endif
using namespace std;
const double conven = 1000. / 3.6; /**< electrons/keV */
const double el = 1.67E-4; /**< electron charge in fC */
/**
\mainpage Common Root library for SLS detectors data analysis
*
* \section intro_sec Introduction
We know very well s-curves etc. but at the end everybody uses different
functions ;-).
* \subsection mot_sec Motivation
It would be greate to use everybody the same functions...
*/
/**
*
*
@libdoc The energiCalibration class contains all the necessary functions for
s-curve fitting and linear calibration of the threshold.
*
* @short Energy calibration functions
* @author Anna Bergamaschi
* @version 0.1alpha
*/
/**
class containing all the possible energy calibration functions (scurves with
and without charge sharing, gaussian spectrum with and without charge sharing,
possibility of chosing the sign of the X-axis)
*/
class energyCalibrationFunctions {
public:
energyCalibrationFunctions(int s = -1) { setScanSign(s); };
/** sets scan sign
\param s can be 1 (energy and x-axis have the same direction) or -1
(energy and x-axis have opposite directions) otherwise gets \returns
current scan sign can be 1 (energy and x-axis have the same direction) or
-1 (energy and x-axis have opposite directions)
*/
int setScanSign(int s = 0) {
if (s == 1 || s == -1)
sign = s;
return sign;
};
;
#ifdef MYROOT
/**
Gaussian Function with charge sharing pedestal
par[0] is the absolute height of the background pedestal
par[1] is the slope of the background pedestal
*/
Double_t pedestal(Double_t *x, Double_t *par);
/**
Gaussian Function with charge sharing pedestal
par[0] is the absolute height of the background pedestal
par[1] is the slope of the background pedestal
par[2] is the gaussian peak position
par[3] is the RMS of the gaussian (and of the pedestal)
par[4] is the height of the function
par[5] is the fractional height of the charge sharing pedestal (scales
with par[3])
*/
Double_t gaussChargeSharing(Double_t *x, Double_t *par);
Double_t gaussChargeSharingKb(Double_t *x, Double_t *par);
Double_t gaussChargeSharingKaDoublet(Double_t *x, Double_t *par);
/**
Gaussian Function with charge sharing pedestal
par[0] is the absolute height of the background pedestal
par[1] is the slope of the background pedestal
par[2] is the gaussian peak position
par[3] is the RMS of the gaussian (and of the pedestal)
par[4] is the height of the function
par[5] is the fractional height of the charge sharing pedestal (scales
with par[3])
*/
Double_t gaussChargeSharingPixel(Double_t *x, Double_t *par);
/**
Basic erf function
par[0] is the inflection point
par[1] is the RMS
par[2] is the amplitude
*/
Double_t erfFunction(Double_t *x, Double_t *par);
Double_t erfBox(Double_t *z, Double_t *par);
/** Erf function with charge sharing slope
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point
par[3] is the RMS
par[4] is the amplitude
par[5] is the angual coefficient of the charge sharing slope (scales
with par[3])
*/
Double_t erfFunctionChargeSharing(Double_t *x, Double_t *par);
/** Double Erf function with charge sharing slope
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point of the first energy
par[3] is the RMS of the first energy
par[4] is the amplitude of the first energy
par[5] is the angual coefficient of the charge sharing slope of the
first energy (scales with par[3]) par[6] is the inflection point of the
second energy par[7] is the RMS of the second energy par[8] is the
amplitude of the second energy par[9] is the angual coefficient of the
charge sharing slope of the second energy (scales with par[8])
*/
Double_t erfFuncFluo(Double_t *x, Double_t *par);
/**
static function Gaussian with charge sharing pedestal with the correct
scan sign par[0] is the absolute height of the background pedestal par[1]
is the slope of the pedestal par[2] is the gaussian peak position par[3]
is the RMS of the gaussian (and of the pedestal) par[4] is the height of
the function par[5] is the fractional height of the charge sharing
pedestal (scales with par[4]
*/
Double_t spectrum(Double_t *x, Double_t *par);
Double_t spectrumkb(Double_t *x, Double_t *par);
Double_t spectrumkadoublet(Double_t *x, Double_t *par);
/**
static function Gaussian with charge sharing pedestal with the correct
scan sign par[0] is the absolute height of the background pedestal par[1]
is the slope of the pedestal par[2] is the gaussian peak position par[3]
is the RMS of the gaussian (and of the pedestal) par[4] is the height of
the function par[5] is the fractional height of the charge sharing
pedestal (scales with par[4]
*/
Double_t spectrumPixel(Double_t *x, Double_t *par);
/** Erf function with charge sharing slope with the correct scan sign
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point
par[3] is the RMS
par[4] is the amplitude
par[5] is the angual coefficient of the charge sharing slope (scales
with par[3])
*/
Double_t scurve(Double_t *x, Double_t *par);
/** Double Erf function with charge sharing slope
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point of the first energy
par[3] is the RMS of the first energy
par[4] is the amplitude of the first energy
par[5] is the angual coefficient of the charge sharing slope of the first
energy (scales with par[3]) par[6] is the inflection point of the second
energy par[7] is the RMS of the second energy par[8] is the amplitude of
the second energy par[9] is the angual coefficient of the charge sharing
slope of the second energy (scales with par[8])
*/
Double_t scurveFluo(Double_t *x, Double_t *par);
#endif
/** Calculates the median of an array of n elements */
static double median(double *x, int n);
/** Calculates the median of an array of n elements (swaps the arrays!)*/
static int quick_select(int arr[], int n);
/** Calculates the median of an array of n elements (swaps the arrays!)*/
static int kth_smallest(int *a, int n, int k);
private:
int sign;
};
/**
class alowing the energy calibration of photon counting and anlogue detectors
*/
class energyCalibration {
public:
/**
default constructor - creates the function with which the s-curves
will be fitted
*/
energyCalibration();
/**
default destructor - deletes the function with which the s-curves will
be fitted
*/
~energyCalibration();
/** sets plot flag
\param p plot flag (-1 gets, 0 unsets, >0 plot)
\returns current plot flag
*/
int setPlotFlag(int p = -1) {
if (p >= 0)
plot_flag = p;
return plot_flag;
};
/** sets scan sign
\param s can be 1 (energy and x-axis have the same direction) or -1
(energy and x-axis have opposite directions) otherwise gets \returns
current scan sign can be 1 (energy and x-axis have the same direction) or
-1 (energy and x-axis have opposite directions)
*/
int setScanSign(int s = 0) { return funcs->setScanSign(s); };
/** sets plot flag
\param p plot flag (-1 gets, 0 unsets, >0 plot)
\returns current plot flag
*/
int setChargeSharing(int p = -1);
void fixParameter(int ip, Double_t val);
void releaseParameter(int ip);
#ifdef MYROOT
/**
Creates an histogram with the median of nchannels starting from a
specified one. the direction on which it is mediated can be selected
(defaults to x=0) \param h2 2D histogram on which the median will be
calculated \param ch0 starting channel \param nch number of channels to
be mediated \param direction can be either 0 (x, default) or 1 (y)
\returns a TH1F histogram with the X-axis as a clone of the h2 Y (if
direction=0) or X (if direction=0) axis, and on the Y axis the median of
the counts of the mediated channels f h2
*/
static TH1F *createMedianHistogram(TH2F *h2, int ch0, int nch,
int direction = 0);
/** sets the s-curve fit range
\param mi minimum of the fit range (-1 is histogram x-min)
\param ma maximum of the fit range (-1 is histogram x-max)
*/
void setFitRange(Double_t mi, Double_t ma) {
fit_min = mi;
fit_max = ma;
};
/** gets the s-curve fit range
\param mi reference for minimum of the fit range (-1 is histogram x-min)
\param ma reference for maximum of the fit range (-1 is histogram x-max)
*/
void getFitRange(Double_t &mi, Double_t &ma) {
mi = fit_min;
ma = fit_max;
};
/** set start parameters for the s-curve function
\param par parameters, -1 sets to auto-calculation
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point
par[3] is the RMS
par[4] is the amplitude
par[5] is the angual coefficient of the charge sharing slope (scales
with par[3]) -- always positive
*/
void setStartParameters(Double_t *par);
void setStartParametersKb(Double_t *par);
void setStartParametersKaDoublet(Double_t *par);
/** get start parameters for the s-curve function
\param par parameters, -1 means auto-calculated
par[0] is the pedestal
par[1] is the slope of the pedestal
par[2] is the inflection point
par[3] is the RMS
par[4] is the amplitude
par[5] is the angual coefficient of the charge sharing slope (scales
with par[3]) -- always positive
*/
void getStartParameters(Double_t *par);
/**
fits histogram with the s-curve function
\param h1 1d-histogram to be fitted
\param mypar pointer to fit parameters array
\param emypar pointer to fit parameter errors
\returns the fitted function - can be used e.g. to get the Chi2 or
similar
*/
TF1 *fitSCurve(TH1 *h1, Double_t *mypar, Double_t *emypar);
/**
fits histogram with the spectrum
\param h1 1d-histogram to be fitted
\param mypar pointer to fit parameters array
\param emypar pointer to fit parameter errors
\returns the fitted function - can be used e.g. to get the Chi2 or
similar
*/
TF1 *fitSpectrum(TH1 *h1, Double_t *mypar, Double_t *emypar);
TF1 *fitSpectrumKb(TH1 *h1, Double_t *mypar, Double_t *emypar);
TF1 *fitSpectrumKaDoublet(TH1 *h1, Double_t *mypar, Double_t *emypar);
/**
calculates gain and offset for the set of inflection points
\param nscan number of energy scans
\param en array of energies (nscan long)
\param een array of errors on energies (nscan long) - can be NULL!
\param fl array of inflection points (nscan long)
\param efl array of errors on the inflection points (nscan long)
\param gain reference to gain resulting from the fit
\param off reference to offset resulting from the fit
\param egain reference to error on the gain resulting from the fit
\param eoff reference to the error on the offset resulting from the fit
\returns graph energy vs inflection point
*/
TGraphErrors *linearCalibration(int nscan, Double_t *en, Double_t *een,
Double_t *fl, Double_t *efl, Double_t &gain,
Double_t &off, Double_t &egain,
Double_t &eoff);
/**
calculates gain and offset for the set of energy scans
\param nscan number of energy scans
\param en array of energies (nscan long)
\param een array of errors on energies (nscan long) - can be NULL!
\param h1 array of TH1
\param gain reference to gain resulting from the fit
\param off reference to offset resulting from the fit
\param egain reference to error on the gain resulting from the fit
\param eoff reference to the error on the offset resulting from the fit
\returns graph energy vs inflection point
*/
TGraphErrors *calibrateScurves(int nscan, Double_t *en, Double_t *een,
TH1F **h1, Double_t &gain, Double_t &off,
Double_t &egain, Double_t &eoff) {
return calibrate(nscan, en, een, h1, gain, off, egain, eoff, 1);
};
/**
calculates gain and offset for the set of energy spectra
\param nscan number of energy scans
\param en array of energies (nscan long)
\param een array of errors on energies (nscan long) - can be NULL!
\param h1 array of TH1
\param gain reference to gain resulting from the fit
\param off reference to offset resulting from the fit
\param egain reference to error on the gain resulting from the fit
\param eoff reference to the error on the offset resulting from the fit
\returns graph energy vs peak
*/
TGraphErrors *calibrateSpectra(int nscan, Double_t *en, Double_t *een,
TH1F **h1, Double_t &gain, Double_t &off,
Double_t &egain, Double_t &eoff) {
return calibrate(nscan, en, een, h1, gain, off, egain, eoff, 0);
};
#endif
private:
#ifdef MYROOT
/**
calculates gain and offset for the set of energies
\param nscan number of energy scans
\param en array of energies (nscan long)
\param een array of errors on energies (nscan long) - can be NULL!
\param h1 array of TH1
\param gain reference to gain resulting from the fit
\param off reference to offset resulting from the fit
\param egain reference to error on the gain resulting from the fit
\param eoff reference to the error on the offset resulting from the fit
\param integral 1 is an s-curve set (default), 0 spectra
\returns graph energy vs peak/inflection point
*/
TGraphErrors *calibrate(int nscan, Double_t *en, Double_t *een, TH1F **h1,
Double_t &gain, Double_t &off, Double_t &egain,
Double_t &eoff, int integral = 1);
/**
Initializes the start parameters and the range of the fit depending on
the histogram characteristics and/or on the start parameters specified by
the user \param fun pointer to function to be initialized \param h1
histogram from which to extract the range and start parameters, if not
already specified by the user
*/
void initFitFunction(TF1 *fun, TH1 *h1);
void initFitFunctionKb(TF1 *fun, TH1 *h1);
void initFitFunctionKaDoublet(TF1 *fun, TH1 *h1);
/**
Performs the fit according to the flags specified and returns the fitted
function \param fun function to fit \param h1 histogram to fit \param
mypar pointer to fit parameters array \param emypar pointer to fit
parameter errors \returns the fitted function - can be used e.g. to get
the Chi2 or similar
*/
TF1 *fitFunction(TF1 *fun, TH1 *h1, Double_t *mypar, Double_t *emypar);
TF1 *fitFunctionKb(TF1 *fun, TH1 *h1, Double_t *mypar, Double_t *emypar);
TF1 *fitFunctionKaDoublet(TF1 *fun, TH1 *h1, Double_t *mypar,
Double_t *emypar);
#endif
#ifdef MYROOT
Double_t fit_min; /**< minimum of the s-curve fitting range, -1 is histogram
x-min */
Double_t fit_max; /**< maximum of the s-curve fitting range, -1 is histogram
x-max */
Double_t bg_offset; /**< start value for the background pedestal */
Double_t bg_slope; /**< start value for the background slope */
Double_t flex; /**< start value for the inflection point */
Double_t noise; /**< start value for the noise */
Double_t ampl; /**< start value for the number of photons */
Double_t cs_slope; /**< start value for the charge sharing slope */
Double_t kb_mean;
Double_t kb_frac;
Double_t mean2;
Double_t ampl2;
TF1 *fscurve; /**< function with which the s-curve will be fitted */
TF1 *fspectrum; /**< function with which the spectrum will be fitted */
TF1 *fspectrumkb; /**< function with which the spectrum will be fitted */
TF1 *fspectrumkadoublet; /**< function with which the spectrum will be
fitted */
TF1 *fspixel; /**< function with which the spectrum will be fitted */
#endif
energyCalibrationFunctions *funcs;
int plot_flag; /**< 0 does not plot, >0 plots (flags?) */
int cs_flag; /**< 0 functions without charge sharing contribution, >0 with
charge sharing contribution */
};
#endif