libatomprobe
Library for Atom Probe Tomography (APT) computation
specsim.cpp
Go to the documentation of this file.
1 #include "atomprobe/atomprobe.h"
2 
3 #include <tuple>
4 #include <numeric>
5 
6 using namespace std;
7 using namespace AtomProbe;
8 
9 const float MASS_TOL=0.05;
10 
11 typedef vector<pair<string,size_t> > FRAGMENT;
12 
13 
14 //Obtain the mass distributions for the given species fragments
15 // this does not take into account the charge state nor the relative intensities of the charges
16 void getMassDistributions(const vector<FRAGMENT> &fragmentVec, const vector<string> &parentSpecies,
17  const AbundanceData &natTable, vector<vector<pair<float,float> > > &massDistVec);
18 
19 void normaliseVec(vector<float> &v)
20 {
21  float normTotal=0;
22  normTotal=std::accumulate(v.begin(),v.end(),0.0f);
23  for(auto &frac : v)
24  frac/=normTotal;
25 }
26 
27 int main(int argc, char *argv[])
28 {
29 
30  //Obtain the natural abundance file
31  //---
32  //Use default unless overridden
33  string sAbundance = "naturalAbundance.xml";
34  if(argc >1)
35  sAbundance =argv[1];
36 
37  AbundanceData natTable;
38 
39  if(natTable.open(sAbundance.c_str()))
40  {
41  cerr << "Failed to open abundance table : " << sAbundance << endl;
42  return 1;
43  }
44  //---
45 
46  //Obtain the species from the user
47  //---
48  std::vector<string> species;
49 
50  std::string specStr;
51  cerr << "Enter species names, space separated" << endl;
52  getline(cin,specStr);
53 
54  //Split the string into a vector, around spaces
55  splitStrsRef(specStr.c_str()," ",species);
56 
57  if(species.empty())
58  {
59  cerr << "no species specified, aborting" << endl;
60  return 1;
61  }
62 
63 
64  std::string compStr;
65  cerr << "Enter species atomic compositions, space separated. This will be normalised" << endl;
66  getline(cin,compStr);
67 
68  vector<float> compositions;
69  vector<string> compStrVec;
70  //Split the string into a vector, around spaces
71  splitStrsRef(compStr.c_str()," ",compStrVec);
72  stripZeroEntries(compStrVec);
73 
74  for(auto &i : compStrVec)
75  {
76  float f;
77  if(stream_cast(f,i))
78  {
79  cerr << "Unable to understand composition : \"" << i << "\", aborting";
80  return 1;
81  }
82 
83  if(f < 0)
84  {
85  cerr << "Composition cannot be negative" << endl;
86  return 1;
87  }
88  compositions.push_back(f);
89  }
90 
91  if(compositions.size() != species.size())
92  {
93  cerr << "Number of compositions did not match number of species, aborting" << endl;
94  return 1;
95  }
96 
97  for(auto frac : compositions)
98  {
99  if(frac < 0)
100  {
101  cerr << "Negative compositions not allowed. Aborting" << endl;
102  return 1;
103  }
104  }
105 
106  //Normalise compositions
107  normaliseVec(compositions);
108  //---
109 
110 
111  //request the charge state
112  //--
113  vector<vector<int> > chargeStates;
114  cout << "Enter charge states, as numbers, e.g. 1 3"<< endl;
115  for(auto &sS: species)
116  {
117  string chargeStr;
118  vector<string> chargesStrVec;
119 
120  cout << sS << "? ";
121  getline(cin,chargeStr);
122 
123 
124  splitStrsRef(chargeStr.c_str()," ",chargesStrVec);
125  stripZeroEntries(chargesStrVec);
126 
127  vector<int> charges;
128  charges.clear();
129 
130  for(auto &s : chargesStrVec)
131  {
132  int i;
133  if(stream_cast(i,s))
134  {
135  cerr << "Unable to understand charge value, aborting" << endl;
136  return 1;
137  }
138  if(i < 1)
139  {
140  cerr << "Charge states must be positive" << endl;
141  return 1;
142  }
143 
144  charges.push_back(i);
145  }
146 
147 
148  chargeStates.push_back(charges);
149 
150  }
151  //--
152 
153  //Check we have some charge states
154  //--
155  unsigned int nCharges=0;
156  for(auto &v : chargeStates)
157  nCharges+=v.size();
158 
159  if(!nCharges)
160  {
161  cerr << "No charges specified, aborting" << endl;
162  return 1;
163  }
164 
165  //--
166 
167 
168  //Request the charge state ratios from the user
169  //----
170  vector<vector<float> > chargeIntensities;
171  bool haveMultiCharge=false;
172  for( auto &v : chargeStates)
173  {
174  if(v.size() >1)
175  {
176  haveMultiCharge=true;
177  break;
178  }
179 
180  }
181 
182 
183  if(haveMultiCharge)
184  cout << "Enter charge state intensities (0->1), will be normalised " << endl;
185  for(auto i=0;i<chargeStates.size();i++)
186  {
187  vector<float> cR;
188  cR.clear();
189 
190  if(chargeStates[i].size() > 1)
191  {
192  for(auto c : chargeStates[i])
193  {
194  float f;
195  cout << species[i] << "(" <<c << ") ?";
196  cin >> f;
197 
198  if(f < 0)
199  {
200  cerr << "Charge state intensity must be greater than 0. Aborting" << endl;
201  return 1;
202  }
203 
204  cR.push_back(f);
205  }
206 
207  normaliseVec(cR);
208  }
209  else
210  cR.push_back(1);
211 
212  chargeIntensities.push_back(cR);
213  }
214 
215  //----
216 
217  vector<FRAGMENT> fragmentVec;
218 
219  //Break each species, such as Fe2H2 into components {Fe,2},{H,2}
220  for(auto &s : species)
221  {
222  vector<pair<string,size_t> > frags;
223  if(!RangeFile::decomposeIonNames(s,frags))
224  {
225  cerr << "WARN : Failed to decompose fragment : " << s << ", skipping" << endl;
226  }
227 
228  fragmentVec.push_back(frags);
229  }
230 
231 
232  //Generate the mass distributions for each species
233  vector<vector<pair<float,float> > > massDistVec;
234  getMassDistributions(fragmentVec,species,natTable,massDistVec);
235 
236  //ASSERT(compositions.size() == massDistVec.size());
237 
238 
239  cerr << "Output is (mass, relative intensity, charge) " << endl;
240  for(auto ui=0;ui<massDistVec.size();ui++)
241  {
242  cerr << "--- " << species[ui] << "---" << endl;
243  vector<tuple<float,float,int> > speciesPeaks;
244  for(auto j=0;j<chargeStates[ui].size();j++)
245  {
246  int charge = chargeStates[ui][j];
247 
248  for(auto &m : massDistVec[ui])
249  {
250  float chargeIntensity = chargeIntensities[ui][j];
251  speciesPeaks.push_back(
252  std::make_tuple(m.first/charge,m.second*compositions[ui]*chargeIntensity, charge));
253  }
254  }
255 
256  //merge the peaks that are within tolerance
257  //FIXME: This algorithm doesn't work if multiple peaks have
258  // transitivity (ie a links to b links to c)
259  // its also a massive hack.
260  //=========
261  //Find any species that links to this one
262  vector<pair<int,int> > linked;
263  for(auto i=0;i<speciesPeaks.size();i++)
264  {
265 
266  //Skip values already linked
267  bool preLinked;
268  preLinked=false;
269  for(auto p : linked)
270  {
271  if(p.second == i)
272  {
273  preLinked=true;
274  break;
275  }
276  }
277 
278  if(preLinked)
279  continue;
280 
281  for(auto j=i+1;j<speciesPeaks.size();j++)
282  {
283  float mass1,mass2;
284  mass1=std::get<0>(speciesPeaks[j]);
285  mass2=std::get<0>(speciesPeaks[i]);
286  int charge1,charge2;
287  charge1=std::get<2>(speciesPeaks[j]);
288  charge2=std::get<2>(speciesPeaks[i]);
289 
290 
291  if(fabs( mass1/charge1- mass2/charge2) < MASS_TOL)
292  linked.push_back(make_pair(i,j));
293  }
294 
295 
296  }
297 
298  //Merge any peaks that are linked
299  vector<std::tuple<float,float,vector<int> > > mergedPeaks;
300  for(auto i : linked)
301  {
302  tuple<float,float,int> t1,t2;
303  t1 = speciesPeaks[i.first];
304  t2 = speciesPeaks[i.second];
305 
306  std::vector<int> charges;
307  charges.push_back(std::get<2>(t1));
308  charges.push_back(std::get<2>(t2));
309 
310 
311  mergedPeaks.push_back(
312  std::make_tuple((std::get<0>(t1) + std::get<0>(t2))*0.5,
313  std::get<1>(t1)+std::get<1>(t2),charges));
314 
315  }
316 
317  vector<bool> unlinked;
318  unlinked.resize(speciesPeaks.size(),true);
319  for(auto i : linked)
320  unlinked[i.first]=unlinked[i.second]=false;
321 
322  for(auto i=0;i<speciesPeaks.size();i++)
323  {
324  if(unlinked[i])
325  {
326  auto t = speciesPeaks[i];
327  vector<int> v;
328  v.push_back(std::get<2>(t));
329  mergedPeaks.push_back(
330  make_tuple(std::get<0>(t),std::get<1>(t),v));
331  }
332  }
333  //=========
334 
335  for(auto &t : mergedPeaks)
336  {
337  string sCharges;
338  sCharges.clear();
339 
340  for(auto charge : std::get<2>(t))
341  {
342  string tmp;
343  stream_cast(tmp,charge);
344  sCharges+=tmp + " ";
345  }
346 
347  cerr << std::get<0>(t) << "," << std::get<1>(t) <<
348  "," << sCharges << endl;
349  }
350 
351  cerr << "-------------------------------" << endl << endl;
352  }
353 
354 
355 
356 }
357 
358 
359 
360 void getMassDistributions(const vector<FRAGMENT> &fragmentVec, const vector<string> &parentSpecies,
361  const AbundanceData &natTable, vector<vector<pair<float,float> > > &massDistVec)
362 {
363  //ASSERT(fragmentVec.size() == parentSpecies.size());
364 
365  for(auto ui=0;ui<fragmentVec.size();ui++)
366  {
367  //Look up this fragment set (e.g. {{Fe,2},{H,2}}) in the
368  // abundance table
369  vector<pair<size_t,unsigned int> > outputVec;
370  natTable.getSymbolIndices(fragmentVec[ui],outputVec);
371 
372  //Check it was OK, and record as needed
373  bool fragmentLookupOK;
374  fragmentLookupOK=true;
375  vector<size_t> indexVec,freqVec;
376  for( auto &p : outputVec)
377  {
378  //Spit out error if lookup failed
379  if(p.first == (size_t)-1)
380  {
381  cerr << "Unable to lookup mass for component:" << ui<< endl;
382  fragmentLookupOK=false;
383  break;
384  }
385 
386  //Record the symbol index for ths component
387  indexVec.push_back(p.first);
388  //Record the count
389  freqVec.push_back(p.second);
390  }
391 
392  //Lookup failed, provide more error data
393  if(!fragmentLookupOK)
394  {
395  cerr << "Component lookup for Fragment :" << parentSpecies[ui] << "failed" << endl;
396  continue;
397  }
398 
399 
400 
401  //Obtain the distribution for this fragment set
402  vector<pair<float,float> > massDist;
403 
404  natTable.generateGroupedIsotopeDist(indexVec,freqVec,massDist,MASS_TOL);
405  massDistVec.emplace_back(massDist);
406  }
407 }
void normaliseVec(vector< float > &v)
Definition: specsim.cpp:19
STL namespace.
void getSymbolIndices(const std::vector< std::string > &symbols, std::vector< size_t > &indices) const
Return a vector of symbol indices.
Definition: abundance.cpp:559
vector< pair< string, size_t > > FRAGMENT
Definition: specsim.cpp:11
void splitStrsRef(const char *cpStr, const char delim, std::vector< std::string > &v)
Split string references using a single delimiter.
void generateGroupedIsotopeDist(const std::vector< size_t > &elementIdx, const std::vector< size_t > &frequency, std::vector< std::pair< float, float > > &massDist, float massTolerance) const
As per generateIsotopeDist, however, this convenience groups the distribution to limit the effect of ...
Definition: abundance.cpp:395
int main(int argc, char *argv[])
Definition: specsim.cpp:27
size_t open(const char *file, bool strict=false)
Attempt to open the abundance data file, return 0 on success, nonzero on failure. ...
Definition: abundance.cpp:79
Class to load abundance information for natural isotopes.
Definition: abundance.h:54
void getMassDistributions(const vector< FRAGMENT > &fragmentVec, const vector< string > &parentSpecies, const AbundanceData &natTable, vector< vector< pair< float, float > > > &massDistVec)
Definition: specsim.cpp:360
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32
const float MASS_TOL
Definition: specsim.cpp:9
void stripZeroEntries(std::vector< std::string > &s)