43 using std::accumulate;
48 bool RangeFile::enforceConsistency =false ;
64 "H",
"He",
"Li",
"Be",
"B",
"C",
"N",
"O",
"F",
"Ne",
66 "Na",
"Mg",
"Al",
"Si",
"P",
"S",
"Cl",
"Ar",
68 "K",
"Ca",
"Sc",
"Ti",
"V",
"Cr",
"Mn",
"Fe",
"Co",
"Ni",
69 "Cu",
"Zn",
"Ga",
"Ge",
"As",
"Se",
"Br",
"Kr",
71 "Rb",
"Sr",
"Y",
"Zr",
"Nb",
"Mo",
"Tc",
"Ru",
"Rh",
"Pd",
72 "Ag",
"Cd",
"In",
"Sn",
"Sb",
"Te",
"I",
"Xe",
74 "Cs",
"Ba",
"La",
"Ce",
"Pr",
"Nd",
"Pm",
"Sm",
"Eu",
"Gd",
75 "Tb",
"Dy",
"Ho",
"Er",
"Tm",
"Yb",
"Lu",
"Hf",
"Ta",
76 "W",
"Re",
"Os",
"Ir",
"Pt",
"Au",
"Hg",
"Tl",
"Pb",
77 "Bi",
"Po",
"At",
"Rn",
79 "Fr",
"Ra",
"Ac",
"Th",
"Pa",
"U",
"Np",
"Pu",
"Am",
"Cm",
80 "Bk",
"Cf",
"Es",
"Fm",
"Md",
"No",
"Lr",
"Rf",
"Db",
81 "Sg",
"Bh",
"Hs",
"Mt",
"Ds",
"Rg",
"Cn",
"Uut",
"Fl",
82 "Uup",
"Lv",
"Uus",
"Uuo",
"" 89 if (!isupper(symbol[0]))
96 }
else if (symbol.size()==1) {
102 for(
size_t ui=1;ui<symbol.size();ui++)
104 if (!islower(symbol[ui]))
117 return string(
"(") + tmp + string(
",") + tmp2 + string(
")");
122 std::vector<pair<string,size_t> > &fragments)
125 size_t digitMarker=0;
135 if(!isascii(name[0]) ||
136 isdigit(name[0]) || islower(name[0]))
142 for(
auto ui=1;ui<name.size();ui++)
144 if(!isascii(name[ui]))
152 if(isdigit(name[ui]))
159 if(isupper(name[ui]))
166 s=name.substr(lastMarker,ui-lastMarker);
167 fragments.emplace_back(s,1);
175 if(isdigit(name[ui]))
178 if(isalpha(name[ui]))
182 std::string s,sDigit;
183 s=name.substr(lastMarker,digitMarker-lastMarker);
185 sDigit=name.substr(digitMarker,ui-digitMarker);
190 fragments.emplace_back(s,multiplicity);
204 s=name.substr(lastMarker,name.size()-lastMarker);
205 fragments.emplace_back(s,1);
209 std::string s,sDigit;
210 s=name.substr(lastMarker,digitMarker-lastMarker);
211 sDigit=name.substr(digitMarker,name.size()-digitMarker);
216 fragments.emplace_back(s,multiplicity);
221 vector<bool> toKill(fragments.size(),
false);
222 for(
auto ui=0u;ui<fragments.size();ui++)
225 if(fragments[ui].first.empty())
228 for(
auto uj=ui+1;uj<fragments.size();uj++)
231 if(fragments[uj].first.empty())
235 if(fragments[uj].first == fragments[ui].first)
237 fragments[ui].second+=fragments[uj].second;
238 fragments[uj].first=
"";
266 std::vector<std::pair<std::string,size_t> > ionFrags;
271 for(
auto& p:ionFrags) {
272 formula[p.first] = p.second;
280 std::string RangeFile::envDropChargeState(
const std::string &strName)
282 std::string res=strName;
283 if(strName[strName.size()-1] ==
'+')
285 size_t chargeStateOffset;
286 chargeStateOffset=strName.find_last_of(
"_");
287 if(chargeStateOffset != std::string::npos)
288 res=strName.substr(0,chargeStateOffset);
299 const vector<pair<string,size_t> > &namesToFind,
size_t &matchOffset)
302 std::vector<vector<pair<string,size_t> > > fragmentVec;
307 fragmentVec.reserve(composedNames.size());
308 for(
const auto & composedName : composedNames)
310 vector<pair<string,size_t> > frags;
315 fragmentVec.push_back(frags);
332 vector<bool> excludedMatch;
333 excludedMatch.resize(fragmentVec.size(),
false);
335 for(
size_t uj=0;uj<namesToFind.size();uj++)
337 pair<string,size_t> curFrag;
338 curFrag=namesToFind[uj];
339 for(
size_t ui=0;ui<fragmentVec.size();ui++)
342 if(excludedMatch[ui])
347 if(std::find(fragmentVec[ui].begin(),
348 fragmentVec[ui].end(),curFrag) == fragmentVec[ui].end())
349 excludedMatch[ui]=
true;
357 for(
size_t ui=0;ui<fragmentVec.size();ui++)
359 if(!excludedMatch[ui])
366 for(
size_t uj=0;uj<fragmentVec[ui].size();uj++)
368 if(std::find(namesToFind.begin(),
369 namesToFind.end(),fragmentVec[ui][uj]) ==
381 if(matchOffset !=(
size_t)-1)
395 unsigned int mapOffset=0;
396 for(
const auto & composedName : composedNames)
399 if(matchOffset==mapOffset)
402 matchOffset=composedName.second;
410 return (matchOffset !=(
size_t) - 1);
427 ionNames=oth.ionNames;
428 ionFormulas=oth.ionFormulas;
432 rangeVolumes=oth.rangeVolumes;
434 enforceConsistency=oth.enforceConsistency;
435 errState=oth.errState;
436 warnMessages=oth.warnMessages;
445 ASSERT(colours.size() == ionNames.size());
452 f << ionNames.size() <<
" " ;
453 f << ranges.size() << std::endl;
456 for(
unsigned int ui=0;ui<ionNames.size() ; ui++)
458 f << ionNames[ui].second<< std::endl;
459 f << ionNames[ui].first <<
" " << colours[ui].red <<
" " << colours[ui].green <<
" " << colours[ui].blue << std::endl;
465 for(
const auto & ionName : ionNames)
467 f <<
" " << ionName.first;
472 for(
unsigned int ui=0;ui<ranges.size() ; ui++)
474 f <<
". " << ranges[ui].first <<
" " << ranges[ui].second ;
477 for(
unsigned int uj=0;uj<ionNames.size(); uj++)
493 f <<
"#" <<
" From libatomprobe" <<std::endl;
496 f << ionNames.size() <<
" " ;
497 f << ranges.size() << std::endl;
500 for(
unsigned int ui=0;ui<ionNames.size() ; ui++)
502 f << ionNames[ui].first <<
" " << colours[ui].red <<
" " << colours[ui].green <<
" " << colours[ui].blue << std::endl;
505 for(
unsigned int ui=0;ui<ranges.size() ; ui++)
507 f << ionNames[ionIDs[ui]].first <<
" " << ranges[ui].first
508 <<
" " << ranges[ui].second <<
" 1.0 1.0" << std::endl;
516 set<string> elementSet;
520 while(strlen(elementList[offset]))
522 elementSet.insert(elementList[offset]);
528 f <<
"[Ions]" << endl;
529 f <<
"Number=" << ionNames.size() << endl;
531 for(
auto ui=0;ui<ionNames.size();ui++)
533 f <<
"Ion" << ui+1 <<
"=" << ionNames[ui].first << endl;
537 f <<
"[Ranges] " << endl;
538 f <<
"Number=" << ranges.size() << endl;
542 for(
auto ui=0u;ui<ranges.size();ui++)
545 std::string colString = col.
toHex();
546 for (
auto & c: colString) c = toupper(c);
549 colString=colString.substr(1);
550 ASSERT(colString.size() == 6);
553 f <<
"Range" << ui+1 <<
"=";
554 f << ranges[ui].first <<
" " << ranges[ui].second <<
" ";
557 if(rangeVolumes.size())
558 f <<
"Vol:" << rangeVolumes[ui];
563 strName=ionNames[ionIDs[ui]].first;
565 f <<
" Name:" << strName;
566 if (ionFormulas.size())
569 for(
const auto& it : ionFormulas[ionIDs[ui]])
570 f <<
" " << it.first <<
":" << it.second;
575 f <<
" Color:" << colString << endl;
589 std::ofstream f(filename);
593 return write(f,format);
596 void RangeFile::clear()
599 warnMessages.clear();
604 rangeVolumes.clear();
614 if(fileSize > MAX_RANGEFILE_SIZE)
618 fpRange=fopen(rangeFilename,
"r");
633 errCode=openRNG(fpRange);
640 errCode=openENV(fpRange);
646 errCode=openRRNG(fpRange);
650 errCode=openDoubleRNG(fpRange);
682 unsigned int assumedFileFormat;
687 if(!
openFormat(rangeFilename,assumedFileFormat))
691 unsigned int errStateRestore;
692 errStateRestore=errState;
699 if(ui == assumedFileFormat)
712 errState=errStateRestore;
719 unsigned int RangeFile::openDoubleRNG(FILE *fpRange)
730 unsigned int errCode;
731 errCode=tmpRange[0].openRNG(fpRange);
741 ret=fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange);
743 while(ret && strlen(ret) < MAX_LINE_SIZE-1 && ret[0] !=
'-')
745 ret=fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange);
748 if(!ret || strlen(ret) >= MAX_LINE_SIZE -1)
755 errCode=tmpRange[1].openRNG(fpRange);
766 vector< pair<size_t,size_t> > rangeMatches;
768 vector<size_t> overrideIonID;
775 rangeMatches.emplace_back(ui,uj);
776 overrideIonID.push_back(tmpRange[0].
getIonID((
unsigned int)ui));
783 tmpRange[0].ionNames.swap(ionNames);
784 tmpRange[0].ionFormulas.swap(ionFormulas);
785 tmpRange[0].colours.swap(colours);
786 tmpRange[0].ionIDs.swap(ionIDs);
787 tmpRange[0].ranges.swap(ranges);
792 vector<size_t> uniqItems=overrideIonID;
793 std::sort(uniqItems.begin(),uniqItems.end());
795 if(std::unique(uniqItems.begin(),uniqItems.end()) != uniqItems.end())
803 for(
auto ui=0;ui<overrideIonID.size();ui++)
806 ids[0]=overrideIonID[ui];
807 ids[1] = tmpRange[1].
getIonID((
unsigned int)rangeMatches[ui].second);
809 ionNames[ids[0]] = tmpRange[1].ionNames[ids[1]];
810 colours[ids[0]] = tmpRange[1].colours[ids[1]];
811 if(ionFormulas.size())
812 ionFormulas[ids[0]] = tmpRange[1].ionFormulas[ids[1]];
822 unsigned int RangeFile::openRNG( FILE *fpRange)
830 unsigned int errCode;
832 unsigned int numRanges;
833 unsigned int numIons;
836 if((errCode=readRNGHeader(fpRange, ionNames, colours, numRanges,numIons)))
842 ret=fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange);
843 if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
849 ret=fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange);
851 if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
858 if(inBuffer[0] !=
'-')
866 vector<string> colHeaders;
867 vector<unsigned int > frequencyEntries;
870 vector<string> warnings;
871 vector<pair<float,float> > massData;
872 errCode=readRNGFreqTable(fpRange,inBuffer,numIons,numRanges,ionNames,
873 colHeaders, frequencyEntries,massData,warnings);
880 warnings.swap(warnMessages);
881 ranges.swap(massData);
918 std::map<string,size_t> composeMap;
920 for(
auto uj=0u;uj<numIons;uj++)
924 for(
auto ui=0u; ui<numRanges;ui++)
928 if(frequencyEntries[numIons*ui + uj])
939 composeMap.insert(make_pair(ionNames[uj].first,uj));
945 std::vector<pair<size_t, map<size_t,size_t > > > unassignedMultiples;
949 for(
auto ui=0u;ui<numRanges;ui++)
951 std::map<size_t,size_t > freqEntries;
959 for(
auto uj=0u;uj<numIons;uj++)
962 thisEntry=frequencyEntries[numIons*ui+uj];
968 freqEntries.insert(make_pair(uj,thisEntry));
976 ASSERT(freqEntries.size() == 1);
977 ionIDs.push_back( freqEntries.begin()->first);
981 if(composeMap.empty())
983 if(enforceConsistency)
988 unassignedMultiples.emplace_back(ui,freqEntries);
989 ionIDs.push_back(-2);
997 vector<pair<string,size_t> > entries;
999 for(map<size_t,size_t>::iterator it=freqEntries.begin();it!=freqEntries.end();++it)
1000 entries.push_back(make_pair(ionNames[it->first].first,it->second));
1020 ASSERT(offset < ionNames.size());
1021 ionIDs.push_back( offset);
1031 if(enforceConsistency)
1033 ionIDs.push_back(-1);
1040 if(unassignedMultiples.size())
1046 map<string,vector<int> > newNames;
1048 for(
auto ui=0u;ui<unassignedMultiples.size();ui++)
1055 vector<pair<size_t,size_t> > flatData;
1057 std::map<size_t,size_t> &m=unassignedMultiples[ui].second;
1058 for(
const auto &i : m )
1059 flatData.emplace_back(i.first,i.second);
1060 std::sort(flatData.begin(),flatData.end(),cmp);
1063 for(
auto uj=0u;uj<flatData.size();uj++)
1069 nameStr+=ionNames[flatData[uj].first].first + tmpStr;
1073 newNames[nameStr].push_back(unassignedMultiples[ui].first);
1080 for(map<
string,vector<int> >::iterator it=newNames.begin(); it!=newNames.end();++it)
1082 for(
auto ui=0u;ui<it->second.size();ui++)
1084 ASSERT(ionIDs[it->second[ui]] == (
unsigned int)-2);
1085 ionIDs[it->second[ui]] =ionNames.size();
1087 ionNames.emplace_back(it->first,it->first);
1090 col.
red=rand()/(float)std::numeric_limits<int>::max();
1091 col.
green=rand()/(float)std::numeric_limits<int>::max();
1092 col.
blue=rand()/(float)std::numeric_limits<int>::max();
1094 colours.push_back(col);
1100 for(
auto ui=ionIDs.size()-1;ui--;)
1102 if(ionIDs[ui] == (
unsigned int)-1)
1104 std::swap(ranges[ui],ranges.back());
1107 std::swap(ionIDs[ui],ionIDs.back());
1120 STATUS_NOT_CHECKED=0,
1125 #if !defined(__WIN32__) && !defined(__WIN64) 1138 std::ifstream f(rangeFile);
1152 vector<string> strs;
1158 if( strs.size() != 2)
1163 goto skipoutRNGChecks;
1167 size_t nIons,nRanges;
1172 if( castRes[0] || castRes[1])
1177 goto skipoutRNGChecks;
1192 if(f.eof() || (!f.good()) )
1199 if(!tmpStr.size() || tmpStr[0] !=
'-')
1203 goto skipoutRNGChecks;
1208 while( ! (f.eof() || f.bad()) )
1210 if(!getline(f,tmpStr))
1213 if(tmpStr.size() > 2 &&
1214 tmpStr[0] ==
'-' && tmpStr[1] ==
'-')
1238 std::ifstream f(rangeFile);
1244 std::vector<string> sections;
1245 sections.emplace_back(
"[ions]");
1246 sections.emplace_back(
"[ranges]");
1248 vector<bool> haveSection(sections.size(),
false);
1250 bool foundAllSections=
false;
1253 while((!f.eof()) &&f.good())
1262 for(
auto ui=0u;ui<sections.size();ui++)
1266 haveSection[ui]=
true;
1269 if(std::find(haveSection.begin(),haveSection.end(),
false)
1270 == haveSection.end())
1271 foundAllSections=
true;
1277 if(foundAllSections)
1281 if(foundAllSections)
1302 f=fopen(rangeFile,
"r");
1304 if(!f || tmpRng.openENV(f))
1320 if((
size_t)std::count(typeStatus.begin(),typeStatus.end(),(
unsigned int)STATUS_IS_NOT) == typeStatus.size()-1)
1324 for(
auto ui=0u;ui<typeStatus.size();ui++)
1326 if(typeStatus[ui]==STATUS_IS_MAYBE)
1344 const char *typeNames[] = {
"RNG - ORNL style",
1345 "RNG - ORNL Style - with polyatomic extension",
1346 "ENV - Cameca environment",
1347 "RRNG - Imago/Cameca \"RRNG\"" 1351 return typeNames[type];
1356 unsigned int RangeFile::readRNGHeader(FILE *fpRange, vector<pair<string,string> > &strNames,
1357 vector<RGBf> &fileColours,
unsigned int &numRanges,
unsigned int &numIons)
1363 if(fscanf(fpRange,
"%64u %64u", &numIons, &numRanges) != 2)
1370 if (!(numIons && numRanges))
1378 pair<string,string> namePair;
1380 for(
unsigned int i=0; i<numIons; i++)
1386 if(
fpeek(fpRange)==
' ')
1392 if(fgetc(fpRange) == EOF)
1397 peekVal=
fpeek(fpRange);
1399 while(peekVal != (
int)
'\n'&&
1400 peekVal !=(
int)
'\r' && peekVal != EOF);
1406 if(fgetc(fpRange) == EOF)
1414 if(!fscanf(fpRange,
" %255s", inBuffer))
1420 namePair.second = inBuffer;
1424 if(!fscanf(fpRange,
" %255s", inBuffer))
1430 namePair.first= inBuffer;
1432 if(!fscanf(fpRange,
"%128f %128f %128f",&(colourStruct.
red),
1433 &(colourStruct.
green),&(colourStruct.
blue)))
1439 strNames.push_back(namePair);
1440 fileColours.push_back(colourStruct);
1447 unsigned int RangeFile::readRNGFreqTable(FILE *fpRange,
char *inBuffer,
const unsigned int numIons,
1448 const unsigned int numRanges,
const vector<pair<string,string> > &names,
1449 vector<string> &colHeaders, vector<unsigned int > &tableEntries,
1450 vector<pair<float,float> > &massData, vector<string> &warnings)
1455 while(*ptrBegin ==
'-')
1458 if(!colHeaders.size() )
1462 for(
auto & colHeader : colHeaders)
1464 colHeader =
stripChars(colHeader,
"\f\n\r\t ");
1470 if(colHeaders.size() > 1)
1473 if(colHeaders.size() !=numIons)
1481 std::string str = colHeaders[colHeaders.size() -1];
1483 if(str[str.size() -1 ] ==
'\n')
1484 colHeaders[colHeaders.size()-1]=str.substr(0,str.size()-1);
1487 for(
auto ui=1u;ui<colHeaders.size();ui++)
1490 if(names[ui-1].second != colHeaders[ui])
1492 warnings.emplace_back(
"Range headings do not match order of the ions listed in the name specifications. The name specification ordering will be used when reading the range table, as the range heading section is declared as a comment in the file-format specifications, and is not to be intepreted by this program. Check range-species associations actually match what you expect.");
1500 tableEntries.resize(numRanges*numIons,0);
1502 pair<float,float> massPair;
1504 for(
unsigned int i=0; i<numRanges; i++)
1508 if(fgets(inBuffer,MAX_LINE_SIZE,fpRange) ==
nullptr)
1512 vector<string> entries;
1522 if(entries.size() != numIons + 2 &&
1523 entries.size() !=numIons+3)
1531 if(entries.size() == numIons +3)
1538 if(
stream_cast(massPair.second,entries[entryOff+1]))
1543 if(massPair.first >= massPair.second)
1548 massData.push_back(massPair);
1552 for(
unsigned int j=0; j<numIons; j++)
1561 tableEntries[numIons*i + j]=tempInt;
1573 size_t nMax=std::accumulate(tableEntries.begin(),tableEntries.end(),0);
1582 unsigned int RangeFile::openENV(FILE *fpRange)
1590 unsigned int numRanges;
1591 unsigned int numIons;
1593 bool beyondRanges=
false;
1594 bool haveNumRanges=
false;
1595 bool haveNameBlock=
false;
1596 bool haveSeenRevHeader=
false;
1597 vector<string> strVec;
1600 while(!beyondRanges && !feof(fpRange) )
1602 if(!fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange)
1603 || strlen(inBuffer) >=MAX_LINE_SIZE-1)
1620 if(!haveSeenRevHeader && (s==
"Rev_2.0"))
1622 haveSeenRevHeader=
true;
1634 for(
auto ui=0u;ui<strVec.size();ui++)
1637 offset=strVec[ui].find(
';');
1638 if(offset == std::string::npos)
1641 strVec[ui]=strVec[ui].substr(0,offset);
1654 if(strVec.size() != 2)
1679 if(strVec.size() == 5)
1681 else if(strVec.size() == 4)
1684 if(!strVec[0].size())
1691 strVec[0]=envDropChargeState(strVec[0]);
1695 for(
unsigned int ui=0; ui<strVec[0].size(); ui++)
1697 if(!isdigit(strVec[0][ui]) &&
1698 !isalpha(strVec[0][ui]) && strVec[0][ui] !=
'.')
1709 bool nameExists=
false;
1710 for(
auto ui=0u;ui<ionNames.size();ui++)
1712 if (ionNames[ui].first == strVec[0])
1725 ionNames.emplace_back(strVec[0],strVec[0]);
1737 if(colourStruct.
red >1.0 || colourStruct.
red < 0.0f ||
1738 colourStruct.
green >1.0 || colourStruct.
green < 0.0f ||
1739 colourStruct.
blue >1.0 || colourStruct.
blue < 0.0f )
1747 colours.push_back(colourStruct);
1762 if(strVec.size() == 5)
1764 unsigned int thisIonID;
1765 thisIonID=(
unsigned int)-1;
1766 strVec[0] = envDropChargeState(strVec[0]);
1767 for(
unsigned int ui=0;ui<ionNames.size();ui++)
1769 if(strVec[0] == ionNames[ui].first)
1777 if(thisIonID==(
unsigned int) -1)
1783 float rangeStart,rangeEnd;
1796 if(rangeStart > rangeEnd)
1802 ranges.emplace_back(rangeStart,rangeEnd);
1804 ionIDs.push_back(thisIonID);
1820 if(!haveNumRanges || ! haveNameBlock)
1825 if(ionNames.empty() || ionNames.size() > numIons || ranges.size() > numRanges)
1838 unsigned int RangeFile::openRRNG(FILE *fpRange)
1843 unsigned int numRanges;
1844 unsigned int numBasicIons;
1854 unsigned int curBlock=BLOCK_NONE;
1855 bool haveSeenIonBlock;
1856 haveSeenIonBlock=
false;
1857 bool haveSeenVolumes=
false;
1860 vector<string> basicIonNames;
1862 while (!feof(fpRange))
1864 if(!fgets((
char *)inBuffer, MAX_LINE_SIZE, fpRange)
1865 || strlen(inBuffer) >=MAX_LINE_SIZE-1)
1879 curBlock=BLOCK_IONS;
1884 curBlock=BLOCK_RANGES;
1901 vector<string> split;
1904 if (split.size() != 2)
1913 haveSeenIonBlock=
true;
1916 if (stmp ==
"number")
1920 if (numBasicIons !=0)
1932 if (numBasicIons == 0)
1938 else if (split[0].size() >3)
1944 basicIonNames.push_back(split[1]);
1946 if (basicIonNames.size() > numBasicIons)
1966 if (!haveSeenIonBlock)
1971 vector<string> split;
1977 if (split.size() != 2)
1983 if (
lowercase(split[0].substr(0,5)) ==
"numbe")
2007 else if (
lowercase(split[0].substr(0,5)) ==
"range")
2036 string rngStart,rngEnd;
2044 if(split.size() < 4)
2052 split.erase(split.begin());
2053 split.erase(split.begin());
2057 bool haveColour,haveNameField;
2059 haveNameField=
false;
2060 string strIonNameTmp,strNameFieldValue;
2062 map<string,size_t> tmpFormula;
2064 for (
unsigned int ui=0; ui<split.size(); ui++)
2070 colonPos = split[ui].find_first_of(
':');
2072 if (colonPos == std::string::npos)
2080 key=split[ui].substr(0,colonPos);
2081 value=split[ui].substr(colonPos+1);
2087 if(!rangeVolumes.size())
2088 rangeVolumes.resize(numRanges,0);
2118 strNameFieldValue=value;
2125 if (value.size() !=6)
2135 unsigned char r,g,b,a;
2143 col.
red = (float)r/255.0f;
2144 col.
green=(float)g/255.0f;
2145 col.
blue=(float)b/255.0f;
2149 vector<string> commaSplit;
2152 if(commaSplit.size() >1)
2158 map<string, unsigned int> uniqMap;
2160 for(
const auto str : commaSplit)
2163 if(std::find(basicIonNames.begin(),basicIonNames.end(),str) == basicIonNames.end())
2168 auto it=uniqMap.find(str);
2169 if( it == uniqMap.end())
2170 uniqMap.insert(make_pair(str,1));
2181 for (
auto &entry : uniqMap)
2184 strIonNameTmp+=entry.first;
2187 if(entry.second > 1)
2192 strIonNameTmp+=tmpStr;
2194 else if (entry.second <=0)
2203 unsigned int pos=(
unsigned int)-1;
2204 for (
unsigned int uj=0; uj<basicIonNames.size(); uj++)
2206 if (basicIonNames[uj] == key)
2213 if (pos == (
unsigned int)-1)
2219 unsigned int uintVal;
2227 tmpFormula[key]=uintVal;
2237 col.
red=rand()/(float)std::numeric_limits<int>::max();
2238 col.
green=rand()/(float)std::numeric_limits<int>::max();
2239 col.
blue=rand()/(float)std::numeric_limits<int>::max();
2244 float rngStartV,rngEndV;
2274 string strIonNameNew_long;
2281 if(!strNameFieldValue.size())
2289 unsigned int chargeStrStop=0;
2290 for(
unsigned int ui=0; ui<strNameFieldValue.size(); ui++)
2292 if(strNameFieldValue[ui] <
'0' || strNameFieldValue[ui] >
'9')
2301 strIonNameNew_long = strNameFieldValue.substr(chargeStrStop,strNameFieldValue.size()-chargeStrStop);
2303 if (strIonNameNew_long.empty())
2313 string strIonNameNew;
2314 if(strIonNameTmp.size())
2317 strIonNameNew = strIonNameTmp;
2319 if (strIonNameNew_long.empty())
2320 strIonNameNew_long = strIonNameTmp;
2322 else if(haveNameField)
2325 strIonNameNew = strIonNameNew_long;
2327 else if(tmpFormula.size())
2330 for(
const auto &v : tmpFormula)
2332 strIonNameNew += v.first;
2334 strIonNameNew+=std::to_string(v.second);
2348 unsigned int pos=(
unsigned int)(-1);
2349 for (
unsigned int ui=0; ui<ionNames.size(); ui++)
2351 if (ionNames[ui].first == strIonNameNew)
2359 ranges.push_back(std::make_pair(rngStartV,rngEndV));
2361 if (pos == (
unsigned int) -1)
2363 ionIDs.push_back(ionNames.size());
2364 ionNames.push_back(make_pair(strIonNameNew,strIonNameNew_long));
2365 colours.push_back(col);
2367 if(ionFormulas.size())
2368 ionFormulas.resize(ionNames.size());
2370 if(tmpFormula.size())
2372 ionFormulas.resize(ionNames.size());
2373 ionFormulas[ionNames.size()-1]=tmpFormula;
2380 ionIDs.push_back(pos);
2400 if(!haveSeenIonBlock )
2409 if(numRanges != ranges.size())
2413 if (!haveSeenVolumes)
2414 rangeVolumes.clear();
2422 unsigned int extOff=0;
2423 while(strlen(RANGE_EXTS[extOff]))
2425 if(!strcmp(ext,RANGE_EXTS[extOff]))
2443 for(
unsigned int ui=0;ui<
ARRAYSIZE(RANGE_EXTS)-1; ui++)
2445 exts[ui]=RANGE_EXTS[ui];
2452 ASSERT(ionIDs.size() == ranges.size());
2453 ASSERT(ionIDs.empty() || *(std::max_element(ionIDs.begin(),ionIDs.end())) < ionNames.size());
2454 ASSERT(rangeVolumes.empty() || ( rangeVolumes.size() == ranges.size()) );
2456 ASSERT(colours.size() == ionNames.size());
2458 ASSERT(ionFormulas.empty() || ionFormulas.size() == ionNames.size());
2461 for(
unsigned int ui=0;ui<ranges.size();ui++)
2464 if(ranges[ui].first == ranges[ui].second)
2468 for(
unsigned int uj=ui+1; uj<ranges.size();uj++)
2471 if(ranges[ui].first > ranges[uj].first &&
2472 ranges[ui].first < ranges[uj].second )
2474 if(ranges[ui].second > ranges[uj].first &&
2475 ranges[ui].second < ranges[uj].second )
2479 if(ranges[ui].first < ranges[uj].first &&
2480 ranges[ui].second > ranges[uj].second)
2484 if(ranges[ui].first == ranges[uj].first &&
2485 ranges[ui].second == ranges[uj].second)
2493 for(
auto ui=0u;ui<ionNames.size();ui++)
2495 for(
auto uj=ui+1;uj<ionNames.size();uj++)
2497 if(ionNames[ui].first == ionNames[uj].first ||
2498 (ionNames[ui].second.size() && (ionNames[ui].second == ionNames[uj].second) ) )
2505 for(
const auto & ionName : ionNames)
2510 const char *DISALLOWED_ION_NAMES=
" \t\r\n";
2512 if(tmp.find_first_of(DISALLOWED_ION_NAMES)!= string::npos)
2516 if(tmp.find_first_of(DISALLOWED_ION_NAMES)!= string::npos)
2522 for(
size_t ui=0;ui<ionFormulas.size();ui++)
2524 for(
size_t uj=ui+1;uj<ionFormulas.size();uj++)
2526 if(ionFormulas[ui] == ionFormulas[uj])
2537 vector<bool> killRange;
2538 killRange.resize(ranges.size(),
false);
2540 for(
unsigned int ui=0;ui<ranges.size();ui++)
2543 if(ranges[ui].first == ranges[ui].second)
2550 for(
unsigned int uj=ui+1; uj<ranges.size();uj++)
2553 if(ranges[ui].first > ranges[uj].first &&
2554 ranges[ui].first < ranges[uj].second )
2559 if(ranges[ui].second > ranges[uj].first &&
2560 ranges[ui].second < ranges[uj].second )
2567 if(ranges[ui].first < ranges[uj].first &&
2568 ranges[ui].second > ranges[uj].second)
2575 if(ranges[ui].first == ranges[uj].first &&
2576 ranges[ui].second == ranges[uj].second)
2593 bool inconsistent=
false;
2595 for(
unsigned int ui=0;ui<ranges.size();ui++)
2598 if(ranges[ui].first == ranges[ui].second)
2600 msg =
"Zero width range : ";
2605 messages.push_back(msg);
2606 inconsistent =
false;
2610 for(
unsigned int uj=ui+1; uj<ranges.size();uj++)
2613 if(ranges[ui].first > ranges[uj].first &&
2614 ranges[ui].first < ranges[uj].second )
2616 msg=
"One Range (A) contains another (B) - A: ";
2621 messages.push_back(msg);
2624 if(ranges[ui].second > ranges[uj].first &&
2625 ranges[ui].second < ranges[uj].second )
2627 msg=
"One Range (A) contains another (B) - A: ";
2632 messages.push_back(msg);
2637 if(ranges[ui].first < ranges[uj].first &&
2638 ranges[ui].second > ranges[uj].second)
2640 msg=
"Ranges span one another: ";
2644 messages.push_back(msg);
2649 if(ranges[ui].first == ranges[uj].first &&
2650 ranges[ui].second == ranges[uj].second)
2652 msg=
"Duplicated range :";
2655 messages.push_back(msg);
2664 for(
size_t ui=0;ui<ionNames.size();ui++)
2666 for(
size_t uj=ui+1;uj<ionNames.size();uj++)
2668 if(ionNames[ui].first == ionNames[uj].first ||
2669 ionNames[ui].second == ionNames[uj].second)
2671 msg=
"Duplicated ion names";
2672 msg+=ionNames[ui].first;
2674 messages.push_back(msg);
2682 for(
size_t ui=0;ui<ionNames.size();ui++)
2685 tmp=ionNames[ui].first;
2687 const char *DISALLOWED_ION_NAMES=
" \t\r\n";
2689 if(tmp.find_first_of(DISALLOWED_ION_NAMES)!= string::npos)
2691 msg=
"Invalid character in short ion name, for ion ";
2694 messages.push_back(msg);
2698 tmp=ionNames[ui].second;
2699 if(tmp.find_first_of(DISALLOWED_ION_NAMES)!= string::npos)
2701 msg=
"Invalid character in long ion name, for ion ";
2704 messages.push_back(msg);
2710 return !inconsistent;
2715 unsigned int numRanges = ranges.size();
2717 for(
unsigned int ui=0; ui<numRanges; ui++)
2719 if( mass >= ranges[ui].first &&
2720 mass <= ranges[ui].second )
2734 vector<IonHit> rangedVec;
2737 unsigned int targetIonID=(
unsigned int)-1;
2738 for(
unsigned int ui=0; ui<ionNames.size(); ui++)
2740 if(ionNames[ui].first == ionShortName)
2747 if(targetIonID == (
unsigned int)(-1))
2751 vector<unsigned int> subRanges;
2752 for(
unsigned int ui=0; ui<ionIDs.size(); ui++)
2754 if(ionIDs[ui] == targetIonID)
2755 subRanges.push_back(ui);
2758 unsigned int numIons=ions.size();
2759 rangedVec.reserve(numIons);
2761 unsigned int numSubRanges = subRanges.size();
2763 for(
unsigned int ui=0; ui<numIons; ui++)
2765 for(
unsigned int uj=0; uj<numSubRanges; uj++)
2767 if( ions[ui].getMassToCharge() >= ranges[subRanges[uj]].first &&
2768 ions[ui].getMassToCharge() <= ranges[subRanges[uj]].second )
2770 rangedVec.push_back(ions[ui]);
2779 ions.swap(rangedVec);
2785 vector<IonHit> rangedVec;
2787 unsigned int numIons=ions.size();
2788 rangedVec.reserve(numIons);
2790 for(
unsigned int ui=0; ui<numIons; ui++)
2793 rangedVec.push_back(ions[ui]);
2799 ions.swap(rangedVec);
2805 vector<IonHit> rangedVec;
2807 unsigned int numIons=ions.size();
2808 rangedVec.reserve(numIons);
2810 for(
unsigned int ui=0; ui<numIons; ui++)
2813 rangedVec.push_back(ions[ui]);
2819 ions.swap(rangedVec);
2824 vector<IonHit> rangedVec;
2826 unsigned int numIons=ions.size();
2827 rangedVec.reserve(numIons);
2829 for(
unsigned int ui=0; ui<numIons; ui++)
2831 if( ions[ui].getMassToCharge() >= ranges[rangeID].first &&
2832 ions[ui].getMassToCharge() <= ranges[rangeID].second )
2834 rangedVec.push_back(ions[ui]);
2842 ions.swap(rangedVec);
2848 return ranges.size();
2854 for(
unsigned int ui=0;ui<ranges.size();ui++)
2865 return ionNames.size();
2880 ASSERT(ui < colours.size());
2886 unsigned int numRanges = ranges.size();
2888 for(
unsigned int ui=0; ui<numRanges; ui++)
2890 if( mass >= ranges[ui].first &&
2891 mass <= ranges[ui].second )
2895 return (
unsigned int)-1;
2906 unsigned int numRanges = ranges.size();
2908 for(
unsigned int ui=0; ui<numRanges; ui++)
2910 if( mass >= ranges[ui].first &&
2911 mass <= ranges[ui].second )
2915 return (
unsigned int)-1;
2920 ASSERT(range < ranges.size());
2922 return ionIDs[
range];
2930 for(
unsigned int ui=0; ui<ionNames.size(); ui++)
2932 if(ionNames[ui].first == name)
2939 for(
unsigned int ui=0; ui<ionNames.size(); ui++)
2941 if(ionNames[ui].second == name)
2946 return (
unsigned int)-1;
2952 ASSERT(ionID < ionFormulas.size());
2953 return ionFormulas[ionID];
2959 unsigned int ui =
getIonID(name.c_str(), useShortName);
2961 ASSERT(ui < ionFormulas.size());
2968 ASSERT(ionID < ionFormulas.size());
2969 if(!ionFormulas.size())
2970 ionFormulas.resize(ionNames.size());
2971 ionFormulas[ionID] = formula;
2977 ASSERT(ionID < ionNames.size());
2979 return ionNames[ionID].first;
2981 return ionNames[ionID].second;
2998 return range(ionHits,ionNames[rng].first);
3002 const vector<unsigned int> &ionID, vector<IonHit> &newIons)
const 3004 vector<unsigned int> sortedIDs;
3007 std::sort(sortedIDs.begin(),sortedIDs.end());
3010 #pragma omp parallel for 3011 for(
unsigned int ui=0;ui<ions.size();ui++)
3014 curId =
getIonID(ions[ui].getMassToCharge());
3015 if(std::binary_search(sortedIDs.begin(),sortedIDs.end(),curId))
3017 #pragma omp critical 3018 newIons.push_back(ions[ui]);
3028 for(
unsigned int ui=ionNames.size(); ui--; )
3030 if(ionNames[ui].first == shortName)
3036 for(
unsigned int ui=ionNames.size(); ui--; )
3041 str = ionNames[ui].first;
3043 if(str.size() !=shortName.size())
3048 for(
unsigned int uj=str.size(); uj--; )
3050 if(tolower(str[uj]) !=
3051 tolower(shortName[uj]))
3068 ASSERT(
id < colours.size());
3075 ionNames[id].first=newName;
3080 ionNames[id].second = newName;
3087 float &f=ranges[rangeId].first;
3108 float &f=ranges[rangeId].second;
3126 swap(ionNames,r.ionNames);
3127 swap(ionFormulas,r.ionFormulas);
3128 swap(colours,r.colours);
3129 swap(ranges,r.ranges);
3130 swap(ionIDs,r.ionIDs);
3131 swap(warnMessages,r.warnMessages);
3132 swap(errState,r.errState);
3138 if(enforceConsistency)
3144 if(newMass <= ranges[rangeId].first)
3149 if(newMass >= ranges[rangeId].second)
3155 for(
unsigned int ui=0; ui<ranges.size(); ui++)
3164 if((ranges[rangeId].first < ranges[ui].first &&
3165 newMass > ranges[ui].first))
3168 if((ranges[rangeId].first < ranges[ui].second &&
3169 newMass > ranges[ui].second))
3176 if((ranges[rangeId].second > ranges[ui].first &&
3177 newMass < ranges[ui].first))
3180 if((ranges[rangeId].second > ranges[ui].second &&
3181 newMass < ranges[ui].second))
3190 ranges[rangeId].second = newMass;
3192 ranges[rangeId].first= newMass;
3202 for(
unsigned int ui=0; ui<ranges.size(); ui++)
3209 if((ranges[rangeId].first < ranges[ui].first &&
3210 newHigh > ranges[ui].first))
3213 if((ranges[rangeId].first < ranges[ui].second &&
3214 newHigh > ranges[ui].second))
3218 if((ranges[rangeId].second > ranges[ui].first &&
3219 newLow < ranges[ui].first))
3222 if((ranges[rangeId].second > ranges[ui].second &&
3223 newLow < ranges[ui].second))
3227 ranges[rangeId].second = newHigh;
3228 ranges[rangeId].first= newLow;
3238 if(enforceConsistency)
3241 for(
auto &
range : ranges)
3244 if(start >
range.first &&
3245 start<=
range.second)
3248 if(end >
range.first &&
3253 if(start < range.first && end >
range.second)
3258 ionIDs.push_back(parentIonID);
3259 ranges.emplace_back(start,end);
3261 if(rangeVolumes.size())
3262 rangeVolumes.push_back(0);
3266 if(enforceConsistency)
3271 return ranges.size() -1;
3276 for(
auto & ionName : ionNames)
3278 if(ionName.first == shortN || ionName.second == longN)
3282 ionNames.emplace_back(shortN,longN);
3283 colours.push_back(newCol);
3285 if(ionFormulas.size())
3287 map<string,size_t> m;
3288 ionFormulas.push_back(m);
3291 return ionNames.size()-1;
3297 ASSERT(newIonId < ionIDs.size());
3298 ionIDs[
range] = newIonId;
3303 ASSERT(rangeId < ranges.size());
3304 std::swap(ranges.back(),ranges[rangeId]);
3307 std::swap(ionIDs.back(),ionIDs[rangeId]);
3310 if(rangeVolumes.size())
3312 std::swap(rangeVolumes.back(),rangeVolumes[rangeId]);
3313 rangeVolumes.pop_back();
3321 vector<bool> killRange(ranges.size(),
false);
3322 for(
auto ui=0u;ui<ionIDs.size(); ui++)
3324 if(ionIDs[ui] == ionId)
3330 if(rangeVolumes.size())
3335 ionNames.erase(ionNames.begin()+ionId);
3336 colours.erase(colours.begin()+ionId);
3337 if(ionFormulas.size())
3338 ionFormulas.erase(ionFormulas.begin()+ionId);
3341 for(
auto ui=0u;ui<ionIDs.size();ui++)
3344 ASSERT(ionIDs[ui] != ionId);
3346 if(ionIDs[ui] >ionId)
3349 ASSERT(ionIDs[ui] < ionNames.size());
3357 const char *rangeErrStrings[] =
3360 "Error interpreting file, check format, name or permissions.",
3361 "Error interpreting range file header, expecting ion count and range count, respectively.",
3362 "Range file appears to be empty, check file is a proper range file and is not empty.",
3363 "Error reading the long name for ion.",
3364 "Error reading the short name for ion.",
3365 "Error reading colour data in the file, expecting 3 decimal values, space separated.",
3366 "Tried skipping to table separator line (line with dashes), but did not find it.",
3367 "Unexpected failure whilst trying to skip over range lead-in data (bit before range start value)",
3368 "Unable to read range start and end values",
3369 "Unable to read range table entry",
3370 "Error reading file, unexpected format, are you sure it is a proper range file?",
3371 "Too many ranges appeared to have range entries with no usable data (eg, all blank)",
3372 "Range file appears to contain malformed data, check things like start and ends of m/c are not equal or flipped.",
3373 "Range file appears to be inconsistent (eg, overlapping ranges)",
3374 "No ion name mapped",
3375 "Opening of range file failed",
3376 "Unable to read range table",
3377 "Number of ions in the table header did not match the number specified at the start of the file",
3378 "Polyatomic extension range matches multiple masses in first section",
3379 "Range file is exceedingly large. Refusing to open",
3380 "Unable to read range table header (aka table separator)",
3381 "Unable to read [Ions] contents, should be of form A=B",
3382 "Unable to parse number of ions",
3383 "Number of ions seems to be duplicated",
3384 "Too many ions in ion block",
3385 "Found ranges block before ion block",
3386 "Number of ranges seems to be duplicated",
3387 "Unable to read number of ranges",
3388 "Range line was too short, needs 4 entries per line, minimum",
3389 "Range line missing required \":\" separator",
3390 "Range colour incorrect size, should be 6 bytes",
3391 "Range specified as named ion, but ion not found in [Ions] block",
3392 "Range had unreadable start value",
3393 "Range had unreadable endvalue",
3394 "Range name was empty",
3395 "Range block had unparsable line, should start with number or range",
3396 "Ion block missing",
3398 "Unable to identify the number of basic ions",
3399 "Number of ranges specfied in range block, did not match number of ranges read",
3400 "Range block contained line that did not match A=xxx format",
3401 "Range had unreadable ion multiplicity",
3402 "Unable to read volume from range",
3403 "Range block had range with empty range row",
3404 "Range file is too large - refusing to process" 3409 return string(rangeErrStrings[errState]);
3414 ASSERT(rangeId < ranges.size());
3415 if(rangeVolumes.empty())
3416 rangeVolumes.resize(ranges.size(),0);
3418 ASSERT(rangeVolumes.size() == ranges.size());
3420 rangeVolumes[rangeId] = newVol;
3425 ASSERT(rangeId < ranges.size());
3427 if(rangeVolumes.empty())
3430 return rangeVolumes[rangeId];
3435 return rangeVolumes.size();
3440 if(ionFormulas.empty() || overwrite)
3442 ionFormulas.clear();
3443 ionFormulas.resize(ionNames.size());
3444 for(
auto ui=0;ui<ionNames.size();ui++)
3452 ionFormulas.resize(ionNames.size());
3453 for(
auto ui=0;ui<ionNames.size();ui++)
3455 if(ionFormulas[ui].empty())
3464 unsigned int &charge,
float tolerance)
const 3466 std::string ionString;
3470 vector<pair<string,size_t> > fragments;
3476 vector<size_t> elementIdx,frequency;
3477 for(
unsigned int ui=0;ui<fragments.size(); ui++)
3480 thisIdx= massTable.
symbolIndex(fragments[ui].first.c_str());
3481 if(thisIdx == (
size_t) -1)
3483 elementIdx.push_back(thisIdx);
3484 frequency.push_back(fragments[ui].second);
3489 vector<pair<float,float> > massDist;
3492 pair<float,float> rangeValues;
3494 float rangeMid = (rangeValues.first + rangeValues.second)/2.0f;
3498 vector<pair<float,unsigned int> > massErrors;
3499 for(
unsigned int ui=0;ui<massDist.size();ui++)
3502 f= massDist[ui].first/rangeMid;
3506 massErrors.push_back(make_pair(fabs(massDist[ui].first-nearInt*rangeMid),nearInt));
3510 float minErr=massErrors[0].first;
3512 for(
unsigned int ui=1;ui<massErrors.size(); ui++)
3514 if(massErrors[ui].first < minErr)
3516 minErr = massErrors[ui].first;
3522 if(massErrors[minIdx].first > tolerance)
3526 charge=massErrors[minIdx].second;
3533 bool RangeFile::test()
3536 if(natData.
open(
"naturalAbundance.xml"))
3542 auto idTi = rng.
addIon(
"Ti",
"Ti",c);
3543 auto idRngTi=rng.
addRange(23.5,24.5,idTi);
3546 TEST_Q(rng.
getIonID(idRngTi) == idTi);
3547 TEST_Q(rng.
getIonID(
"Ti") == idTi);
3549 TEST_Q(rng.
getRangeID(225.0) == (
unsigned int)-1);
3554 unsigned int charge;
3556 TEST(charge == 2,
"Charge state guessing (2)");
3559 bool enforceConsistencyOn = enforceConsistency;
3560 enforceConsistency=
true;
3561 auto idC2 = rng.
addIon(
"C2",
"C2",c);
3562 TEST(rng.
addRange(23.7,24.6,idC2) == (
unsigned int) -1,
"Add bad range (strict on), should be disallowed");
3563 enforceConsistency=
false;
3564 TEST(rng.
addRange(23.7,24.6,idC2) != (
unsigned int) -1,
"Add bad range (non-strict), should be allowed");
3575 enforceConsistency=enforceConsistencyOn;
3582 auto idTiO2 = rng.
addIon(
"TiO2O",
"TitaniumTrioxide", c);
3585 TEST(formula.at(
"Ti")==1 && formula.at(
"O")==3,
"Formula not correct");
3589 std::ofstream nullStr(
"/dev/null");
3600 TEST(rng.
write(nullStr,ui) == 0,
"null write test");
3605 vector<IonHit> ions;
3606 const unsigned int NIONS=100;
3607 for(
auto ui=0;ui<NIONS;ui++)
3610 rngDup.
range(ions,
string(
"Ti"));
3612 TEST_Q(ions.size() < NIONS);
void range(std::vector< IonHit > &ionHits) const
Clips out ions that are not inside the rangefile's ranges.
size_t symbolIndex(const char *symbol, bool caseSensitive=true) const
Return the element's position in table, starting from 0.
std::string getName(unsigned int ionID, bool shortName=true) const
Get the short name or long name of a specified ionID.
static void decomposeIonNameToFormula(const std::string &name, std::map< std::string, size_t > &formula)
Break a given string down into a chemical formula with a count of each element.
RGBf getColour(unsigned int) const
Retrieve a given colour from the ion ID.
unsigned int getIonID(float mass) const
Get the ion's ID from a specified mass.
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.
void eraseRange(unsigned int rangeId)
Erase given range - this will reorder rangeIDs, so any ids you had previously will not longer be vali...
Data holder for colour as float.
float getRangeVolume(unsigned int rangeId) const
Obtain an ions volume, if we have it. Zero may indicate no ion volume specfied for that range...
bool makeSelfConsistent()
Modify range file to ensure self-consistency, by arbitrary heuristics.
std::string stripWhite(const std::string &str)
Strip whitespace, (eg tab,space) from either side of a string.
bool moveBothRanges(unsigned int range, float newLow, float newHigh)
Move both of a range's masses to a new location.
bool setRangeEnd(unsigned int rangeID, float v)
Set the upper bound of the given range.
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.
static bool decomposeIonNames(const std::string &name, std::vector< std::pair< std::string, size_t > > &fragments)
bool isNotDirectory(const char *filename)
void vectorMultiErase(std::vector< T > &vec, const std::vector< bool > &wantKill)
Remove elements from the vector, without preserving order.
void nullifyMarker(char *buffer, char marker)
static void getAllExts(std::vector< std::string > &exts)
Grab a vector that contains all the extensions that are valid for range files.
const size_t MAX_LINE_SIZE
static std::string rangeTypeString(unsigned int rangeType)
Return the human readable name for the given RANGE_FORMAT value.
bool guessChargeState(unsigned int rangeId, const AtomProbe::AbundanceData &massTable, unsigned int &charge, float tolerance=0.5f) const
Guess the charge state for the ion that corresponds to the given range's midpoint.
static bool extensionIsRange(const char *ext)
is the extension string the same as that for a range file? I don't advocate this method, but it is convenient in a pinch.
bool isValidElementSymbol(std::string &symbol)
void setIonFormula(const std::string &name, const std::map< std::string, size_t > &formula, bool useShortName=true)
Set ion formula using ion short or long name (if it is already set)
bool isSelfConsistent() const
Performs checks for self consistency.
unsigned int getNumRanges() const
Get the number of unique ranges.
void pushLocale(const char *newLocale, int type)
void extractIons(const std::vector< IonHit > &ionHits, const std::vector< unsigned int > &ionIDs, std::vector< IonHit > &hits) const
Extract ion hit events in the specified ion ID values, from the input ion ionhit sequence.
void setColour(unsigned int, const RGBf &r)
Set the colour using the ion ID.
void splitStrsRef(const char *cpStr, const char delim, std::vector< std::string > &v)
Split string references using a single delimiter.
A 3D point data class storage.
const char * elementList[]
void rangeByRangeID(std::vector< IonHit > &ionHits, unsigned int rangeID)
Range the given ions, allowing only ions in the specified range. Input data will be modified to retur...
bool setRangeStart(unsigned int rangeID, float v)
Set the lower bound of the given range.
bool moveRange(unsigned int range, bool limit, float newMass)
Move a range's mass to a new location.
bool matchComposedName(const std::map< string, size_t > &composedNames, const vector< pair< string, size_t > > &namesToFind, size_t &matchOffset)
string rangeToStr(const pair< float, float > &rng)
bool getFilesize(const char *fname, size_t &size)
std::string toHex() const
Convert to hex-256 representation #rrggbb.
float getMassToCharge() const
void setIonShortName(unsigned int ionID, const std::string &newName)
set the short name for a given ion
const RangeFile & operator=(const RangeFile &other)
void guessFormulas(bool overwrite=false)
Use heuristics to guess missing formula data from the shortname.
bool isRanged(float mass) const
Returns true if a specified mass is ranged.
size_t open(const char *file, bool strict=false)
Attempt to open the abundance data file, return 0 on success, nonzero on failure. ...
const char * RANGE_EXTS[]
Class to load abundance information for natural isotopes.
std::pair< float, float > & getRangeByRef(unsigned int)
Retrieve the start and end of a given range as a pair(start,end)
std::string lowercase(std::string s)
Return a lowercase version for a given string.
bool decomposeIonById(unsigned int ionId, std::vector< std::pair< std::string, size_t > > &fragments) const
Perform decomposeIonNames(...) for a given ionID.
bool open(const char *rangeFile)
Open a specified range file - returns true on success.
This is a data holding class for POS file ions, from.
void setIonLongName(unsigned int ionID, const std::string &newName)
Set the long name for a given ion.
void rangeInvertable(std::vector< IonHit > &ionHits, bool invert)
Clips out ions that are inside the rangefile's ranges, if invert is false. If true, then reverse the set.
bool haveRangeVolumes() const
Return true if we have range volume data, false otherwise.
bool parseColString(const std::string &str, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a)
Parse a colour string containing rgb[a]; hex for with leading #.
bool rangeByID(std::vector< IonHit > &ionHits, unsigned int range)
Clips out ions that don't lie in the specified range number.
Data storage and retrieval class for various range files.
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
static unsigned int detectFileType(const char *file)
Attempt to detect the file format of an unknown rangefile.
const size_t MAX_RANGEFILE_SIZE
unsigned int openFormat(const char *rangeFile, unsigned int format)
Open a specified range file using a given file format. Returns nonzero on failure.
unsigned int getNumIons() const
Get the number of unique ions.
void swap(RangeFile &rng)
Swap a range file with this one.
unsigned int write(std::ostream &o, size_t format=RANGE_FORMAT_ORNL) const
Write the rangefile to the specified output stream (default ORNL format)
void setIonID(unsigned int range, unsigned int newIonId)
Set the ion ID for a given range.
std::string getErrString() const
Retrieve the translated error associated with the current range file state.
void stripZeroEntries(std::vector< std::string > &s)
std::map< std::string, size_t > getIonFormula(unsigned int ionID) const
Get ion formula by ion ID.
unsigned int getRangeID(float mass) const
Get a range ID from mass to charge.
void strAppend(std::string s, const T &a)
unsigned int addRange(float start, float end, unsigned int ionID)
Add a range to the rangefile. Returns ID number of added range.
void setRangeVolume(unsigned int rangeId, float newVolume)
Set the ion volume for a given range. If ion volumes are not tracked, these will be created...
std::string stripChars(const std::string &Str, const char *chars)
std::pair< float, float > getRange(unsigned int) const
Retrieve the start and end of a given range as a pair(start,end)
void eraseIon(unsigned int ionId)
erase given ions and associated ranges)