libatomprobe
Library for Atom Probe Tomography (APT) computation
massconvert.cpp
Go to the documentation of this file.
1 /*
2  * abundance.cpp : module to load, manipulate and compute natural abundance information
3  * Copyright (C) 2016 D Haley
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <algorithm>
20 #include <iostream>
21 
22 #include <cmath>
23 #include <limits>
24 
25 
28 
30 
32 
33 
34 namespace AtomProbe
35 {
36 using std::map;
37 using std::vector;
38 using std::string;
39 
40 
41 void convertMolToMass(const AbundanceData &atomTable,
42  const map<unsigned int, double> &compositionMols,
43  map<unsigned int, double> &compositionMass)
44 {
45  map<unsigned int, double> massValues;
46 
47  for(map<unsigned int, double>::const_iterator it=compositionMols.begin(); it!=compositionMols.end();++it)
48  massValues[it->first] = atomTable.getNominalMass(it->first);
49 
50 
51  //compute the total summed molar values
52  double totalMols=0;
53  for(map<unsigned int, double>::const_iterator it=compositionMols.begin();
54  it!=compositionMols.end(); ++it)
55  totalMols+=it->second;
56 
57 
58  double totalMass=0;
59  for(map<unsigned int, double>::const_iterator it=compositionMols.begin();
60  it!=compositionMols.end(); ++it)
61  totalMass+=massValues.at(it->first)*it->second/totalMols;
62 
63  for(map<unsigned int, double>::const_iterator it=compositionMols.begin();
64  it!=compositionMols.end(); ++it)
65  {
66  ASSERT(compositionMass.find(it->first) == compositionMass.end());
67  compositionMass[it->first] = it->second/totalMols*massValues.at(it->first)/totalMass;
68  }
69 
70 
71 }
72 
73 //FIXME : Error handling? What if user supplies an atom that does not exist?
74 void convertMassToMol(const AbundanceData &atomTable,
75  const map<unsigned int, double> &compositionMass,
76  map<unsigned int, double> &compositionMols)
77 {
78  map<unsigned int, double> massValues;
79 
80  for(map<unsigned int,double>::const_iterator it=compositionMass.begin(); it!=compositionMass.end();++it)
81  massValues[it->first] = atomTable.getNominalMass(it->first);
82 
83  double totalMol=0;
84  for(map<unsigned int,double>::const_iterator it=compositionMass.begin(); it!=compositionMass.end();++it)
85  {
86  double thisMol;
87  thisMol= (it->second/massValues.at(it->first));
88  compositionMols[it->first] = thisMol;
89  totalMol+=thisMol;
90  }
91 
92  for(map<unsigned int,double>::const_iterator it=compositionMass.begin(); it!=compositionMass.end();++it)
93  {
94  compositionMols[it->first]/=totalMol;
95  }
96 
97 }
98 
99 
100 unsigned int parseCompositionData(const std::vector<std::string> &atomList,
101  const AbundanceData &massTable, std::map<unsigned int, double> &atomData)
102 {
103  //Dummy composition value to use as a placeholder when computing composition data
104  const double BALANCE_TOKEN = -128.0f;
105 
106  double totalComp=0.0f;
107  //Number of times we have seen the "bal" marker before
108  unsigned int balanceNumber=0;
109 
110  for(unsigned int ui=0;ui<atomList.size();ui++)
111  {
112  std::string s;
113  s=stripWhite(atomList[ui]);
114 
115  vector<string> strs;
116  splitStrsRef(s.c_str(),",\t ",strs);
117 
118  if(strs.empty())
119  break;
120 
121  stripZeroEntries(strs);
122 
123  if(strs.size() !=2)
125 
126  //Convert bal or numeric string to lowercase
127  strs[1]=lowercase(strs[1]);
128 
129  //Ensure bal value is used the right number of times
130  double value;
131  if(stream_cast(value,strs[1]) && strs[1] != "bal")
133  else if( strs[1] == "bal" && balanceNumber)
134  return COMPPARSE_BAD_BAL_USAGE;
135 
136  //parse atomic data
137  size_t atomicNumber;
138  atomicNumber= massTable.symbolIndex(strs[0].c_str())+1;
139  if(!atomicNumber)
140  return COMPPARSE_BAD_SYMBOL;
141 
142  if(atomData.find(atomicNumber) != atomData.end())
144 
145  //Record atomic number->composition pairing
146  if(strs[1] != "bal")
147  {
148  atomData[atomicNumber-1] = value;
149  totalComp+=value;
150  }
151  else
152  {
153  balanceNumber=atomicNumber-1;
154  atomData[atomicNumber-1] = BALANCE_TOKEN;
155  }
156 
157  }
158  if(balanceNumber)
159  {
160  if(totalComp > 1.0f )
161  {
163  }
164 
165  atomData[balanceNumber] = 1.0-totalComp;
166 
167  }
168 
169  return 0;
170 }
171 
172 #ifdef DEBUG
174 #include "helper/helpFuncs.h"
175 
176 
177 bool testMassToMolConversion()
178 {
179  AbundanceData natData;
180  if(natData.open("naturalAbundance.xml"))
181  return false;
182 
183  map<unsigned int, double> molComp,massComp;
184 
185  unsigned int idxFe,idxC;
186  idxFe=natData.symbolIndex("Fe");
187  massComp[idxFe]=0.96;
188  idxC=natData.symbolIndex("C");
189  massComp[idxC]=0.04;
190 
191  convertMassToMol(natData,massComp, molComp);
192 
193  TEST(massComp.size() ==2, "Mass Composition data size");
194  float total=0;
195  for(auto it=molComp.begin();it!=molComp.end(); it++)
196  {
197  TEST(massComp.find(it->first) != molComp.end(),"Symbol present in both mass and molar comp");
198  TEST(it->second <=1 && it->second >=0, "Composition should be in 0->1");
199  total+=it->second;
200  }
201 
202  TEST(TOL_EQ(total,1.0f),"total composition sums to 1");
203 
204  TEST(TOL_EQ(molComp[idxFe],0.8377079),"Fe composition");
205  TEST(TOL_EQ(molComp[idxC],0.162292),"C composition");
206 
207  return true;
208 }
209 
210 bool testMolToMassConversion()
211 {
212  AbundanceData natData;
213  if(natData.open("naturalAbundance.xml"))
214  return false;
215 
216  map<unsigned int, double> molComp,massComp;
217 
218  unsigned int idxFe,idxC;
219  idxFe=natData.symbolIndex("Fe");
220  molComp[idxFe]=0.96;
221  idxC=natData.symbolIndex("C");
222  molComp[idxC]=0.04;
223 
224  convertMolToMass(natData,molComp, massComp);
225 
226  TEST(massComp.size() ==2, "Mass Composition data size");
227  float total=0;
228  for(auto it=massComp.begin();it!=massComp.end(); it++)
229  {
230  TEST(molComp.find(it->first) != molComp.end(),"Symbol present in both mass and molar comp");
231  total+=it->second;
232  }
233 
234  TEST(TOL_EQ(total,1.0f),"total composition sums to 1");
235 
236  TEST(TOL_EQ(massComp[idxFe],0.99115),"Fe composition");
237  TEST(TOL_EQ(massComp[idxC],0.008849557),"C composition");
238 
239  return true;
240 }
241 
242 bool testMassMolConversion()
243 {
244  TEST(testMolToMassConversion(),"Mol->mass conversion");
245  TEST(testMassToMolConversion(),"Mass->Mol conversion");
246 
247  return true;
248 }
249 #endif
250 }
251 
size_t symbolIndex(const char *symbol, bool caseSensitive=true) const
Return the element&#39;s position in table, starting from 0.
Definition: abundance.cpp:214
std::string stripWhite(const std::string &str)
Strip whitespace, (eg tab,space) from either side of a string.
float getNominalMass(size_t elementIdx) const
Obtain the isotope weighted mass for the given element.
Definition: abundance.cpp:626
#define TEST(f, g)
Definition: aptAssert.h:49
void convertMolToMass(const AbundanceData &atomTable, const std::map< unsigned int, double > &compositionMols, std::map< unsigned int, double > &compositionMass)
Convert the given composition from molar fraction data to mass fraction.
Definition: massconvert.cpp:41
void convertMassToMol(const AbundanceData &atomTable, const std::map< unsigned int, double > &compositionMass, std::map< unsigned int, double > &compositionMols)
Convert the given composition from mass fraction data to molar fraction.
Definition: massconvert.cpp:74
void splitStrsRef(const char *cpStr, const char delim, std::vector< std::string > &v)
Split string references using a single delimiter.
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
std::string lowercase(std::string s)
Return a lowercase version for a given string.
#define ASSERT(f)
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32
void stripZeroEntries(std::vector< std::string > &s)
unsigned int parseCompositionData(const std::vector< std::string > &s, const AbundanceData &atomTable, std::map< unsigned int, double > &atomData)
Convert atomic string label data, in the form "Fe 0.81" to fraction map.