mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-13 05:17:13 +02:00
Classes, Libraries and Functions for Characterization and Calibration of SLS Detectors. First import.
git-svn-id: file:///afs/psi.ch/project/sls_det_software/svn/slsDetectorCalibration@1 113b152e-814d-439b-b186-022a431db7b5
This commit is contained in:
88
slsDetectorCalibration/MovingStat.h
Executable file
88
slsDetectorCalibration/MovingStat.h
Executable file
@ -0,0 +1,88 @@
|
|||||||
|
class MovingStat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MovingStat() : m_n(0), n(0) {}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
m_n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetN(int i) {n=i;};
|
||||||
|
int GetN() {return n;};
|
||||||
|
void Calc(double x) {
|
||||||
|
if (m_n<n) Add(x);
|
||||||
|
else Push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(double x) {
|
||||||
|
m_n++;
|
||||||
|
|
||||||
|
// See Knuth TAOCP vol 2, 3rd edition, page 232
|
||||||
|
if (m_n == 1)
|
||||||
|
{
|
||||||
|
m_oldM = m_newM = x;
|
||||||
|
m_oldM2 = x*x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_newM = m_oldM + x;
|
||||||
|
m_newM2 = m_oldM2 + x*x;
|
||||||
|
//m_newM2 = m_oldM2 + (x*x - m_oldM*m_oldM)/m_n;
|
||||||
|
|
||||||
|
// set up for next iteration
|
||||||
|
m_oldM = m_newM;
|
||||||
|
m_oldM2 = m_newM2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Push(double x)
|
||||||
|
{
|
||||||
|
if (m_n == 1)
|
||||||
|
{
|
||||||
|
m_oldM = m_newM = x;
|
||||||
|
m_oldM2 = x*x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_newM = m_oldM + (x - m_oldM/m_n);
|
||||||
|
m_newM2 = m_oldM2 + (x*x - m_oldM2/m_n);
|
||||||
|
//m_newM2 = m_oldM2 + (x*x/m_n - m_oldM*m_oldM/(m_n*m_n));
|
||||||
|
// set up for next iteration
|
||||||
|
m_oldM = m_newM;
|
||||||
|
m_oldM2 = m_newM2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int NumDataValues() const
|
||||||
|
{
|
||||||
|
return m_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Mean() const
|
||||||
|
{
|
||||||
|
return (m_n > 0) ? m_newM/m_n : 0.0;
|
||||||
|
}
|
||||||
|
double M2() const
|
||||||
|
{
|
||||||
|
return ( (m_n > 1) ? m_newM2/m_n : 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
double Variance() const
|
||||||
|
{
|
||||||
|
return ( (m_n > 1) ? (M2()-Mean()*Mean()) : 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
double StandardDeviation() const
|
||||||
|
{
|
||||||
|
return ( (Variance() > 0) ? sqrt( Variance() ) : -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int n;
|
||||||
|
int m_n;
|
||||||
|
double m_oldM, m_newM, m_oldM2, m_newM2;
|
||||||
|
};
|
55
slsDetectorCalibration/RunningStat.h
Executable file
55
slsDetectorCalibration/RunningStat.h
Executable file
@ -0,0 +1,55 @@
|
|||||||
|
class RunningStat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RunningStat() : m_n(0) {}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
m_n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Push(double x)
|
||||||
|
{
|
||||||
|
m_n++;
|
||||||
|
|
||||||
|
// See Knuth TAOCP vol 2, 3rd edition, page 232
|
||||||
|
if (m_n == 1)
|
||||||
|
{
|
||||||
|
m_oldM = m_newM = x;
|
||||||
|
m_oldS = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_newM = m_oldM + (x - m_oldM)/m_n;
|
||||||
|
m_newS = m_oldS + (x - m_oldM)*(x - m_newM);
|
||||||
|
|
||||||
|
// set up for next iteration
|
||||||
|
m_oldM = m_newM;
|
||||||
|
m_oldS = m_newS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int NumDataValues() const
|
||||||
|
{
|
||||||
|
return m_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Mean() const
|
||||||
|
{
|
||||||
|
return (m_n > 0) ? m_newM : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Variance() const
|
||||||
|
{
|
||||||
|
return ( (m_n > 1) ? m_newS/(m_n - 1) : 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
double StandardDeviation() const
|
||||||
|
{
|
||||||
|
return sqrt( Variance() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_n;
|
||||||
|
double m_oldM, m_newM, m_oldS, m_newS;
|
||||||
|
};
|
457
slsDetectorCalibration/energyCalibration.cpp
Normal file
457
slsDetectorCalibration/energyCalibration.cpp
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
#include "energyCalibration.h"
|
||||||
|
|
||||||
|
#ifdef __CINT
|
||||||
|
#define MYROOT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
#include <TMath.h>
|
||||||
|
#include <TH1F.h>
|
||||||
|
#include <TH2F.h>
|
||||||
|
#include <TGraphErrors.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define ELEM_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; }
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
Double_t energyCalibrationFunctions::gaussChargeSharing(Double_t *x, Double_t *par) {
|
||||||
|
Double_t f, arg=0;
|
||||||
|
if (par[3]!=0) arg=(x[0]-par[2])/par[3];
|
||||||
|
f=par[4]*TMath::Exp(-1*arg*arg/2.);
|
||||||
|
f=f+par[5]*(par[4]/2*(TMath::Erfc(sign*arg/(TMath::Sqrt(2.)))))+par[0]-par[1]*sign*x[0];
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// basic erf function
|
||||||
|
Double_t energyCalibrationFunctions::erfFunction(Double_t *x, Double_t *par) {
|
||||||
|
double arg=0;
|
||||||
|
if (par[1]!=0) arg=(par[0]-x[0])/par[1];
|
||||||
|
return ((par[2]/2.*(1+TMath::Erf(sign*arg/(TMath::Sqrt(2))))));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Double_t energyCalibrationFunctions::erfFunctionChargeSharing(Double_t *x, Double_t *par) {
|
||||||
|
Double_t f;
|
||||||
|
|
||||||
|
f=erfFunction(x, par+2)*(1+par[5]*(par[2]-x[0]))+par[0]-par[1]*x[0]*sign;
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Double_t energyCalibrationFunctions::erfFuncFluo(Double_t *x, Double_t *par) {
|
||||||
|
Double_t f;
|
||||||
|
f=erfFunctionChargeSharing(x, par)+erfFunction(x, par+6)*(1+par[9]*(par[6]-x[0]));
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double energyCalibrationFunctions::median(double *x, int n){
|
||||||
|
// sorts x into xmed array and returns median
|
||||||
|
// n is number of values already in the xmed array
|
||||||
|
double xmed[n];
|
||||||
|
int k,i,j;
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
k=0;
|
||||||
|
for (j=0; j<n; j++) {
|
||||||
|
if(*(x+i)>*(x+j))
|
||||||
|
k++;
|
||||||
|
if (*(x+i)==*(x+j)) {
|
||||||
|
if (i>j)
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmed[k]=*(x+i);
|
||||||
|
}
|
||||||
|
k=n/2;
|
||||||
|
return xmed[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int energyCalibrationFunctions::quick_select(int arr[], int n){
|
||||||
|
int low, high ;
|
||||||
|
int median;
|
||||||
|
int middle, ll, hh;
|
||||||
|
|
||||||
|
low = 0 ; high = n-1 ; median = (low + high) / 2;
|
||||||
|
for (;;) {
|
||||||
|
if (high <= low) /* One element only */
|
||||||
|
return arr[median] ;
|
||||||
|
|
||||||
|
if (high == low + 1) { /* Two elements only */
|
||||||
|
if (arr[low] > arr[high])
|
||||||
|
ELEM_SWAP(arr[low], arr[high]) ;
|
||||||
|
return arr[median] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find median of low, middle and high items; swap into position low */
|
||||||
|
middle = (low + high) / 2;
|
||||||
|
if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
|
||||||
|
if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
|
||||||
|
if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
|
||||||
|
|
||||||
|
/* Swap low item (now in position middle) into position (low+1) */
|
||||||
|
ELEM_SWAP(arr[middle], arr[low+1]) ;
|
||||||
|
|
||||||
|
/* Nibble from each end towards middle, swapping items when stuck */
|
||||||
|
ll = low + 1;
|
||||||
|
hh = high;
|
||||||
|
for (;;) {
|
||||||
|
do ll++; while (arr[low] > arr[ll]) ;
|
||||||
|
do hh--; while (arr[hh] > arr[low]) ;
|
||||||
|
|
||||||
|
if (hh < ll)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ELEM_SWAP(arr[ll], arr[hh]) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap middle item (in position low) back into correct position */
|
||||||
|
ELEM_SWAP(arr[low], arr[hh]) ;
|
||||||
|
|
||||||
|
/* Re-set active partition */
|
||||||
|
if (hh <= median)
|
||||||
|
low = ll;
|
||||||
|
if (hh >= median)
|
||||||
|
high = hh - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int energyCalibrationFunctions::kth_smallest(int *a, int n, int k){
|
||||||
|
register int i,j,l,m ;
|
||||||
|
register double x ;
|
||||||
|
|
||||||
|
l=0 ; m=n-1 ;
|
||||||
|
while (l<m) {
|
||||||
|
x=a[k] ;
|
||||||
|
i=l ;
|
||||||
|
j=m ;
|
||||||
|
do {
|
||||||
|
while (a[i]<x) i++ ;
|
||||||
|
while (x<a[j]) j-- ;
|
||||||
|
if (i<=j) {
|
||||||
|
ELEM_SWAP(a[i],a[j]) ;
|
||||||
|
i++ ; j-- ;
|
||||||
|
}
|
||||||
|
} while (i<=j) ;
|
||||||
|
if (j<k) l=i ;
|
||||||
|
if (k<i) m=j ;
|
||||||
|
}
|
||||||
|
return a[k] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
Double_t energyCalibrationFunctions::spectrum(Double_t *x, Double_t *par) {
|
||||||
|
return gaussChargeSharing(x,par);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Double_t energyCalibrationFunctions::scurve(Double_t *x, Double_t *par) {
|
||||||
|
return erfFunctionChargeSharing(x,par);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Double_t energyCalibrationFunctions::scurveFluo(Double_t *x, Double_t *par) {
|
||||||
|
return erfFuncFluo(x,par);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
energyCalibration::energyCalibration() :
|
||||||
|
#ifdef MYROOT
|
||||||
|
fit_min(-1),
|
||||||
|
fit_max(-1),
|
||||||
|
bg_offset(-1),
|
||||||
|
bg_slope(-1),
|
||||||
|
flex(-1),
|
||||||
|
noise(-1),
|
||||||
|
ampl(-1),
|
||||||
|
cs_slope(-1),
|
||||||
|
fscurve(NULL),
|
||||||
|
fspectrum(NULL),
|
||||||
|
#endif
|
||||||
|
funcs(NULL),
|
||||||
|
plot_flag(1),
|
||||||
|
cs_flag(1)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
funcs=new energyCalibrationFunctions();
|
||||||
|
|
||||||
|
fscurve=new TF1("fscurve",funcs,&energyCalibrationFunctions::scurve,0,1000,6,"energyCalibrationFunctions","scurve");
|
||||||
|
fscurve->SetParNames("Background Offset","Background Slope","Inflection Point","Noise RMS", "Number of Photons","Charge Sharing Slope");
|
||||||
|
|
||||||
|
fspectrum=new TF1("fspectrum",funcs,&energyCalibrationFunctions::spectrum,0,1000,6,"energyCalibrationFunctions","spectrum");
|
||||||
|
fspectrum->SetParNames("Background Pedestal","Background slope", "Peak position","Noise RMS", "Number of Photons","Charge Sharing Pedestal");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void energyCalibration::fixParameter(int ip, Double_t val){
|
||||||
|
|
||||||
|
fscurve->FixParameter(ip, val);
|
||||||
|
fspectrum->FixParameter(ip, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void energyCalibration::releaseParameter(int ip){
|
||||||
|
|
||||||
|
fscurve->ReleaseParameter(ip);
|
||||||
|
fspectrum->ReleaseParameter(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
energyCalibration::~energyCalibration(){
|
||||||
|
#ifdef MYROOT
|
||||||
|
delete fscurve;
|
||||||
|
delete fspectrum;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TH1F* energyCalibration::createMedianHistogram(TH2F* h2, int ch0, int nch) {
|
||||||
|
|
||||||
|
if (h2==NULL || nch==0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
double *x=new double[nch];
|
||||||
|
TH1F *h1=NULL;
|
||||||
|
|
||||||
|
double val=-1;
|
||||||
|
|
||||||
|
h1=new TH1F("median","Median",h2->GetYaxis()->GetNbins(),h2->GetYaxis()->GetXmin(),h2->GetYaxis()->GetXmax());
|
||||||
|
|
||||||
|
|
||||||
|
for (int ib=0; ib<h1->GetXaxis()->GetNbins(); ib++) {
|
||||||
|
for (int ich=0; ich<nch; ich++) {
|
||||||
|
x[ich]=h2->GetBinContent(ch0+ich+1,ib+1);
|
||||||
|
}
|
||||||
|
val=energyCalibrationFunctions::median(x, nch);
|
||||||
|
h1->SetBinContent(ib+1,val);
|
||||||
|
}
|
||||||
|
return h1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void energyCalibration::setStartParameters(Double_t *par){
|
||||||
|
bg_offset=par[0];
|
||||||
|
bg_slope=par[1];
|
||||||
|
flex=par[2];
|
||||||
|
noise=par[3];
|
||||||
|
ampl=par[4];
|
||||||
|
cs_slope=par[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void energyCalibration::getStartParameters(Double_t *par){
|
||||||
|
par[0]=bg_offset;
|
||||||
|
par[1]=bg_slope;
|
||||||
|
par[2]=flex;
|
||||||
|
par[3]=noise;
|
||||||
|
par[4]=ampl;
|
||||||
|
par[5]=cs_slope;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
int energyCalibration::setChargeSharing(int p) {
|
||||||
|
if (p>=0) {
|
||||||
|
cs_flag=p;
|
||||||
|
#ifdef MYROOT
|
||||||
|
if (p) {
|
||||||
|
fscurve->ReleaseParameter(5);
|
||||||
|
fspectrum->ReleaseParameter(1);
|
||||||
|
} else {
|
||||||
|
fscurve->FixParameter(5,0);
|
||||||
|
fspectrum->FixParameter(1,0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
void energyCalibration::initFitFunction(TF1 *fun, TH1 *h1) {
|
||||||
|
|
||||||
|
Double_t min=fit_min, max=fit_max;
|
||||||
|
|
||||||
|
Double_t mypar[6];
|
||||||
|
|
||||||
|
if (max==-1)
|
||||||
|
max=h1->GetXaxis()->GetXmax();
|
||||||
|
|
||||||
|
if (min==-1)
|
||||||
|
min=h1->GetXaxis()->GetXmin();
|
||||||
|
|
||||||
|
|
||||||
|
if (bg_offset==-1)
|
||||||
|
mypar[0]=0;
|
||||||
|
else
|
||||||
|
mypar[0]=bg_offset;
|
||||||
|
|
||||||
|
|
||||||
|
if (bg_slope==-1)
|
||||||
|
mypar[1]=0;
|
||||||
|
else
|
||||||
|
mypar[1]=bg_slope;
|
||||||
|
|
||||||
|
|
||||||
|
if (flex==-1)
|
||||||
|
mypar[2]=(min+max)/2.;
|
||||||
|
else
|
||||||
|
mypar[2]=flex;
|
||||||
|
|
||||||
|
|
||||||
|
if (noise==-1)
|
||||||
|
mypar[3]=0.1;
|
||||||
|
else
|
||||||
|
mypar[3]=noise;
|
||||||
|
|
||||||
|
if (ampl==-1)
|
||||||
|
mypar[4]=h1->GetBinContent(h1->GetXaxis()->FindBin(0.5*(max+min)));
|
||||||
|
else
|
||||||
|
mypar[4]=ampl;
|
||||||
|
|
||||||
|
if (cs_slope==-1)
|
||||||
|
mypar[5]=0;
|
||||||
|
else
|
||||||
|
mypar[5]=cs_slope;
|
||||||
|
|
||||||
|
fun->SetParameters(mypar);
|
||||||
|
|
||||||
|
fun->SetRange(min,max);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TF1* energyCalibration::fitFunction(TF1 *fun, TH1 *h1, Double_t *mypar, Double_t *emypar) {
|
||||||
|
|
||||||
|
|
||||||
|
TF1* fitfun;
|
||||||
|
|
||||||
|
char fname[100];
|
||||||
|
|
||||||
|
strcpy(fname, fun->GetName());
|
||||||
|
|
||||||
|
if (plot_flag) {
|
||||||
|
h1->Fit(fname,"R");
|
||||||
|
} else
|
||||||
|
h1->Fit(fname,"R0Q");
|
||||||
|
|
||||||
|
|
||||||
|
fitfun= h1->GetFunction(fname);
|
||||||
|
fitfun->GetParameters(mypar);
|
||||||
|
for (int ip=0; ip<6; ip++) {
|
||||||
|
emypar[ip]=fitfun->GetParError(ip);
|
||||||
|
}
|
||||||
|
return fitfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
TF1* energyCalibration::fitSCurve(TH1 *h1, Double_t *mypar, Double_t *emypar) {
|
||||||
|
initFitFunction(fscurve,h1);
|
||||||
|
return fitFunction(fscurve, h1, mypar, emypar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TF1* energyCalibration::fitSpectrum(TH1 *h1, Double_t *mypar, Double_t *emypar) {
|
||||||
|
initFitFunction(fspectrum,h1);
|
||||||
|
return fitFunction(fspectrum, h1, mypar, emypar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TGraphErrors* energyCalibration::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) {
|
||||||
|
|
||||||
|
TGraphErrors *gr;
|
||||||
|
|
||||||
|
Double_t mypar[2];
|
||||||
|
|
||||||
|
gr = new TGraphErrors(nscan,en,fl,een,efl);
|
||||||
|
|
||||||
|
if (plot_flag) {
|
||||||
|
gr->Fit("pol1");
|
||||||
|
gr->SetMarkerStyle(20);
|
||||||
|
} else
|
||||||
|
gr->Fit("pol1","0Q");
|
||||||
|
|
||||||
|
TF1 *fitfun= gr->GetFunction("pol1");
|
||||||
|
fitfun->GetParameters(mypar);
|
||||||
|
|
||||||
|
egain=fitfun->GetParError(1);
|
||||||
|
eoff=fitfun->GetParError(0);
|
||||||
|
|
||||||
|
gain=funcs->setScanSign()*mypar[1];
|
||||||
|
off=mypar[0];
|
||||||
|
|
||||||
|
return gr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TGraphErrors* energyCalibration::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) {
|
||||||
|
|
||||||
|
TH1F *h;
|
||||||
|
|
||||||
|
Double_t mypar[6], emypar[6];
|
||||||
|
Double_t fl[nscan], efl[nscan];
|
||||||
|
|
||||||
|
|
||||||
|
for (int ien=0; ien<nscan; ien++) {
|
||||||
|
h=h1[ien];
|
||||||
|
if (integral)
|
||||||
|
fitSCurve(h,mypar,emypar);
|
||||||
|
else
|
||||||
|
fitSpectrum(h,mypar,emypar);
|
||||||
|
|
||||||
|
fl[ien]=mypar[2];
|
||||||
|
efl[ien]=emypar[2];
|
||||||
|
}
|
||||||
|
return linearCalibration(nscan,en,een,fl,efl,gain,off, egain, eoff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
412
slsDetectorCalibration/energyCalibration.h
Normal file
412
slsDetectorCalibration/energyCalibration.h
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MYROOT
|
||||||
|
#include <TROOT.h>
|
||||||
|
#include <TF1.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
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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) ;
|
||||||
|
|
||||||
|
/** 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 fractional height of the charge sharing pedestal (scales with par[3]
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
Double_t spectrum(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
|
||||||
|
|
||||||
|
static TH1F* createMedianHistogram(TH2F* h2, int ch0, int nch);
|
||||||
|
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
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);
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
|
TF1 *fscurve; /**< function with which the s-curve will be fitted */
|
||||||
|
|
||||||
|
TF1 *fspectrum; /**< 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
6
slsDetectorCalibration/energyCalibration_cpp.d
Normal file
6
slsDetectorCalibration/energyCalibration_cpp.d
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
./energyCalibration_cpp.so: energyCalibration.h
|
||||||
|
./energyCalibration_cpp.so: /afs/psi.ch/project/sls_det_software/root_v5.32.01_sl5_32bit/include/cintdictversion.h /afs/psi.ch/project/sls_det_software/root_v5.32.01_sl5_32bit/include/RVersion.h
|
||||||
|
energyCalibration_cpp__ROOTBUILDVERSION= 5.32/01
|
Reference in New Issue
Block a user