libatomprobe
Library for Atom Probe Tomography (APT) computation
ion.cpp
Go to the documentation of this file.
1 /* ion.h : atomic and molecular ion primitive
2  * Copyright (C) 2014 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 
19 #include "atomprobe/primitives/ion.h"
20 #include "atomprobe/helper/misc.h"
21 
22 #include <set>
23 #include <map>
24 #include <cctype>
25 #include <vector>
26 #include <cstring>
27 #include <utility>
28 #include <fstream>
29 
30 using std::string;
31 using std::vector;
32 using std::pair;
33 using std::make_pair;
34 using std::string;
35 
36 namespace AtomProbe{
37 
46 Ion::Ion(const std::string &strName) {
48  std::vector<std::pair<std::string,size_t> > ionFragments;
49  ionStr2ionFragments(strName, ionFragments);
50  setIonFragments(ionFragments);
51 }
52 
54 Ion::Ion(const std::string &strName, const unsigned int chargeState) {
55  std::vector<std::pair<std::string,size_t> > ionFragments;
56  ionStr2ionFragments(strName, ionFragments);
57  setIonFragments(ionFragments);
58  setChargeState(chargeState);
59 }
60 
63 bool Ion::ionStr2ionFragments(const std::string &name,
64  std::vector<pair<string,size_t> > &fragments)
65 {
66  // Take a string and turn it into an ion class
67  // str could have charge state (+ char) or not
68  // Parse text and turn it into elemental fragments
69  size_t lastMarker=0;
70  size_t digitMarker=0;
71 
72  if(!name.size())
73  return true;
74 
75  //Atomic naming systems use uppercase ascii
76  // letters, like "A" in Au, or Ag as delimiters.
77  //
78  // numerals are multipliers, and are forbidden
79  // for the first char...
80  if(!isalnum(name[0]) ||
81  isdigit(name[0]) || islower(name[0]))
82  return false;
83 
84  //true - was last, or now am on ion name
85  //false - am still on multiplier
86  bool nameMode=true;
87  for(size_t ui=1;ui<name.size();ui++)
88  {
89  if(!isalnum(name[ui]))
90  return false;
91 
92  if(nameMode)
93  {
94  //If we hit a digit,
95  //this means that we
96  //are now on a multiplier
97  if(isdigit(name[ui]))
98  {
99  digitMarker=ui;
100  nameMode=false;
101  continue;
102  }
103 
104  if(isupper(name[ui]))
105  {
106  //Looks like we hit another
107  // ion name, without hitting any
108  // specification for the number.
109  // This means unitary spec.
110  std::string s;
111  s=name.substr(lastMarker,ui-lastMarker);
112  fragments.push_back(make_pair(s,1));
113  lastMarker=ui;
114  }
115  }
116  else
117  {
118  //OK, we still have a digit.
119  // keep moving
120  if(isdigit(name[ui]))
121  continue;
122 
123  if(isalpha(name[ui]))
124  {
125  //OK, this looks like a new ion
126  //but we need to record multiplicity
127  std::string s,sDigit;
128  s=name.substr(lastMarker,digitMarker-lastMarker);
129 
130  sDigit=name.substr(digitMarker,ui-digitMarker);
131 
132  size_t multiplicity;
133  stream_cast(multiplicity,sDigit);
134 
135  fragments.push_back(make_pair(s,multiplicity));
136 
137  lastMarker=ui;
138  nameMode=true;
139  }
140 
141  }
142  }
143 
144  if(nameMode)
145  {
146  //Hit end of string.
147  //record fragment
148  std::string s;
149  s=name.substr(lastMarker,name.size()-lastMarker);
150  fragments.push_back(make_pair(s,1));
151  }
152  else
153  {
154  std::string s,sDigit;
155  s=name.substr(lastMarker,digitMarker-lastMarker);
156  sDigit=name.substr(digitMarker,name.size()-digitMarker);
157 
158  size_t multiplicity;
159  stream_cast(multiplicity,sDigit);
160 
161  fragments.push_back(make_pair(s,multiplicity));
162  }
163 
164 
165  //Spin through dataset and collect the non-unique fragment
166  vector<bool> toKill(fragments.size(),false);
167  for(size_t ui=0;ui<fragments.size();ui++)
168  {
169  //skip empty fragments
170  if(fragments[ui].first.empty())
171  continue;
172 
173  for(size_t uj=ui+1;uj<fragments.size();uj++)
174  {
175  //skip empty fragments
176  if(fragments[uj].first.empty())
177  continue;
178 
179  //Collect fragment multiplicities if they have the same name
180  if(fragments[uj].first == fragments[ui].first)
181  {
182  fragments[ui].second+=fragments[uj].second;
183  fragments[uj].first=""; //Zero out name so we don't hit it
184 
185  toKill[uj]=true;
186 
187  }
188  }
189  }
190 
191  vectorMultiErase(fragments,toKill);
192 
193  return true;
194 }
195 
197 bool Ion::ionFragments2ionStr(const std::vector<pair<string,size_t> > &fragments,
198  std::string &name)
199 {
200  for (auto frag:fragments){
201  if ((frag).second == 1) {
202  name += (frag).first; // element name only
203  } else {
204  // name and how many of the element there are
205  name += (frag).first + std::to_string((frag).second);
206  }
207  }
208  return true;
209 }
210 
211 } // namespace AtomProbe
void vectorMultiErase(std::vector< T > &vec, const std::vector< bool > &wantKill)
Remove elements from the vector, without preserving order.
Definition: misc.h:112
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32