48 const std::vector<IonHit> &hits,
float (*backgroundEstimator)(
float,
float),
49 std::vector<std::pair<unsigned int,float> > &decomposedHits,
float rangeTolerance)
53 !rangeData.
getNumRanges() || hits.empty() || rangeTolerance < 0)
57 vector<MultiRange> decomposedRanges;
63 if(decomposedRanges.empty())
66 vector<vector<float> > solutions;
67 vector<vector<unsigned int> > solvedIonIds;
68 vector<float> residuals;
70 for(
const auto &mRng : decomposedRanges)
73 std::vector<FLATTENED_RANGE> flatRange;
74 mRng.flattenToMassAxis(flatRange);
77 vector<unsigned int> containedIonIds;
78 containedIonIds.clear();
80 std::set<unsigned int> idSet;
81 for(
const auto &e : flatRange)
84 for(
const auto id : e.containedIonIDs)
89 containedIonIds.assign(idSet.begin(),idSet.end());
96 m=gsl_matrix_alloc(flatRange.size(),containedIonIds.size());
97 gsl_matrix_set_zero(m);
101 for(
auto ui=0u; ui< containedIonIds.size();ui++)
103 std::set<SIMPLE_SPECIES> ss;
104 ss = mRng.getMolecule(containedIonIds[ui]);
105 vector<size_t> elemIdx,frequency;
107 elemIdx.clear(); frequency.clear();
108 for(
const auto &mol : ss)
110 frequency.push_back(mol.count);
115 if(elemIdx.back() == -1)
120 for(
auto uj=0u; uj< flatRange.size();uj++)
124 flatRange[uj].startMass,flatRange[uj].endMass);
125 gsl_matrix_set(m,uj,ui,thisAbundance);
136 if(rank < mRng.getNumIons())
140 b=gsl_vector_alloc(flatRange.size());
142 vector<unsigned int> counts;
143 counts.resize(flatRange.size());
146 for(
auto uj=0;uj<flatRange.size();uj++)
148 if(flatRange[uj].startMass < h.getMassToCharge()
149 && flatRange[uj].endMass> h.getMassToCharge())
158 if(backgroundEstimator)
160 vector<float> background;
161 background.resize(counts.size(),0);
162 for(
auto ui=0;ui<flatRange.size();ui++)
164 background[ui]=(*backgroundEstimator)(
165 flatRange[ui].startMass,flatRange[ui].endMass);
169 for(
auto ui=0;ui<counts.size();ui++)
170 gsl_vector_set(b,ui,counts[ui]-background[ui]);
174 for(
auto ui=0;ui<counts.size();ui++)
175 gsl_vector_set(b,ui,counts[ui]);
182 x=gsl_vector_alloc(mRng.getNumIons());
188 soln.resize(x->size);
189 for(
auto ui=0;ui<x->size;ui++)
190 soln[ui]=x->data[ui];
192 solutions.push_back(soln);
195 solvedIonIds.push_back(containedIonIds);
205 map<unsigned int,float> decomposeMap;
206 ASSERT(solutions.size() == solvedIonIds.size());
207 for(
auto ui=0;ui<solvedIonIds.size();ui++)
209 ASSERT(solutions[ui].size() == solvedIonIds[ui].size());
210 for(
auto uj=0;uj<solvedIonIds[ui].size();uj++)
212 auto it =decomposeMap.find(solvedIonIds[ui][uj]);
214 if( it == decomposeMap.end())
215 decomposeMap[solvedIonIds[ui][uj]] = solutions[ui][uj];
217 it->second+=solutions[ui][uj];
221 for(
auto &v : decomposeMap)
223 decomposedHits.push_back(std::make_pair(v.first,v.second));
232 const unsigned int numIron,
233 const unsigned int numNickel,
234 vector<ISOTOPE_ENTRY> entriesFe, vector<ISOTOPE_ENTRY> &entriesNi,
235 vector<float> ironCDF, vector<float> &nickelCDF,
236 vector<float> &feCounts, vector<float> &niCounts)
243 unsigned int actualFeCount=0,actualNiCount=0;
244 for(
auto ui=0;ui<numIron;ui++)
247 r=gsl_rng_uniform(rng);
249 unsigned int atom=-1;
250 for(
auto uj=0;uj < ironCDF.size();uj++)
259 if(atom == (
unsigned int) -1)
261 ions.push_back(
IonHit(0,0,0,entriesFe[atom].mass));
266 for(
auto ui=0;ui<numNickel;ui++)
269 r=gsl_rng_uniform(rng);
271 unsigned int atom=-1;
272 for(
auto uj=0;uj < nickelCDF.size();uj++)
274 if(r <=nickelCDF[uj])
281 if(atom == (
unsigned int) -1)
283 ions.push_back(
IonHit(0,0,0,entriesNi[atom].mass));
288 vector<pair<unsigned int,float> > decomposedResults;
290 ions,
nullptr,decomposedResults,0.05))
295 ASSERT(decomposedResults.size() ==2);
297 for(
auto &v : decomposedResults)
302 feCounts.push_back(v.second);
303 else if(name ==
"Ni")
304 niCounts.push_back(v.second);
312 bool testDeconvolve()
325 auto ionIdFe=mRng.
addIon(ss,
"Fe",col);
330 auto ionIdNi=mRng.
addIon(ss,
"Ni",col);
334 auto errCode=natTable.
open(
"../data/naturalAbundance.xml");
338 WARN(
false,
"Unable to read abundance table. Skipping test");
343 const unsigned int NUM_IRON =100;
344 const unsigned int NUM_NICKEL=200;
345 vector<float> ironCDF,nickelCDF;
347 unsigned int ironIdx,nickelIdx;
351 ASSERT(ironIdx != (
unsigned int) -1);
352 ASSERT(nickelIdx != (
unsigned int) -1);
354 vector<ISOTOPE_ENTRY> entriesFe = natTable.
isotopes(ironIdx);
355 vector<ISOTOPE_ENTRY> entriesNi = natTable.
isotopes(nickelIdx);
357 vector<unsigned int> rangeGrouping;
360 const float MASSTOL =0.1;
362 for(
auto v: entriesFe)
365 ironCDF.push_back(accum);
366 mRng.
addRange(v.mass-MASSTOL,v.mass+MASSTOL,ionIdFe);
368 rangeGrouping.push_back(0);
373 for(
auto v: entriesNi)
376 nickelCDF.push_back(accum);
377 mRng.
addRange(v.mass-MASSTOL,v.mass+MASSTOL,ionIdNi);
378 rangeGrouping.push_back(1);
381 ASSERT( (ironCDF.back() <= 1.0f) );
382 ASSERT( (nickelCDF.back() <= 1.0f) );
389 vector<float> counts[2];
392 const unsigned int NTRIALS=100;
393 for(
auto ui=0;ui<NTRIALS;ui++)
395 runFe_Ni_Sim(mRng,natTable,NUM_IRON,NUM_NICKEL,
396 entriesFe,entriesNi,ironCDF, nickelCDF, counts[0],counts[1]);
404 float errFe=fabs(meanFe-NUM_IRON)/(float)NUM_IRON ;
405 float errNi=fabs(meanNi-NUM_NICKEL)/(float)NUM_NICKEL;
unsigned int atomicNumber
Number of protons (element number)
size_t symbolIndex(const char *symbol, bool caseSensitive=true) const
Return the element's position in table, starting from 0.
Data holder for colour as float.
bool solveLeastSquares(gsl_matrix *m, gsl_vector *b, gsl_vector *&x)
Use an SVD based least-squares solver to solve Mx=b (for x).
unsigned int addRange(float start, float end, unsigned int ionID)
Add a range to the rangefile. Returns ID number of added range if adding successful, (unsigned int)-1 otherwise.
std::string getIonName(unsigned int ionID) const
Get the name of a specified ionID.
unsigned int addIon(const std::set< SIMPLE_SPECIES > &molecule, const std::string &name, const RGBf &ionCol)
Add the ion to the database returns ion ID if successful, -1 otherwise.
void meanAndStdev(const std::vector< T > &f, float &meanVal, float &stdevVal, bool normalCorrection=true)
float abundanceBetweenLimits(const std::vector< size_t > &elemIdx, const std::vector< size_t > &frequency, float massStart, float massEnd) const
Obtain the fractional abundance between two limits for the given species [start,end) ...
Data storage and retrieval class for "ranging" a spectra, where overlapping ranges are permitted...
float nullBackground(float rangeStart, float rangeEnd)
unsigned int getNumRanges() const
Get the number of unique ranges.
void setRangeGroups(const std::vector< unsigned int > &groups)
Set the groupings for the ranges : this is used when splitting overlapping ranges.
void splitOverlapping(std::vector< MultiRange > &decomposedRanges, float massTolerance=0) const
size_t open(const char *file, bool strict=false)
Attempt to open the abundance data file, return 0 on success, nonzero on failure. ...
Class to load abundance information for natural isotopes.
unsigned int getNumIons() const
Get the number of unique ions.
const std::vector< ISOTOPE_ENTRY > & isotopes(size_t offset) const
Return the isotope at a given position in the table. Offset must exist.
This is a data holding class for POS file ions, from.
unsigned int count
Number of copies of this isotope.
unsigned int estimateRank(const gsl_matrix *m, float tolerance=sqrt(std::numeric_limits< float >::epsilon()))
Estimate the rank of the given matrix.
gsl_rng * getRng() const
Obtain a GSL random number generator.
size_t symbolIdxFromAtomicNumber(size_t atomicNumber) const
Return the symbol index (offset in vector) for the given atomic number, -1 if it cannot be found...
bool leastSquaresOverlapSolve(const AtomProbe::MultiRange &rangeData, const AtomProbe::AbundanceData &abundance, const std::vector< IonHit > &hits, float(*backgroundEstimator)(float, float), std::vector< std::pair< unsigned int, float > > &decomposedHits, float rangeTolerance=0)
Solve overlaps using least squares for given multi-range.