24 #include <gsl/gsl_sf_erf.h> 25 #include <gsl/gsl_histogram.h> 52 float &statistic,
size_t &undefCount,
bool computeMeanAndStdev=
true)
59 if(computeMeanAndStdev)
63 for(
size_t ui=0;ui<n;ui++)
64 vals[ui]=(vals[ui]-meanV)/stdevVal;
67 std::sort(vals.begin(),vals.end());
72 std::vector<double> normedPhi,lonCdf;
73 std::vector<bool> normedPhiOK;
75 normedPhiOK.resize(n,
true);
77 for(
size_t ui=0;ui<n; ui++)
79 normedPhi[ui] = 0.5*(1.0+gsl_sf_erf(vals[ui]/sqrt(2.0)));
81 if(normedPhi[ui] < std::numeric_limits<float>::epsilon())
82 normedPhiOK[ui]=
false;
86 for(
size_t ui=0;ui<n; ui++)
89 lonCdf[ui] = log(normedPhi[ui]);
99 for(
size_t i=0;i<n; i++)
102 v=1.0-normedPhi[n-(i+1)];
104 sumV+=(2.0*(i+1.0)-1.0)*(lonCdf[i] + log(v));
111 statistic=-(double)n - sumV/(
double)n;
117 statistic*=(1.0 + 4.0/(double)n - 25/(
double(n)*double(n)));
127 float end,
float step, vector<float> &histVals)
130 ASSERT(step > std::numeric_limits<float>::epsilon());
132 gsl_histogram *h = gsl_histogram_alloc((end-start)/step);
133 gsl_histogram_set_ranges_uniform(h,start,end);
135 for(
size_t ui=0; ui<data.size();ui++)
136 gsl_histogram_increment(h,data[ui]);
139 histVals.resize(h->n);
140 for(
size_t ui=0;ui<h->n; ui++)
141 histVals[ui]=h->bin[ui];
143 gsl_histogram_free(h);
151 "Insufficient bins to perform fit (in TOF-space)",
152 "Insufficient counts to perform fit (in TOF-space)",
153 "Insufficient data to perform fit",
154 "Data did not appear to be random noise - cannot fit noise level" 157 return std::string(errorMsgs[errMsg]);
165 vector<float> sqrtFiltMass;
166 for(
size_t ui=0;ui<masses.size();ui++)
169 sqrtFiltMass.push_back(sqrtf(masses[ui]));
173 const unsigned int MIN_REQUIRED_AVG_COUNTS=10;
174 const unsigned int MIN_REQUIRED_BINS=10;
177 float filterStep = (sqrt(backParams.
massEnd) - sqrt(backParams.
massStart) )/ nBinsTof;
180 if ( nBinsTof < MIN_REQUIRED_BINS)
189 float averageCounts = sqrtFiltMass.size()/ (float)nBinsTof;
190 if( averageCounts < MIN_REQUIRED_AVG_COUNTS)
194 vector<float> histogram;
196 sqrt(backParams.
massEnd), filterStep,histogram);
198 float andersonStat,meanVal;
211 const float STATISTIC_THRESHOLD=2.0;
212 if(andersonStat > STATISTIC_THRESHOLD || undefCount == histogram.size())
225 float tofBackIntensity, vector<float> &histogram)
227 const float MC_BIN_STEP = (massEnd-massStart)/nBinsMass;
230 histogram.resize(nBinsMass);
231 for(
size_t ui=0;ui<histogram.size();ui++)
234 mcX=(float)(ui)*MC_BIN_STEP+ massStart;
240 float mHigh=mcX+MC_BIN_STEP;
243 histogram[ui] = tofBackIntensity*(sqrt(mHigh) - sqrt(mLow));
249 void diff(
const vector<float> & in, vector<float>& out)
254 out.resize(in.size()-1);
255 for(
auto i=1u; i<in.size()-1; ++i)
256 out[i-1] = 0.5*(in[i+1] - in[i-1]);
259 out[out.size()-1] = in[in.size()-1] - in[in.size()-2];
262 out.resize(in.size()-1);
263 for(
auto i=1u; i<in.size(); ++i)
264 out[i-1] = in[i] - in[i-1];
268 void findPeaks(
const vector<float> &x0, vector<unsigned int>& peakInds,
float sel,
269 bool autoSel,
bool includeEndpoints)
277 auto p = std::minmax_element(x0.begin(),x0.end());
279 size_t minIdx=std::distance(x0.begin(),p.first);
280 size_t maxIdx=std::distance(x0.begin(),p.second);
282 sel = (x0[maxIdx]-x0[minIdx])/4.0;
293 f = std::numeric_limits<float>::epsilon();
297 vector<unsigned int> ind;
305 for(
auto ui=0u;ui<dx0.size()-1;ui++)
307 if(std::signbit(dx0[ui]) !=std::signbit(dx0[ui+1]))
311 float leftMin, minMag;
317 x.resize(ind.size()+2);
319 for(
auto i=0u; i<ind.size()-1; i++)
322 x[i+1] = x0[ind[i+1]];
324 x[x.size()-1] =x0[x0.size()-1];
326 leftMin=minMag = *std::min_element(x.begin(),x.end());
328 ind.push_back(x0.size()-1);
335 minMag=*std::min_element(x.begin(),x.end());
336 leftMin=std::min(x[0],x0[0]);
344 float tempMag= minMag;
348 vector<float> xSub = {x[0],x[1],x[2]};
349 vector<float> signDx;
351 for(
auto &f : signDx)
352 f = std::copysign(1.0f,f);
357 if(signDx[0] == signDx[1])
359 x.erase(x.begin()+1);
360 ind.erase(ind.begin()+1);
365 if(signDx[0] == signDx[1])
368 ind.erase(ind.begin());
375 unsigned int ii = (x[0] >=x[1]) ? 0 : 1;
376 vector<unsigned int> peakLoc;
377 bool foundPeak=
false;
379 unsigned int tempLoc;
380 while( ii < x.size()-1)
395 if( x[ii-1] > tempMag && x[ii-1] > leftMin + sel)
407 if( !foundPeak && tempMag > sel + x[ii-1])
411 peakLoc.push_back(tempLoc);
420 if(x[x.size()-1] > tempMag && x[x.size()-1] > leftMin + sel)
421 peakLoc.push_back(x.size()-1);
422 else if (!foundPeak && tempMag > minMag)
423 peakLoc.push_back(tempLoc);
427 if(x[x.size()-1] >tempMag && x[x.size()-1] > leftMin + sel)
428 peakLoc.push_back(x.size()-1);
429 else if( tempMag > std::min(x0[x0.size()-1],x[x.size()-1]) + sel)
430 peakLoc.push_back(tempLoc);
433 peakInds.resize(peakLoc.size());
434 for(
auto i=0u; i< peakLoc.size();i++)
435 peakInds[i]=ind[peakLoc[i]];
442 bool testBackgroundFitMaths()
445 std::random_device r;
446 std::mt19937 gen(r());
447 std::uniform_real_distribution<> dist(0.0, 1.0);
449 const unsigned int NUM_IONS =100000;
456 const float TOF_LIMIT[2] = { 0.0,100};
458 vector<float> rawData;
459 rawData.resize(NUM_IONS);
463 simTof = dist(gen)*(TOF_LIMIT[1]-TOF_LIMIT[0] ) + TOF_LIMIT[0];
464 rawData[ui] = simTof;
474 vector<float> massData;
475 massData.resize(NUM_IONS);
477 massData[ui] = rawData[ui]*rawData[ui];
478 vector<float> massHist;
482 const float NBINS_TOF = 2000;
483 const float NBINS_MASS= NBINS_TOF;
484 const float MASS_LIMIT[2] = {TOF_LIMIT[0]*TOF_LIMIT[0], TOF_LIMIT[1]*TOF_LIMIT[1]};
488 const float TOF_MEAN_INT= NUM_IONS/(TOF_LIMIT[1] - TOF_LIMIT[0]);
490 const float MC_BIN_STEP = (MASS_LIMIT[1]-MASS_LIMIT[0])/NBINS_MASS;
491 makeHistogram(massData,MASS_LIMIT[0],MASS_LIMIT[1],MC_BIN_STEP,massHist);
494 vector<float > fittedMassHist;
496 TOF_MEAN_INT,fittedMassHist);
502 for(
size_t ui=1;ui<massHist.size();ui++)
505 midV = massHist[ui] + fittedMassHist[ui];
508 accum+=(massHist[ui]-fittedMassHist[ui]);
512 ASSERT(accum/(
float)massHist.size() < 0.05f);
const unsigned int NUM_IONS
std::string getFitErrorMsg(unsigned int errCode)
void makeHistogram(const vector< float > &data, float start, float end, float step, vector< float > &histVals)
void selectElements(const std::vector< T > &in, const std::vector< unsigned int > &indices, std::vector< T > &out)
Obtain the elements at positions indicies in the input vector, copy to output.
void diff(const vector< float > &in, vector< float > &out)
void meanAndStdev(const std::vector< T > &f, float &meanVal, float &stdevVal, bool normalCorrection=true)
unsigned int doFitBackground(const std::vector< float > &massData, BACKGROUND_PARAMS ¶ms)
Perform a background fit, assuming constant TOF noise, from 0->inf time.
bool andersonDarlingStatistic(std::vector< T > vals, float &meanV, float &stdevVal, float &statistic, size_t &undefCount, bool computeMeanAndStdev=true)
void findPeaks(const std::vector< float > &x0, std::vector< unsigned int > &peakInds, float sel, bool autoSel=true, bool includeEndpoints=true)
Simple peak-finding algorithm.
void createMassBackground(float massStart, float massEnd, unsigned int nBinsMass, float tofBackIntensity, std::vector< float > &histogram)
Build a histogram of the background counts.