Page MenuHomec4science

reader_common.cpp
No OneTemporary

File Metadata

Created
Tue, Jun 11, 22:43

reader_common.cpp

/*-------------------------------------------------------------------------------
Copyright (c) 2015 F. Georget <fabieng@princeton.edu>, Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------*/
#include "reader_common.hpp"
#include "section_name.hpp"
#include "errors.hpp"
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <locale>
//#include <cctype>
namespace specmicp {
namespace database {
void parse_equation(const std::string& equation, std::map<std::string, scalar_t> &compo)
{
std::vector<std::string> list_compo;
boost::split(list_compo, equation, [](char input){return input == ',';}, boost::token_compress_on);
for (auto it=list_compo.begin(); it!=list_compo.end(); ++it)
{
std::string& toparse = *it;
double coeff = 0;
boost::trim_all(toparse);
unsigned int pos_end = 0;
while (pos_end < toparse.size())
{
if (std::isalpha(toparse[pos_end])) // or std::isblank(toparse[pos_end]))
{
break;
}
++pos_end;
}
std::string label(toparse.substr(pos_end, toparse.size()-pos_end));
boost::trim_all(label);
if (pos_end == 0) coeff =1;
else if (pos_end == 1 and toparse[0] == '-') coeff=-1;
else
{
std::string tofloat = toparse.substr(0, pos_end);
while (pos_end > 1)
{
if ((tofloat[0] == '-' or tofloat[0] == '+')
and std::isspace(tofloat[1]))
{
tofloat = tofloat[0] + tofloat.substr(2,pos_end-2);
--pos_end;
continue;
}
else
{
break;
}
}
if ( tofloat[pos_end-1] == '-' ) {coeff = -1;}
else if (tofloat[pos_end-1] == '+') {coeff = +1;}
else {coeff = std::stof(tofloat);}
}
compo[label] = coeff;
}
}
scalar_t charge_from_label(const std::string& label)
{
int sign=1;
auto start= label.end();
auto stop = label.end();
for (auto it=label.begin(); it != label.end(); ++it)
{
if (*it == INDB_OPEN_DELIMITER_CHARGE) { start = it; }
}
if (start == label.end()) {return 0;} // no charge specified
for (auto it=start+1; it != label.end(); ++it)
{
if (*it == INDB_CLOSE_DELIMITER_CHARGE) { stop = it; }
}
if (stop == label.end()) {throw db_invalid_syntax("Charge : missing closing delimiter for species : "+label+".");}
start = start+1;
if (stop == start) {return 0;} // nothing inside bracket
// get the signs
if (*(stop-1) == '-')
{
sign = -1;
stop =stop-1;
}
else if (*(stop-1) == '+')
{
sign = +1;
stop = stop-1;
}
if (stop == start)
{
return sign; // just the sign, |z|=1
}
scalar_t charge;
try
{
charge = sign*std::stof(std::string(start,stop));
}
catch (std::invalid_argument&)
{
throw db_invalid_syntax("Charge : bad formatting for species :"+ label+".");
}
return charge;
}
// find the next element
std::string::size_type find_element(const std::string& label, std::string::size_type pos, element_map& element_coeff);
// insert label in elem_map if it doesn't exist else add coeff to the value
void insert_or_add(element_map& elem_map, const std::string& label, scalar_t coeff);
// find the position of the matching parenthesis
std::string::size_type find_matching_parenthesis(const std::string& label, std::string::size_type init_pos);
// find a number, return 1 if it's not there
std::string::size_type find_number(const std::string& label, std::string::size_type init_pos, scalar_t& number);
// return true of the bit in paremnthesis is a phase qualifier (aq, g, s, am, mic)
bool is_phase_qualifier(const std::string& bit_in_parenthesis);
// return true if it is an expected special character (not a number or a parenthesis)
bool is_special(std::string::size_type charac);
void element_composition_from_label(std::string label, element_map& compo)
{
boost::trim_all(label);
compo.clear();
std::string::size_type pos = 0;
while (pos < label.size())
{
if (label[pos] == '(') // ex Al(OH)4
{
++pos; // go into the parenthesis
// find composition in parenthesis
element_map subcompo;
std::string::size_type final_pos = find_matching_parenthesis(label, pos);
const std::string sublabel = label.substr(pos, final_pos-pos);
if (is_phase_qualifier(sublabel))
{
// skip that
pos = final_pos;
break;
}
element_composition_from_label(sublabel, subcompo);
// find coefficient of parenthesis
scalar_t coeff;
final_pos = find_number(label, final_pos+1, coeff);
// add the compo of parenthesis to the total compo
add_to_element_map(compo, subcompo, coeff);
pos = final_pos;
}
else if (label[pos] == ':') // ex CaSO3:0.5H2O
{
++pos; // skip the semi-colon
// find coefficient
scalar_t coeff;
std::string::size_type final_pos = find_number(label, pos, coeff);
// find element
element_map subcompo;
element_composition_from_label(label.substr(final_pos, label.size()-final_pos), subcompo);
// add compo to total compo
add_to_element_map(compo, subcompo, coeff);
pos = label.size();
}
else if (label[pos] == '[') // charge AlO(OH)3[-]
{
// it's finished
break;
}
else
{
pos = find_element(label, pos, compo);
}
}
}
bool is_special(std::string::size_type charac)
{
return (charac == '(' or charac == ':' or charac == ')' or charac == '[' or charac == ']');
}
std::string::size_type find_matching_parenthesis(const std::string& label, std::string::size_type init_pos)
{
for (std::string::size_type ind=init_pos; ind<label.size(); ++ind)
{
if (label[ind] == '(')
{
throw std::invalid_argument("Too many parenthesis in label : '"+label+"' ( pos : "+std::to_string(ind)+" ).");
}
else if (label[ind] == ')')
{
return ind;
}
}
throw std::invalid_argument("Unmatched parenthesis in label : '"+label+"' (pos : "+std::to_string(init_pos)+" ).");
}
std::string::size_type find_number(const std::string& label, std::string::size_type init_pos, scalar_t& number)
{
if (not std::isdigit(label[init_pos]))
{
number = 1;
return init_pos;
}
std::string::size_type pos = init_pos + 1;
while (pos < label.size())
{
const std::string::value_type chr = label[pos];
if (not (chr == '.' or std::isdigit(chr)))
{
break;
}
++pos;
}
const std::string coeff_str = label.substr(init_pos, pos);
number = std::stod(coeff_str);
return pos;
}
void insert_or_add(element_map& elem_map, const std::string& label, scalar_t coeff)
{
auto it = elem_map.find(label);
if (it != elem_map.end())
{
it->second += coeff;
}
else
{
elem_map.insert(element_map::value_type(label, coeff));
}
}
std::string::size_type find_element(const std::string& label, std::string::size_type pos, element_map& compo)
{
if (not std::isupper(label[pos]))
throw std::invalid_argument("Invalid label : "+label+" (Error detected at position "+std::to_string(pos)+" ).");
std::string::size_type current_pos = pos +1;
std::string::size_type start_number_pos = std::string::npos;
while (true)
{
if (current_pos == label.size() or
is_special(label[current_pos]) or
std::isupper(label[current_pos])
)
{
if (start_number_pos == std::string::npos)
{
insert_or_add(compo, label.substr(pos, current_pos-pos), 1.0);
}
else
{
const std::string coeff_str = label.substr(start_number_pos, current_pos-start_number_pos);
insert_or_add(compo, label.substr(pos, start_number_pos-pos), std::stod(coeff_str));
}
break;
}
else if (std::isdigit(label[current_pos]) or label[current_pos] == '.')
{
if (start_number_pos == std::string::npos) start_number_pos = current_pos;
}
++current_pos;
}
return current_pos;
}
bool is_phase_qualifier(const std::string& bit_in_parenthesis)
{
if (bit_in_parenthesis == "aq" or
bit_in_parenthesis == "g" or
bit_in_parenthesis == "s" or
bit_in_parenthesis == "am" or
bit_in_parenthesis == "mic"
)
{
return true;
}
else
{
return false;
}
}
void add_to_element_map(element_map& to_update, const element_map& to_add, const scalar_t coeff)
{
for (auto& it:to_add)
{
insert_or_add(to_update, it.first, coeff*it.second);
}
}
} //end namespace database
} //end namespace specmicp

Event Timeline