libatomprobe
Library for Atom Probe Tomography (APT) computation
curveFit.cpp
Go to the documentation of this file.
1 /* curveFit.cpp : Sample program to fit a simple mass spectrum
2  * Copyright (C) 2015 Daniel Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 
20 #include <iostream>
21 
22 #include "atomprobe/atomprobe.h"
23 
24 using namespace std;
25 using namespace AtomProbe;
26 
27 int main(int argc, char *argv[])
28 {
29  if(argc != 2)
30  {
31  cerr << "USAGE: " << argv[0] << " spectrum" << endl;
32 
33  cerr << " an example file, spectrum-example.txt, is distributed with libatomprobe" << endl;
34  return 1;
35  }
36 
37  //Load the file
38  std::string filename = argv[1];
39  cerr << "Processing file :" << filename << endl;
40 
41  vector<vector<float> > data;
42  vector<string> headers;
43  if(loadTextData(filename.c_str(),data,headers))
44  {
45  cerr << "failed to load data" << endl;
46  return 1;
47  }
48 
49  if(data.empty())
50  {
51  cerr << "0 rows found. Aborting" << endl;
52  return 2;
53  }
54 
55  transposeVector(data);
56 
57  if(data[0].size() !=2)
58  {
59  cerr << "Expected nx2 data size, got nx" << data[0].size() << endl;
60  return 3;
61  }
62 
63  cerr << "Loaded data : " << data.size() << " rows" << endl;
64 
65  //Flip to column format (?)
66  transposeVector(data);
67 
68 
69 
70  //Square-root all x-values, which moves the data from mass to TOF space
71  for(auto &v : data[0])
72  v=sqrt(v);
73 
74  vector<double> xData,yData;
75  xData.resize(data[0].size());
76  yData.resize(data[0].size());
77  for(auto ui=0u;ui<data[0].size();ui++)
78  {
79  xData[ui] = data[0][ui];
80  yData[ui] = data[1][ui];
81  }
82  //Fit the voigt function
83  double sigma,gamma,mu,amp;
84  if(!fitVoigt(xData,yData, sigma,gamma,mu,amp))
85  {
86  cerr << "Curve fit failed. " << endl;
87  }
88 
89 
90  cerr << "VOIGT " << endl;
91  cerr << "=========" << endl;
92  cerr << "sigma:\t" << sigma <<endl;
93  cerr << "gamma:\t" << gamma <<endl;
94  cerr << "mu:\t" << mu << " ( Sqrt : " << mu*mu<< ")" << endl;
95  cerr << "amplitude:\t" << amp <<endl;
96  cerr << "=========" << endl;
97 
98 
99 
100  vector<double> fittedVoigtProfile;
101  voigtProfile(xData,sigma,gamma,mu,amp,fittedVoigtProfile);
102 
103  //Now feed this into provide a log-Gaussian like function
104  double K;
105 
106  cerr << "Attempting semi-random fits of exponential-normal distribution." << endl;
107  cerr << "This can be unstable if too far from initial conditions" << endl;
108  cerr << " This is effectively a budget simulated anneal, and can fail. Try running a few times." << endl;
109 
110  vector<double> bestV = {K,sigma,mu,amp};
111 
112  const unsigned int N_ATTEMPTS=200;
113  unsigned int iter=0;
114  float bestLSQ=std::numeric_limits<float>::max();
115  auto r = randGen.getRng();
116 
117  //FIXME: proper simulated anneal. This is a shitty random re-search method
118  auto handler=gsl_set_error_handler_off();
119  bool firstIt=true;
120  do
121  {
122  //do our best to fit the curve. If first iteration, guess values heuristically
123  fitExpNorm(xData,yData,K,mu,sigma,amp,firstIt);
124  firstIt=false;
125 
126  //Compute residual^2
127  double lsqThis;
128  vector<double> fittedExpNormProfile;
129  expNorm(xData,K,mu,sigma,amp,fittedExpNormProfile);
130  lsqThis=lsq(yData,fittedExpNormProfile);
131  if(lsqThis < bestLSQ)
132  {
133  bestV[0]=K;
134  bestV[1]=sigma;
135  bestV[2]=mu;
136  bestV[3]=amp;
137  bestLSQ=lsqThis;
138  cerr << "Best: (K,Sigma,Mu,Amp) : (" << K << "," << sigma << "," << mu << "," << amp << ")" << endl;
139  }
140 
141  const float SCALE=0.35;
142  K = bestV[0] + gsl_ran_gaussian(r,bestV[0]*SCALE);
143  sigma = bestV[1] + gsl_ran_gaussian(r,bestV[1]*SCALE);
144  mu= bestV[2] + gsl_ran_gaussian(r,bestV[2]*SCALE);
145  amp = bestV[3] + gsl_ran_gaussian(r,bestV[3]*SCALE);
146 
147  //Force positivity for amplitude & sigma
148  amp=fabs(amp);
149  sigma=fabs(sigma);
150 
151 
152  iter++;
153  }while (iter < N_ATTEMPTS);
154  gsl_set_error_handler(handler);
155 
156 
157  K = bestV[0] ;
158  sigma = bestV[1] ;
159  mu= bestV[2] ;
160  amp = bestV[3] ;
161 
162 
163  cerr << "ExpNorm" << endl;
164  cerr << "=========" << endl;
165  cerr << "K:\t" << K <<endl;
166  cerr << "mu:\t" << mu << " ( Sqrt : " << mu*mu<< ")" << endl;
167  cerr << "sigma:\t" << sigma <<endl;
168  cerr << "amplitude:\t" << amp <<endl;
169  cerr << "---------" << endl;
170  cerr << "LSQ:" << bestLSQ << endl;
171  cerr << "=========" << endl;
172 
173  vector<double> fittedExpNormProfile;
174  expNorm(xData,K,mu,sigma,amp,fittedExpNormProfile);
175 
176 
177  ofstream fOut("fittedProfile.txt");
178  if(!fOut)
179  {
180  cerr << "Failed to open fittedProfile.txt for output" << endl;
181  return 6;
182  }
183 
184  fOut << "x\torig\tvoigt\tllg" << endl;
185  for(auto ui=0u; ui<xData.size();ui++)
186  {
187  fOut << (xData[ui]) << "\t" << yData[ui] << "\t" << fittedVoigtProfile[ui] << "\t" << fittedExpNormProfile[ui]<<endl;
188  }
189 
190 
191  cerr << "Wrote curves to : fittedProfile.txt" << endl;
192 
193 }
194 
195 
STL namespace.
void transposeVector(std::vector< std::vector< T > > &v)
Perform an out-of-place tranposition of a given vector.
Definition: misc.h:81
void voigtProfile(const std::vector< double > &x, double sigma, double gamma, double mu, double amp, std::vector< double > &y)
Generate a shifted voigt profile.
Definition: fitting.cpp:486
unsigned int loadTextData(const char *cpFilename, std::vector< std::vector< float > > &dataVec, std::vector< std::string > &headerVec, const char *delim="\", bool allowNan=true, bool allowConvFails=false, unsigned int headerCount=-1)
Load a CSV, TSV or similar text file. Assumes "C" Locale for input (ie "." as decimal separator)...
Definition: dataFiles.cpp:1504
int main(int argc, char *argv[])
Definition: curveFit.cpp:27
const float SCALE
Definition: KDTest.cpp:27
void expNorm(const std::vector< double > &x, double &K, double &mu, double &sigma, double &amp, std::vector< double > &y)
Exponentially decaying normal distribution.
Definition: fitting.cpp:532
bool fitExpNorm(const std::vector< double > &x, const std::vector< double > &y, double &K, double &mu, double &sigma, double &amp, bool autoInit=true)
Fit a smoothed log-gaussian curve (arxiv:0711.4449)
Definition: fitting.cpp:280
bool fitVoigt(const std::vector< double > &x, const std::vector< double > &y, double &sigma, double &gamma, double &mu, double &amp, bool autoInit=true)
Fit a Voigt function to the given X/Y values. Internally, a function minimiser is used...
Definition: fitting.cpp:123
gsl_rng * getRng() const
Obtain a GSL random number generator.
Definition: atomprobe.h:115
RandNumGen randGen
Definition: atomprobe.cpp:29
double lsq(const std::vector< double > &y, const std::vector< double > &yFit)
Definition: fitting.cpp:27