libatomprobe
Library for Atom Probe Tomography (APT) computation
rangeCheck.cpp
Go to the documentation of this file.
1 /*
2  * rangeCheck.cpp : Rangefile sanity checking routines
3  * Copyright (C) 2017 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 
22 
23 #include <string>
24 #include <utility>
25 
26 using std::string;
27 using std::vector;
28 using std::pair;
29 using std::make_pair;
30 
31 namespace AtomProbe {
32 
33 //This holdes information about decomposed range information
35 {
36  bool isOK;
37 
38  string name;
39  //First is element symbol offset (eg H->0).
40  // second is multiplicity (eg H2 has value 2)
41  vector<pair<size_t,size_t> > components;
42 
43 };
44 
45 //Check to see if a value is contained within a given pair
46 bool pairContains(const pair<float,float> &p, float m)
47 {
48  ASSERT(p.first < p.second);
49  return (p.first <= m && p.second >=m);
50 }
51 
52 //returns a range "molecule" - a wrapper for decomposition of a range
53 // if an ion cannot be broken down into components (eg unknown ion), then
54 // an empty molecule is returned, with isOK=false.
56  const RangeFile &rng, unsigned int rangeId)
57 {
58  RANGE_MOLECULE mol;
59  auto ionId=rng.getIonID(rangeId);
60  mol.name=rng.getName(ionId);
61  mol.components.clear();
62  mol.isOK=true;
63 
64  //
65  size_t symbolIdx;
66  symbolIdx=massTable.symbolIndex(mol.name.c_str());
67 
68  if(symbolIdx ==(size_t)-1)
69  {
70  vector<pair<string,size_t> > namedComponent;
71  //try decomposing. If it fails, return a bad molecule
72  if(!RangeFile::decomposeIonNames(mol.name,namedComponent))
73  {
74  mol.isOK=false;
75  return mol;
76  }
77 
78  //Check decomposed elements are identifiable
79  for(size_t uj=0;uj<namedComponent.size();uj++)
80  {
81  symbolIdx=massTable.symbolIndex(namedComponent[uj].first.c_str());
82  if( symbolIdx == (size_t)-1)
83  {
84  mol.isOK=false;
85  return mol;
86  }
87 
88 
89  //Store component
90  mol.components.push_back(make_pair(symbolIdx,namedComponent[uj].second));
91  }
92  }
93  else
94  {
95  mol.components.push_back(make_pair(symbolIdx,1));
96  }
97 
98  return mol;
99 }
100 
102  float massTolerance, unsigned int maxChargeState,
103  unsigned int maxComponents,std::vector<bool> &badRanges)
104 {
105  badRanges.resize(rng.getNumRanges(),false);
106 
107  for(size_t ui=0;ui<rng.getNumRanges();ui++)
108  {
109  //Check we can decompose a range
110  RANGE_MOLECULE rngMol;
111  rngMol=getRangeMolecule(massTable,rng,ui);
112  if(rngMol.components.empty() || !rngMol.isOK)
113  continue;
114 
115  //Work out the number of atoms in the molecule
116  size_t totalComponents;
117  totalComponents=0;
118  for(size_t uk=0;uk<rngMol.components.size();uk++)
119  totalComponents+=rngMol.components[uk].second;
120 
121  //Skip check if there are too many components, that will cause
122  // problems when checking
123  if(totalComponents > maxComponents)
124  continue;
125 
126 
127  pair<float,float> thisRange;
128  thisRange=rng.getRange(ui);
129 
130  //widen range by mass
131  thisRange.first-=massTolerance;
132  thisRange.second+=massTolerance;
133 
134  //Convert rngMol to more "friendly" form for isotope distribution
135  // generation
136  vector<size_t> elements;
137  vector<size_t> composition;
138  for(size_t uj=0;uj<rngMol.components.size();uj++)
139  {
140  for(size_t uk=0;uk<rngMol.components[uj].second; uk++)
141  {
142  elements.push_back(rngMol.components[uj].first);
143  composition.push_back(1);
144  }
145  }
146 
147  //Generate isotope distribution
148  vector<pair<float,float> > isotopeDist;
149  massTable.generateIsotopeDist(elements,composition,isotopeDist);
150 
151  //The isotopeDist ranged must match a theoretical range
152  // Check each range for several differing chargestates
153  bool foundMass;
154  foundMass=false;
155  for(size_t uj=1;uj<=maxChargeState;uj++)
156  {
157  for(size_t um=0;um<isotopeDist.size();um++)
158  {
159  if(pairContains(thisRange,isotopeDist[um].first/(float)uj))
160  {
161  foundMass=true;
162  break;
163  }
164  }
165  if(foundMass)
166  break;
167  }
168 
169  //If we were not able to find an isotope that fits within
170  // the specified range, then this is an incorrect range
171  if(!foundMass)
172  badRanges[ui]=true;
173  }
174 
175 }
176 
177 
178 #ifdef DEBUG
179 bool testRangeChecking()
180 {
181  //Perform direct range-test
182  // should be no incorrectranges
183  // then add a bad range
184  AbundanceData natData;
185  if(natData.open("naturalAbundance.xml"))
186  return false;
187 
188  RangeFile rng;
189  RGBf c;
190  c.red=c.green=c.blue=1.0f;
191 
192  auto ionIdTi=rng.addIon("Ti","Ti",c);
193  auto ionIdH = rng.addIon("H","H",c);
194 
195  //Add Ranges
196  auto rngH=rng.addRange(0.95,1.05,ionIdH);
197  auto rngTi=rng.addRange(23.9,24.1,ionIdTi);
198 
199 
200  vector<bool> badRanges;
201  checkMassRangingCorrectness(rng,natData,
202  0.05,3,3,badRanges);
203 
204  TEST(badRanges.size() == 2,"Check bad range count");
205 
206  TEST((badRanges[0] == false) && (badRanges[1] == false)
207  ,"Ranges should be OK");
208 
209  //Move Ti to a bad mass
210  rng.moveBothRanges(rngTi, 17,18);
211  checkMassRangingCorrectness(rng,natData,
212  0.05,3,3,badRanges);
213  TEST((badRanges[rngH] == false) && (badRanges[rngTi] == true)
214  ,"Ranges should be wrong");
215 
216  return true;
217 }
218 #endif
219 }
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 getName(unsigned int ionID, bool shortName=true) const
Get the short name or long name of a specified ionID.
Definition: ranges.cpp:2975
unsigned int getIonID(float mass) const
Get the ion&#39;s ID from a specified mass.
Definition: ranges.cpp:2884
unsigned int addIon(const std::string &shortName, const std::string &longName, const RGBf &ionCol)
Add the ion to the database returns ion ID if successful, -1 otherwise.
Definition: ranges.cpp:3274
Data holder for colour as float.
Definition: misc.h:26
float green
Definition: misc.h:30
bool moveBothRanges(unsigned int range, float newLow, float newHigh)
Move both of a range&#39;s masses to a new location.
Definition: ranges.cpp:3197
void generateIsotopeDist(const std::vector< size_t > &elementIdx, const std::vector< size_t > &frequency, std::vector< std::pair< float, float > > &massDist) const
Compute the mass-probability distribution for the grouped set of ions.
Definition: abundance.cpp:277
static bool decomposeIonNames(const std::string &name, std::vector< std::pair< std::string, size_t > > &fragments)
Definition: ranges.cpp:121
#define TEST(f, g)
Definition: aptAssert.h:49
unsigned int getNumRanges() const
Get the number of unique ranges.
Definition: ranges.cpp:2846
vector< pair< size_t, size_t > > components
Definition: rangeCheck.cpp:41
void checkMassRangingCorrectness(const AtomProbe::RangeFile &rng, AtomProbe::AbundanceData &massTable, float massTolerance, unsigned int maxChargeState, unsigned int maxComponents, std::vector< bool > &badRanges)
Ensure that each mass given spans a peak that should exist.
Definition: rangeCheck.cpp:101
float blue
Definition: misc.h:31
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
bool pairContains(const pair< float, float > &p, float m)
Definition: rangeCheck.cpp:46
#define ASSERT(f)
Data storage and retrieval class for various range files.
Definition: ranges.h:95
RANGE_MOLECULE getRangeMolecule(const AbundanceData &massTable, const RangeFile &rng, unsigned int rangeId)
Definition: rangeCheck.cpp:55
float red
Definition: misc.h:29
unsigned int addRange(float start, float end, unsigned int ionID)
Add a range to the rangefile. Returns ID number of added range.
Definition: ranges.cpp:3235
std::pair< float, float > getRange(unsigned int) const
Retrieve the start and end of a given range as a pair(start,end)
Definition: ranges.cpp:2868