#include "chemelem.h" #include namespace geoworld { PeriodicTable periodicity; PeriodicTable::PeriodicTable () { #define ASSIGN_CHEM(x) _name2num[#x] = x ASSIGN_CHEM(H); ASSIGN_CHEM(He); ASSIGN_CHEM(Li); ASSIGN_CHEM(Be); ASSIGN_CHEM(B); ASSIGN_CHEM(C); ASSIGN_CHEM(N); ASSIGN_CHEM(O); ASSIGN_CHEM(F); ASSIGN_CHEM(Ne); ASSIGN_CHEM(Na); ASSIGN_CHEM(Mg); ASSIGN_CHEM(Al); ASSIGN_CHEM(Si); ASSIGN_CHEM(P); ASSIGN_CHEM(S); ASSIGN_CHEM(Cl); ASSIGN_CHEM(Ar); ASSIGN_CHEM(K); ASSIGN_CHEM(Ca); ASSIGN_CHEM(Sc); ASSIGN_CHEM(Ti); ASSIGN_CHEM(V); ASSIGN_CHEM(Cr); ASSIGN_CHEM(Mn); ASSIGN_CHEM(Fe); ASSIGN_CHEM(Co); ASSIGN_CHEM(Ni); ASSIGN_CHEM(Cu); ASSIGN_CHEM(Zn); ASSIGN_CHEM(Ga); ASSIGN_CHEM(Ge); ASSIGN_CHEM(As); ASSIGN_CHEM(Se); ASSIGN_CHEM(Br); ASSIGN_CHEM(Kr); ASSIGN_CHEM(Rb); ASSIGN_CHEM(Sr); ASSIGN_CHEM(Y); ASSIGN_CHEM(Zr); ASSIGN_CHEM(Nb); ASSIGN_CHEM(Mo); ASSIGN_CHEM(Tc); ASSIGN_CHEM(Ru); ASSIGN_CHEM(Rh); ASSIGN_CHEM(Pd); ASSIGN_CHEM(Ag); ASSIGN_CHEM(Cd); ASSIGN_CHEM(In); ASSIGN_CHEM(Sn); ASSIGN_CHEM(Sb); ASSIGN_CHEM(Te); ASSIGN_CHEM(I); ASSIGN_CHEM(Xe); ASSIGN_CHEM(Cs); ASSIGN_CHEM(Ba); ASSIGN_CHEM(La); ASSIGN_CHEM(Ce); ASSIGN_CHEM(Pr); ASSIGN_CHEM(Nd); ASSIGN_CHEM(Pm); ASSIGN_CHEM(Sm); ASSIGN_CHEM(Eu); ASSIGN_CHEM(Gd); ASSIGN_CHEM(Tb); ASSIGN_CHEM(Dy); ASSIGN_CHEM(Ho); ASSIGN_CHEM(Er); ASSIGN_CHEM(Tm); ASSIGN_CHEM(Yb); ASSIGN_CHEM(Lu); ASSIGN_CHEM(Hf); ASSIGN_CHEM(Ta); ASSIGN_CHEM(W); ASSIGN_CHEM(Re); ASSIGN_CHEM(Os); ASSIGN_CHEM(Ir); ASSIGN_CHEM(Pt); ASSIGN_CHEM(Au); ASSIGN_CHEM(Hg); ASSIGN_CHEM(Tl); ASSIGN_CHEM(Pb); ASSIGN_CHEM(Bi); ASSIGN_CHEM(Po); ASSIGN_CHEM(At); ASSIGN_CHEM(Rn); ASSIGN_CHEM(Fr); ASSIGN_CHEM(Ra); ASSIGN_CHEM(Ac); ASSIGN_CHEM(Th); ASSIGN_CHEM(Pa); ASSIGN_CHEM(U); ASSIGN_CHEM(Np); ASSIGN_CHEM(Pu); ASSIGN_CHEM(Am); ASSIGN_CHEM(Cm); ASSIGN_CHEM(Bk); ASSIGN_CHEM(Cf); ASSIGN_CHEM(Es); ASSIGN_CHEM(Fm); ASSIGN_CHEM(Md); ASSIGN_CHEM(No); ASSIGN_CHEM(Lr); ASSIGN_CHEM(Rf); ASSIGN_CHEM(Db); ASSIGN_CHEM(Sg); ASSIGN_CHEM(Bh); ASSIGN_CHEM(Hs); ASSIGN_CHEM(Mt); ASSIGN_CHEM(Ds); ASSIGN_CHEM(Rg); ASSIGN_CHEM(Uub); ASSIGN_CHEM(Uut); ASSIGN_CHEM(Uuq); ASSIGN_CHEM(Uup); ASSIGN_CHEM(Uuh); ASSIGN_CHEM(Uus); ASSIGN_CHEM(Uuo); #undef ASSIGN_CHEM } ChemicalFormulaParser::Token::Token( const std::string & formula, const unsigned s0 ) : type(typeOf(formula[s0])), _s0(s0), _formula(formula), _s(s0) { switch (type) { case TNum: while (++_s < formula.length() && typeOf(formula[_s]) == TNum); break; case TWord: while (++_s < formula.length() && (formula[_s] >= 'a' && formula[_s] <= 'z')); break; case TSep: while (++_s < formula.length() && typeOf(formula[_s]) == TSep); break; default: ++_s; break; } } ChemicalFormulaParser::Token & ChemicalFormulaParser::Token::operator = ( const ChemicalFormulaParser::Token & a ) { _s0 = a._s0; _s = a._s; if (_formula != a._formula) throw Ex(); return *this; } ChemicalFormulaParser::TokenType ChemicalFormulaParser::Token::typeOf( const char ch ) { if ((ch >= '0' && ch <= '9') || ch == '.') return TNum; else if (ch >= 'A' && ch <= 'Z') return TWord; else if (ch == ' ' || ch == '.') return TSep; else if (ch == '(') return TOpen; else if (ch == ')') return TClose; else if (ch == ',') return TAlt; else throw Ex(); } void ChemicalFormulaParser::Token::operator >> ( unsigned & num ) const { num = atoi (_formula.substr(_s0, _s - _s0).c_str()); } void ChemicalFormulaParser::Token::operator >> ( AtomicNumber & atom ) const { atom = periodicity[_formula.substr(_s0, _s - _s0)]; } void ChemicalFormulaParser::Token::operator >> ( float & f ) const { f = static_cast (atof(_formula.substr(_s0, _s - _s0).c_str())); } unsigned ChemicalFormulaParser::Token::length() const { return _s - _s0; } bool ChemicalFormulaParser::lookAhead( const std::vector ::const_iterator & i, const ChemicalFormulaParser::TokenType tok ) const { return ((i + 1) != _tokens.end() && (i + 1)->type == tok); } bool ChemicalFormulaParser::lookBehind( const std::vector ::const_iterator & i, const ChemicalFormulaParser::TokenType tok ) const { return (i != _tokens.begin() && (i - 1)->type == tok); } void ChemicalFormulaParser::quantities (ChemicalFormulaParser::IQuantityCallback * cb) { float mqty = 1, gqty = 1, gdqty = 1; AtomicNumber atom; std::vector ::const_iterator i = _tokens.begin(); float quantiteas[NUM_CHEM_ELEMENTS]; memset(quantiteas, 0, sizeof(quantiteas)); while (i != _tokens.end()) { // Do nothing, skip, group quantifiers were processed in-advance while processing 'TOpen' if (lookBehind(i, TClose) && i->type == TNum) {} else if (i->type == TNum) { *i++ >> mqty; if (i == _tokens.end()) throw Ex(); // Molecular quantifiers cannot terminate a formula if (i->type == TWord) { unsigned aqty = 1; *i >> atom; // If we're at the end of the word, we expect an atomic quantifier here if (lookAhead(i, TNum)) { *++i >> aqty; } quantiteas[atom] += mqty * aqty * (gqty / gdqty); } else throw Ex(); // A chemical element name must immediately follow a molecular quantifier } else if (i->type == TWord) { unsigned aqty = 1; *i >> atom; // If we're at the end of the word, we expect an atomic quantifier here if (lookAhead(i, TNum)) { *++i >> aqty; } quantiteas[atom] += mqty * aqty * (gqty / gdqty); // Process a group including the suffixes after the group terminator } else if (i->type == TOpen) { std::vector ::const_iterator i2 = i; // Scan to the end of the group while (i2->type != TClose && i2 != _tokens.end()) { // If we encounter a comma, then we increase the group quantity dividend (Q = Qm * Qa * Qg / Qd) if (i->type == TAlt) gdqty++; i2++; } // Check for an unbalanced group (no closing brace found) if (i2 == _tokens.end()) throw Ex(); // No closing brace found // We hope the next token after the group terminator is a number, it becomes our group quantity if (lookAhead(i2, TNum)) *++i2 >> gqty; } else if (i->type == TClose) { gqty = 1; gdqty = 1; } i++; } for (unsigned c = 0; c < NUM_CHEM_ELEMENTS; c++) { if (quantiteas[c] > 0) cb->setChemicalQuantity(static_cast (c), quantiteas[c]); } } ChemicalFormulaParser::ChemicalFormulaParser (const std::string & formula) : _formula(formula) { unsigned c = 0; while (c < _formula.length()) { _tokens.push_back(Token(_formula, c)); c += _tokens.back().length(); } } }