diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt index 373b635..59c2c2b 100644 --- a/src/database/CMakeLists.txt +++ b/src/database/CMakeLists.txt @@ -1,115 +1,117 @@ # The database # ============ # database libraries # ------------------ add_custom_target(database_incl SOURCES species/ionic_parameters.hpp species/component_list.hpp species/aqueous_list.hpp section_name.hpp errors.hpp module.hpp ) set(DATABASE_LIBFILE species/species.cpp species/base_wrapper.cpp species/mineral_list.cpp species/gas_list.cpp species/sorbed_list.cpp species/compounds_list.cpp species/element_list.cpp data_container.cpp module.cpp database.cpp + reader_common.cpp reader.cpp + yaml_reader.cpp selector.cpp appender.cpp mineral_selector.cpp aqueous_selector.cpp oxydo_selector.cpp switch_basis.cpp writer.cpp io/configuration.cpp ) set_visibility_flag(${DATABASE_LIBFILE}) set_pgo_flag(${DATABASE_LIBFILE}) #set_property(SOURCE ${DATABASE_LIBFILE} APPEND PROPERTY COMPILE_FLAGS -fvisibility-inlines-hidden) add_library(objspecmicp_database OBJECT ${DATABASE_LIBFILE}) set_property(TARGET objspecmicp_database PROPERTY POSITION_INDEPENDENT_CODE 1) add_library(specmicp_database SHARED $) install(TARGETS specmicp_database LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} ) # export includes # ---------------- set(DATABASE_SPECIES_INCLUDE_LIST species/species.hpp species/base_wrapper.hpp species/ionic_parameters.hpp species/component_list.hpp species/aqueous_list.hpp species/mineral_list.hpp species/gas_list.hpp species/sorbed_list.hpp species/compounds_list.hpp species/element_list.hpp ) set(DATABASE_INCLUDE_LIST errors.hpp module.hpp data_container.hpp database.hpp selector.hpp appender.hpp mineral_selector.hpp aqueous_selector.hpp oxydo_selector.hpp switch_basis.hpp ) install(FILES ${DATABASE_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/database/ ) install(FILES ${DATABASE_SPECIES_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/database/species/ ) install(FILES io/configuration.hpp DESTINATION ${INCLUDE_INSTALL_DIR}/database/io/ ) # static libraries # ---------------- if(SPECMICP_BUILD_STATIC) add_library(specmicp_database_static STATIC $) install(TARGETS specmicp_database_static ARCHIVE DESTINATION ${STATIC_LIBRARY_INSTALL_DIR} ) else() add_library(specmicp_database_static EXCLUDE_FROM_ALL STATIC $) endif() set_target_properties(specmicp_database_static PROPERTIES OUTPUT_NAME specmicp_database) add_dependencies(specmicp_database_static database_incl) diff --git a/src/database/database.cpp b/src/database/database.cpp index c7fdf68..055054a 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -1,172 +1,173 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , 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 "database.hpp" #include "selector.hpp" #include "switch_basis.hpp" #include "mineral_selector.hpp" #include "reader.hpp" +#include "yaml_reader.hpp" #include "oxydo_selector.hpp" #include "appender.hpp" #include "writer.hpp" namespace specmicp { namespace database { // Implementation note // -------------------- // This class does not contain any major algorithm // Instead it calls the database modules methods // This is done in the source file to reduce compilation dependancy // and avoid exporting too many symbols // // This class should only contains short functions. void Database::parse_database(std::string filepath) { - DataReader reader(filepath); + DataReaderYaml reader(filepath); set_database(reader.get_database()); } void Database::parse_database(std::istream& input) { - DataReader reader(input); + DataReaderYaml reader(input); set_database(reader.get_database()); } void Database::remove_components(const std::vector& labels_components_to_remove) { std::vector id_components_to_remove; id_components_to_remove.reserve(labels_components_to_remove.size()); for (auto it: labels_components_to_remove) { id_components_to_remove.push_back(safe_component_label_to_id(it)); } remove_components(id_components_to_remove); } void Database::remove_components(const std::vector& id_components_to_remove) { DatabaseSelector selector(data); selector.remove_component(id_components_to_remove); } void Database::keep_only_components(const std::vector& labels_components_to_keep) { std::vector id_components_to_keep; id_components_to_keep.reserve(labels_components_to_keep.size()); for (auto it: labels_components_to_keep) { id_components_to_keep.push_back(safe_component_label_to_id(it)); } keep_only_components(id_components_to_keep); } void Database::keep_only_components(const std::vector& id_components_to_keep) { DatabaseSelector selector(data); selector.keep_only_component(id_components_to_keep); } void Database::minerals_keep_only(const std::vector& minerals_to_keep) { MineralSelector(data).keep_only(minerals_to_keep); } void Database::minerals_keep_only(const std::vector& minerals_to_keep) { MineralSelector(data).keep_only(minerals_to_keep); } void Database::swap_components(const std::map& swap_to_make) { BasisSwitcher(data).swap_components(swap_to_make); } void Database::remove_gas_phases() { DatabaseSelector(data).remove_all_gas(); } void Database::add_gas_phases(const std::string &gas_input) { DataAppender(data).add_gas(gas_input); } void Database::remove_solid_phases() { MineralSelector(data).remove_all_minerals(); } void Database::add_solid_phases(const std::string &solid_phases_input) { DataAppender(data).add_minerals(solid_phases_input); } void Database::remove_sorbed_species() { DatabaseSelector(data).remove_all_sorbed(); } void Database::add_sorbed_species(const std::string& sorbed_input) { DataAppender(data).add_sorbed(sorbed_input); } void Database::remove_compounds() { DatabaseSelector(data).remove_all_compounds(); } void Database::add_compounds(const std::string& compounds_input) { DataAppender(data).add_compounds(compounds_input); } void Database::remove_half_cell_reactions(const std::vector& list_components) { OxydoSelector(data).remove_half_cells(list_components); } void Database::remove_half_cell_reactions(const std::vector& list_id_components) { OxydoSelector(data).remove_half_cells(list_id_components); } void Database::save(const std::string& filename) { DatabaseWriter(data).write(filename); } } // end namespace database } // end namespace specmicp diff --git a/src/database/reader.cpp b/src/database/reader.cpp index 1f3e6f8..b78fd2d 100644 --- a/src/database/reader.cpp +++ b/src/database/reader.cpp @@ -1,690 +1,590 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , 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.hpp" #include "json/json.h" #include "../utils/json.hpp" #include #include -#include -#include -#include -#include +#include "reader_common.hpp" #include "utils/log.hpp" #include "section_name.hpp" #define PRECISION_TEST_CHARGE 1e-6 #include namespace specmicp { namespace database { // safe access to values std::string obtain_label(Json::Value& species); void obtain_composition(Json::Value& species, std::map& compo); scalar_t obtain_logk(Json::Value& species); bool is_kinetic(Json::Value& species); void DataReader::parse(const std::string& filepath) { std::ifstream datafile(filepath, std::ifstream::binary); if (not datafile.is_open()) { ERROR << "Database not found : " << filepath; std::string message("Database not found : " + filepath); throw std::invalid_argument(message); } data->metadata.path = filepath; parse(datafile); datafile.close(); } void DataReader::parse(std::istream& input ) { Json::Value root; json::parse_json(input, root); json::check_for_mandatory_member(root, INDB_SECTION_METADATA); parse_metadata(root[INDB_SECTION_METADATA]); // Basis // ------ json::check_for_mandatory_member(root, INDB_SECTION_BASIS); parse_basis(root[INDB_SECTION_BASIS]); // Elements // -------- ElementList elements; json::check_for_mandatory_member(root, INDB_SECTION_ELEMENTS); parse_elements(root[INDB_SECTION_ELEMENTS], elements); data->elements = std::move(elements); // Aqueous species // --------------- json::check_for_mandatory_member(root, INDB_SECTION_AQUEOUS); AqueousList alist; parse_aqueous(root[INDB_SECTION_AQUEOUS], alist); data->aqueous = std::move(alist); // Minerals // -------- json::check_for_mandatory_member(root, INDB_SECTION_MINERALS); MineralList minerals, minerals_kinetic; parse_minerals(root[INDB_SECTION_MINERALS], minerals, minerals_kinetic); data->minerals = std::move(minerals); data->minerals_kinetic = std::move(minerals_kinetic); // Gas // ---- GasList glist(0, data->nb_component()); if (root.isMember(INDB_SECTION_GAS)) parse_gas(root[INDB_SECTION_GAS], glist); else glist.set_valid(); data->gas = std::move(glist); // Sorbed species // -------------- SorbedList slist(0, data->nb_component()); if (root.isMember(INDB_SECTION_SORBED)) parse_sorbed(root[INDB_SECTION_SORBED], slist); else slist.set_valid(); data->sorbed = std::move(slist); // Compounds // --------- CompoundList clist(0, data->nb_component()); if (root.isMember(INDB_SECTION_COMPOUNDS)) parse_compounds(root[INDB_SECTION_COMPOUNDS], clist); else clist.set_valid(); data->compounds = std::move(clist); } void DataReader::parse_metadata(Json::Value &root) { json::check_for_mandatory_member(root, INDB_ATTRIBUTE_NAME); data->metadata.name = root[INDB_ATTRIBUTE_NAME].asString(); json::check_for_mandatory_member(root, INDB_ATTRIBUTE_VERSION); data->metadata.version = root[INDB_ATTRIBUTE_VERSION].asString(); } void DataReader::parse_basis(Json::Value& basis) { DEBUG << "Size basis : " << basis.size(); data->components = ComponentList(basis.size()); if (data->nb_component() <= 3) throw std::invalid_argument("The basis is too small."); index_t starting_point = 2; for (int id: data->components.range()) { index_t id_in_db = starting_point; if (id_in_db >= data->nb_component()) { throw std::invalid_argument("The basis should contain H2O and E[-]."); } Json::Value species = basis[id]; json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LABEL); std::string label = obtain_label(species); if (label == water_label) { id_in_db = 0; //throw invalid_database("The first component should be "+water_label+"."); } else if (label == electron_label) { id_in_db = 1; //throw invalid_database("The second component should be "+electron_label+"."); } else { ++starting_point; } auto is_already_in_the_database = data->components.get_id(label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + label + "is already in the database."); SPAM << "Parsing component : " << label; ComponentValues values; values.label = label; values.ionic_values.charge = charge_from_label(label); if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) { values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); } json::check_for_mandatory_member(species, INDB_ATTRIBUTE_MOLARMASS); values.molar_mass = species[INDB_ATTRIBUTE_MOLARMASS].asDouble(); data->components.set_values(id_in_db, std::move(values)); } data->components.set_valid(); } void DataReader::parse_aqueous(Json::Value& aqueous, AqueousList& alist) { DEBUG << "Parse aqueous species"; alist = AqueousList(aqueous.size(), data->nb_component()); //const auto size = data->nb_aqueous(); for (auto id: alist.range()) { Json::Value& species = aqueous[static_cast(id)]; AqueousValues values; values.label = obtain_label(species); values.ionic_values.charge = charge_from_label(values.label); if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) { values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); } values.logk = obtain_logk(species); alist.set_values(id, std::move(values)); // equation std::map compo; obtain_composition(species, compo); scalar_t test_charge {0.0}; std::map to_canonicalize; for (const auto& it: compo) { // component ? const auto search = data->components.get_id(it.first); if(search != no_species) { alist.set_nu_ji(id, search, it.second); test_charge += it.second*data->charge_component(search); } // aqueous species ? else { // in the document we parse ? const auto id_aq = alist.get_id(it.first); if (id_aq != no_species) { to_canonicalize.insert({id_aq, it.second}); test_charge += it.second*alist.charge(id_aq); } // cannot be found... else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + alist.get_label(id) +"."); } } } if (std::abs(test_charge - alist.charge(id)) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for aqueous species : '" + alist.get_label(id) + "' - Charge-decomposition - charge species : "+ std::to_string(test_charge - alist.charge(id) )+"."); } for (const auto& tocanon: to_canonicalize) { alist.canonicalize(id, tocanon.first, tocanon.second); } } alist.set_valid(); } void DataReader::parse_minerals(Json::Value& minerals, MineralList& minerals_list, MineralList& minerals_kinetic_list) { DEBUG << "Parse minerals"; index_t nb_mineral = minerals.size(); // find kinetic minerals int nb_kin = 0; for (int id=0; idnb_component()); minerals_kinetic_list = MineralList(nb_kin, data->nb_component()); // id for each class of minerals index_t id_in_eq=0; index_t id_in_kin=0; for (index_t id=0; id(id)]; //check if material is at equilibrium or governed by kinetics bool is_kin = is_kinetic(species); MineralValue value; value.label = std::move(obtain_label(species)); value.logk = obtain_logk(species); if (species.isMember(INDB_ATTRIBUTE_MOLARVOLUME)) { value.molar_volume = species[INDB_ATTRIBUTE_MOLARVOLUME].asDouble(); } else { // ###FIXME value.molar_volume = -1; } auto& mlist = is_kin?minerals_kinetic_list:minerals_list; auto& true_id = is_kin?id_in_kin:id_in_eq; mlist.set_values(true_id, std::move(value)); // equation // -------- std::map compo; obtain_composition(species, compo); double test_charge = 0; std::map to_canonicalize; for (const auto& it: compo) { auto idc = data->components.get_id(it.first); if(idc != no_species) { // this is a component mlist.set_nu_ji(true_id, idc, it.second); test_charge += it.second * data->charge_component(idc); } else { // this is an aqueous species auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second * data->charge_aqueous(idaq); } else // or something we don't know { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + mlist.get_label(true_id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for mineral : '"+ mlist.get_label(true_id) + "' - total charge : "+std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { mlist.canonicalize(true_id, data->aqueous, tocanon.first, tocanon.second); } // update index ++true_id; } specmicp_assert(id_in_kin == minerals_kinetic_list.size()); specmicp_assert(id_in_eq == minerals_list.size()); minerals_list.set_valid(); minerals_kinetic_list.set_valid(); } void DataReader::parse_gas(Json::Value& gas, GasList& glist) { DEBUG << "Parse gas"; glist = GasList(gas.size(), data->nb_component()); for (auto id: glist.range()) { Json::Value& species = gas[static_cast(id)]; GasValues values; values.label = obtain_label(species); auto is_already_in_the_database = data->gas.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + values.label + "is already in the database."); values.logk = obtain_logk(species); glist.set_values(id, std::move(values)); // equation std::map compo; obtain_composition(species, compo); scalar_t test_charge = 0.0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); // component if(idc != no_species) { glist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } // aqueous species else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + data->gas.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+data->gas.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { glist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } glist.set_valid(); } void DataReader::parse_sorbed(Json::Value& sorbed, SorbedList& slist) { DEBUG << "Parse sorbed species"; slist = SorbedList(sorbed.size(), data->nb_component()); for (auto id: slist.range()) { Json::Value& species = sorbed[static_cast(id)]; SorbedValues values; values.label = obtain_label(species); auto is_already_in_the_database = slist.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Sorbed species : " + values.label + "is already in the database."); values.logk = obtain_logk(species); json::check_for_mandatory_member(species, INDB_ATTRIBUTE_NBSITEOCCUPIED); const auto nb_site_occupied = species[INDB_ATTRIBUTE_NBSITEOCCUPIED].asDouble(); if (nb_site_occupied < 0) { throw db_invalid_data("The number of sites occupied by a sorbed species must be positive. (Species : " + values.label + ", number of sites : " +std::to_string(nb_site_occupied) + ")"); } values.sorption_site_occupied = nb_site_occupied; slist.set_values(id, std::move(values)); std::map compo; obtain_composition(species, compo); double test_charge = 0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); if(idc != no_species) { slist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + slist.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+slist.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { slist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } slist.set_valid(); } void DataReader::parse_compounds(Json::Value& compounds, CompoundList &clist) { DEBUG << "Parse compounds"; clist = CompoundList(compounds.size(), data->nb_component()); for (auto id: clist.range()) { Json::Value& species = compounds[static_cast(id)]; std::string label = obtain_label(species); auto is_already_in_the_database = clist.get_id(label); if (is_already_in_the_database != no_species) throw invalid_database("Compounds : " + label + "is already in the database."); clist.set_values(id, label); std::map compo; obtain_composition(species, compo); double test_charge = 0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); if(idc != no_species) { clist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + clist.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+clist.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { clist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } clist.set_valid(); } void DataReader::parse_elements(Json::Value &elements, ElementList &elist) { if (elements.size() != data->nb_component()) throw db_invalid_data("The number of elements does not corresponds to the number of components"); for (index_t id: data->range_component()) { Json::Value& elem = elements[static_cast(id)]; json::check_for_mandatory_member(elem, INDB_ATTRIBUTE_ELEMENT); json::check_for_mandatory_member(elem, INDB_ATTRIBUTE_COMPONENT); const std::string elem_label = elem[INDB_ATTRIBUTE_ELEMENT].asString(); const std::string comp_label = elem[INDB_ATTRIBUTE_COMPONENT].asString(); index_t id_comp = data->get_id_component(comp_label); if (id_comp == no_species) { throw db_invalid_label("'"+comp_label+"' is not a valid component"); } elist.add_element(elem_label, id_comp); } } -void parse_equation(const std::string& equation, std::map &compo) -{ - std::vector 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; - } -} - -double 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 - } - double 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; - -} std::string obtain_label(Json::Value& species) { json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LABEL); return species[INDB_ATTRIBUTE_LABEL].asString(); } void obtain_composition(Json::Value& species, std::map& compo) { json::check_for_mandatory_member(species, INDB_ATTRIBUTE_COMPOSITION); parse_equation(species[INDB_ATTRIBUTE_COMPOSITION].asString(), compo); } scalar_t obtain_logk(Json::Value& species) { json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LOGK); return species[INDB_ATTRIBUTE_LOGK].asDouble(); } bool is_kinetic(Json::Value& species) { bool is_kin {false}; if (species.isMember(INDB_ATTRIBUTE_FLAG_KINETIC)) { is_kin = species[INDB_ATTRIBUTE_FLAG_KINETIC].asBool(); } return is_kin; } +} // end namespace database } // end namespace specmicp -} // end namespace chemy diff --git a/src/database/reader.hpp b/src/database/reader.hpp index 4ed9c44..9f7ca22 100644 --- a/src/database/reader.hpp +++ b/src/database/reader.hpp @@ -1,140 +1,125 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , 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. -----------------------------------------------------------------------------*/ #ifndef DATABASE_READER_H #define DATABASE_READER_H //! \file reader.hpp Read the database from a json file #include "json/json-forwards.h" #include "module.hpp" #include namespace specmicp { namespace database { //! \brief Read a json file containing a database class SPECMICP_DLL_LOCAL DataReader: public DatabaseModule { public: //! \brief Empty constructor DataReader() {} //! \brief Constructor DataReader(RawDatabasePtr data): DatabaseModule(data) {} //! \brief Constructor //! //! @param filepath string containing the path to the database DataReader(const std::string& filepath): DatabaseModule() { parse(filepath); } //! \brief Constructor //! //! @param input input stream that contains the database DataReader(std::istream& input): DatabaseModule() { parse(input); } //! Return the databes RawDatabasePtr get_database() {return data;} //! \brief Parse the basis section //! //! Contains the list of primary species void parse_basis(Json::Value& basis_root); //! \brief Parse the aqueous section //! //! Contains the list of secondary species void parse_aqueous(Json::Value& aqueous_root, AqueousList& alist); //! \brief Parse the mineral section //! //! Contains the list of minerals void parse_minerals( Json::Value& minerals, MineralList &minerals_list, MineralList &minerals_kinetic_list ); //! \brief Parse the gas section void parse_gas(Json::Value& gas_root, GasList &glist); //! \brief Parse the sorbed species section void parse_sorbed(Json::Value& sorbed_root, SorbedList &slist); //! \brief Parse the compounds void parse_compounds(Json::Value& compounds, CompoundList &clist); //! \brief Parse the elements void parse_elements(Json::Value& elements, ElementList &elist); private: //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(std::istream& input); //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(const std::string& filepath); //! \brief Parse the metadata section //! //! we don't do much with them for now.... void parse_metadata(Json::Value& root); }; -//! \brief Parse an equation -void SPECMICP_DLL_LOCAL parse_equation(const std::string &equation, - std::map& compo); - -//! \brief Get the charge of a species by parsing the label -//! -//! Examples : -//! - neutral -> 0 -//! - neutral[] -> 0 -//! - charge[+] -> +1 -//! - charge[-1] -> -1 -//! - charge[+2] -> +2 -//! - charge[2-] -> -2 -double SPECMICP_DLL_LOCAL charge_from_label(const std::string& label); - } // end namespace database } // end namespace specmicp #endif // DATABASE_READER_H diff --git a/src/database/reader_common.cpp b/src/database/reader_common.cpp new file mode 100644 index 0000000..4c12216 --- /dev/null +++ b/src/database/reader_common.cpp @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------------- + +Copyright (c) 2015 F. Georget , 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 +#include +#include +#include + +namespace specmicp { +namespace database { + + +void parse_equation(const std::string& equation, std::map &compo) +{ + std::vector 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; + +} + +} //end namespace database +} //end namespace specmicp diff --git a/src/database/reader_common.hpp b/src/database/reader_common.hpp new file mode 100644 index 0000000..7cbdb40 --- /dev/null +++ b/src/database/reader_common.hpp @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------------- + +Copyright (c) 2015 F. Georget , 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. + +-----------------------------------------------------------------------------*/ + +#ifndef SPECMICP_DATABASE_READERCOMMON_HPP +#define SPECMICP_DATABASE_READERCOMMON_HPP + +//! \file reader_common +//! \brief Common functions for database readers + +#include "../types.hpp" +#include +#include + +namespace specmicp { +namespace database { + +//! \brief Parse an equation +void parse_equation(const std::string& equation, std::map &compo); + +//! \brief Get the charge of a species by parsing the label +//! +//! Examples : +//! - neutral -> 0 +//! - neutral[] -> 0 +//! - charge[+] -> +1 +//! - charge[-1] -> -1 +//! - charge[+2] -> +2 +//! - charge[2-] -> -2 +scalar_t charge_from_label(const std::string& label); + +} //end namespace database +} //end namespace specmicp + +#endif // SPECMICP_DATABASE_READERCOMMON_HPP diff --git a/src/database/section_name.hpp b/src/database/section_name.hpp index 108e32a..4811da5 100644 --- a/src/database/section_name.hpp +++ b/src/database/section_name.hpp @@ -1,33 +1,35 @@ #define INDB_SECTION_ELEMENTS "Elements" #define INDB_SECTION_BASIS "Basis" #define INDB_SECTION_AQUEOUS "Aqueous" #define INDB_SECTION_MINERALS "Minerals" #define INDB_SECTION_GAS "Gas" #define INDB_SECTION_SORBED "Sorbed" #define INDB_SECTION_COMPOUNDS "Compounds" #define INDB_ATTRIBUTE_LABEL "label" #define INDB_ATTRIBUTE_ACTIVITY "activity" #define INDB_ATTRIBUTE_ACTIVITY_A "a" #define INDB_ATTRIBUTE_ACTIVITY_B "b" #define INDB_ATTRIBUTE_MOLARMASS "molar_mass" #define INDB_ATTRIBUTE_MOLARVOLUME "molar_volume" #define INDB_ATTRIBUTE_COMPOSITION "composition" #define INDB_ATTRIBUTE_LOGK "log_k" #define INDB_ATTRIBUTE_NBSITEOCCUPIED "nb_sites_occupied" #define INDB_ATTRIBUTE_FLAG_KINETIC "flag_kinetic" #define INDB_OPEN_DELIMITER_CHARGE '[' #define INDB_CLOSE_DELIMITER_CHARGE ']' #define INDB_SECTION_METADATA "Metadata" #define INDB_ATTRIBUTE_NAME "name" #define INDB_ATTRIBUTE_VERSION "version" #define INDB_ATTRIBUTE_PATH "path" #define INDB_ATTRIBUTE_ELEMENT "element" #define INDB_ATTRIBUTE_COMPONENT "component" +#define INDB_MAIN "__main__" + #define INDB_ELECTRON "E[-]" diff --git a/src/database/reader.cpp b/src/database/yaml_reader.cpp similarity index 65% copy from src/database/reader.cpp copy to src/database/yaml_reader.cpp index 1f3e6f8..64badea 100644 --- a/src/database/reader.cpp +++ b/src/database/yaml_reader.cpp @@ -1,690 +1,578 @@ /*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 F. Georget , Princeton University +Copyright (c) 2015 F. Georget , 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.hpp" - -#include "json/json.h" -#include "../utils/json.hpp" -#include -#include - -#include -#include -#include -#include - -#include "utils/log.hpp" - +#include "yaml_reader.hpp" +#include "reader_common.hpp" #include "section_name.hpp" +#include +#include "../utils/io/yaml.hpp" +#include +#include "../utils/log.hpp" #define PRECISION_TEST_CHARGE 1e-6 -#include + namespace specmicp { namespace database { + // safe access to values -std::string obtain_label(Json::Value& species); -void obtain_composition(Json::Value& species, std::map& compo); -scalar_t obtain_logk(Json::Value& species); -bool is_kinetic(Json::Value& species); +std::string obtain_label(const YAML::Node& species, const std::string& section); +void obtain_composition(const YAML::Node& species, std::map& compo, const std::string& label); +scalar_t obtain_logk(const YAML::Node& species, const std::string& label); +bool is_kinetic(const YAML::Node& species,const std::string& label); -void DataReader::parse(const std::string& filepath) +void DataReaderYaml::parse(const std::string& filepath) { std::ifstream datafile(filepath, std::ifstream::binary); if (not datafile.is_open()) { ERROR << "Database not found : " << filepath; std::string message("Database not found : " + filepath); throw std::invalid_argument(message); } data->metadata.path = filepath; parse(datafile); datafile.close(); } -void DataReader::parse(std::istream& input ) +void DataReaderYaml::parse(std::istream& input ) { - Json::Value root; - json::parse_json(input, root); + const YAML::Node root = io::parse_yaml(input); + + const char* indb_main = INDB_MAIN; - json::check_for_mandatory_member(root, INDB_SECTION_METADATA); + io::check_mandatory_yaml_node(root, INDB_SECTION_METADATA, indb_main); parse_metadata(root[INDB_SECTION_METADATA]); + // Basis // ------ - json::check_for_mandatory_member(root, INDB_SECTION_BASIS); + io::check_mandatory_yaml_node(root, INDB_SECTION_BASIS, indb_main); parse_basis(root[INDB_SECTION_BASIS]); // Elements // -------- + io::check_mandatory_yaml_node(root, INDB_SECTION_ELEMENTS, indb_main); ElementList elements; - json::check_for_mandatory_member(root, INDB_SECTION_ELEMENTS); parse_elements(root[INDB_SECTION_ELEMENTS], elements); data->elements = std::move(elements); // Aqueous species // --------------- - json::check_for_mandatory_member(root, INDB_SECTION_AQUEOUS); + io::check_mandatory_yaml_node(root, INDB_SECTION_AQUEOUS, indb_main); AqueousList alist; parse_aqueous(root[INDB_SECTION_AQUEOUS], alist); data->aqueous = std::move(alist); // Minerals // -------- - json::check_for_mandatory_member(root, INDB_SECTION_MINERALS); + io::check_mandatory_yaml_node(root, INDB_SECTION_MINERALS, indb_main); MineralList minerals, minerals_kinetic; parse_minerals(root[INDB_SECTION_MINERALS], minerals, minerals_kinetic); data->minerals = std::move(minerals); data->minerals_kinetic = std::move(minerals_kinetic); // Gas // ---- GasList glist(0, data->nb_component()); - if (root.isMember(INDB_SECTION_GAS)) + if (root[INDB_SECTION_GAS]) parse_gas(root[INDB_SECTION_GAS], glist); else glist.set_valid(); data->gas = std::move(glist); // Sorbed species // -------------- SorbedList slist(0, data->nb_component()); - if (root.isMember(INDB_SECTION_SORBED)) + if (root[INDB_SECTION_SORBED]) parse_sorbed(root[INDB_SECTION_SORBED], slist); else slist.set_valid(); data->sorbed = std::move(slist); // Compounds // --------- CompoundList clist(0, data->nb_component()); - if (root.isMember(INDB_SECTION_COMPOUNDS)) + if (root[INDB_SECTION_COMPOUNDS]) parse_compounds(root[INDB_SECTION_COMPOUNDS], clist); else clist.set_valid(); data->compounds = std::move(clist); } -void DataReader::parse_metadata(Json::Value &root) +void DataReaderYaml::parse_metadata(const YAML::Node& root) { - json::check_for_mandatory_member(root, INDB_ATTRIBUTE_NAME); - data->metadata.name = root[INDB_ATTRIBUTE_NAME].asString(); - json::check_for_mandatory_member(root, INDB_ATTRIBUTE_VERSION); - data->metadata.version = root[INDB_ATTRIBUTE_VERSION].asString(); + data->metadata.name = + io::get_yaml_mandatory(root, INDB_ATTRIBUTE_NAME, INDB_SECTION_METADATA); + data->metadata.version = + io::get_yaml_mandatory(root, INDB_ATTRIBUTE_VERSION, INDB_SECTION_METADATA); } -void DataReader::parse_basis(Json::Value& basis) +void DataReaderYaml::parse_basis(const YAML::Node& basis) { DEBUG << "Size basis : " << basis.size(); data->components = ComponentList(basis.size()); if (data->nb_component() <= 3) throw std::invalid_argument("The basis is too small."); index_t starting_point = 2; for (int id: data->components.range()) { index_t id_in_db = starting_point; if (id_in_db >= data->nb_component()) { throw std::invalid_argument("The basis should contain H2O and E[-]."); } - - Json::Value species = basis[id]; - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LABEL); - std::string label = obtain_label(species); + const YAML::Node& species = basis[id]; + std::string label = obtain_label(species, INDB_SECTION_BASIS); if (label == water_label) { id_in_db = 0; //throw invalid_database("The first component should be "+water_label+"."); } else if (label == electron_label) { id_in_db = 1; //throw invalid_database("The second component should be "+electron_label+"."); } else { ++starting_point; } auto is_already_in_the_database = data->components.get_id(label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + label + "is already in the database."); SPAM << "Parsing component : " << label; ComponentValues values; values.label = label; - - + // activity coeeficients values.ionic_values.charge = charge_from_label(label); - if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) + if (species[INDB_ATTRIBUTE_ACTIVITY]) { - values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); - values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); + values.ionic_values.a_debye = io::get_yaml_mandatory( + species[INDB_ATTRIBUTE_ACTIVITY], INDB_ATTRIBUTE_ACTIVITY_A, label); + values.ionic_values.b_debye = io::get_yaml_mandatory( + species[INDB_ATTRIBUTE_ACTIVITY], INDB_ATTRIBUTE_ACTIVITY_B, label); } - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_MOLARMASS); - values.molar_mass = species[INDB_ATTRIBUTE_MOLARMASS].asDouble(); + // molar mass + values.molar_mass = io::get_yaml_mandatory( + species, INDB_ATTRIBUTE_MOLARMASS, label); data->components.set_values(id_in_db, std::move(values)); - } - + // after this the basis is ready to use data->components.set_valid(); } -void DataReader::parse_aqueous(Json::Value& aqueous, AqueousList& alist) +void DataReaderYaml::parse_aqueous(const YAML::Node& aqueous, AqueousList& alist) { DEBUG << "Parse aqueous species"; alist = AqueousList(aqueous.size(), data->nb_component()); //const auto size = data->nb_aqueous(); for (auto id: alist.range()) { - Json::Value& species = aqueous[static_cast(id)]; + const YAML::Node& species = aqueous[static_cast(id)]; AqueousValues values; - values.label = obtain_label(species); + values.label = obtain_label(species, INDB_SECTION_AQUEOUS); values.ionic_values.charge = charge_from_label(values.label); - if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) + if (species[INDB_ATTRIBUTE_ACTIVITY]) { - values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); - values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); + values.ionic_values.a_debye = io::get_yaml_mandatory( + species[INDB_ATTRIBUTE_ACTIVITY], INDB_ATTRIBUTE_ACTIVITY_A, values.label); + values.ionic_values.b_debye = io::get_yaml_mandatory( + species[INDB_ATTRIBUTE_ACTIVITY], INDB_ATTRIBUTE_ACTIVITY_B, values.label); } - values.logk = obtain_logk(species); + values.logk = obtain_logk(species, values.label); alist.set_values(id, std::move(values)); // equation std::map compo; - obtain_composition(species, compo); + obtain_composition(species, compo, values.label); scalar_t test_charge {0.0}; std::map to_canonicalize; for (const auto& it: compo) { // component ? const auto search = data->components.get_id(it.first); if(search != no_species) { alist.set_nu_ji(id, search, it.second); test_charge += it.second*data->charge_component(search); } // aqueous species ? else { // in the document we parse ? const auto id_aq = alist.get_id(it.first); if (id_aq != no_species) { to_canonicalize.insert({id_aq, it.second}); test_charge += it.second*alist.charge(id_aq); } // cannot be found... else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + alist.get_label(id) +"."); } } } if (std::abs(test_charge - alist.charge(id)) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for aqueous species : '" + alist.get_label(id) + "' - Charge-decomposition - charge species : "+ std::to_string(test_charge - alist.charge(id) )+"."); } for (const auto& tocanon: to_canonicalize) { alist.canonicalize(id, tocanon.first, tocanon.second); } - } + // valid set of aqueous species alist.set_valid(); } -void DataReader::parse_minerals(Json::Value& minerals, MineralList& minerals_list, MineralList& minerals_kinetic_list) +void DataReaderYaml::parse_minerals( + const YAML::Node& minerals, + MineralList& minerals_list, + MineralList& minerals_kinetic_list + ) { + // this one is a little bit more complicated since we need to detect + // if it is a solid phase governed by equilibrium or kinetic + DEBUG << "Parse minerals"; index_t nb_mineral = minerals.size(); // find kinetic minerals int nb_kin = 0; for (int id=0; idnb_component()); minerals_kinetic_list = MineralList(nb_kin, data->nb_component()); // id for each class of minerals index_t id_in_eq=0; index_t id_in_kin=0; for (index_t id=0; id(id)]; + const YAML::Node& species = minerals[static_cast(id)]; //check if material is at equilibrium or governed by kinetics - bool is_kin = is_kinetic(species); MineralValue value; - value.label = std::move(obtain_label(species)); - value.logk = obtain_logk(species); - if (species.isMember(INDB_ATTRIBUTE_MOLARVOLUME)) - { - value.molar_volume = species[INDB_ATTRIBUTE_MOLARVOLUME].asDouble(); - } - else - { - // ###FIXME - value.molar_volume = -1; - } + value.label = std::move(obtain_label(species, INDB_SECTION_MINERALS)); + value.logk = obtain_logk(species, value.label); + + bool is_kin = is_kinetic(species, value.label); + // ###FIXME + value.molar_volume = io::get_yaml_optional(species, INDB_ATTRIBUTE_MOLARVOLUME, value.label, -1); auto& mlist = is_kin?minerals_kinetic_list:minerals_list; auto& true_id = is_kin?id_in_kin:id_in_eq; mlist.set_values(true_id, std::move(value)); // equation // -------- std::map compo; - obtain_composition(species, compo); + obtain_composition(species, compo, value.label); double test_charge = 0; std::map to_canonicalize; for (const auto& it: compo) { auto idc = data->components.get_id(it.first); if(idc != no_species) { // this is a component mlist.set_nu_ji(true_id, idc, it.second); test_charge += it.second * data->charge_component(idc); } else { // this is an aqueous species auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second * data->charge_aqueous(idaq); } else // or something we don't know { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + mlist.get_label(true_id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for mineral : '"+ mlist.get_label(true_id) + "' - total charge : "+std::to_string(test_charge)+"."); } - // canonicalise for (const auto& tocanon: to_canonicalize) { mlist.canonicalize(true_id, data->aqueous, tocanon.first, tocanon.second); } // update index ++true_id; } specmicp_assert(id_in_kin == minerals_kinetic_list.size()); specmicp_assert(id_in_eq == minerals_list.size()); - + // ok after that point minerals_list.set_valid(); minerals_kinetic_list.set_valid(); } -void DataReader::parse_gas(Json::Value& gas, GasList& glist) +void DataReaderYaml::parse_gas(const YAML::Node& gas, GasList& glist) { DEBUG << "Parse gas"; glist = GasList(gas.size(), data->nb_component()); for (auto id: glist.range()) { - Json::Value& species = gas[static_cast(id)]; + const YAML::Node& species = gas[static_cast(id)]; GasValues values; - values.label = obtain_label(species); + values.label = obtain_label(species, INDB_SECTION_GAS); auto is_already_in_the_database = data->gas.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + values.label + "is already in the database."); - values.logk = obtain_logk(species); + values.logk = obtain_logk(species, values.label); glist.set_values(id, std::move(values)); // equation std::map compo; - obtain_composition(species, compo); + obtain_composition(species, compo, values.label); scalar_t test_charge = 0.0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); // component if(idc != no_species) { glist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } // aqueous species else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + data->gas.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+data->gas.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { glist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } glist.set_valid(); } -void DataReader::parse_sorbed(Json::Value& sorbed, SorbedList& slist) +void DataReaderYaml::parse_sorbed(const YAML::Node& sorbed, SorbedList& slist) { DEBUG << "Parse sorbed species"; slist = SorbedList(sorbed.size(), data->nb_component()); for (auto id: slist.range()) { - Json::Value& species = sorbed[static_cast(id)]; + const YAML::Node& species = sorbed[static_cast(id)]; SorbedValues values; - values.label = obtain_label(species); + values.label = obtain_label(species, INDB_SECTION_SORBED); auto is_already_in_the_database = slist.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Sorbed species : " + values.label + "is already in the database."); - values.logk = obtain_logk(species); - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_NBSITEOCCUPIED); - const auto nb_site_occupied = species[INDB_ATTRIBUTE_NBSITEOCCUPIED].asDouble(); + values.logk = obtain_logk(species, values.label); + const scalar_t nb_site_occupied = io::get_yaml_mandatory + (species, INDB_ATTRIBUTE_NBSITEOCCUPIED, values.label); if (nb_site_occupied < 0) { throw db_invalid_data("The number of sites occupied by a sorbed species must be positive. (Species : " + values.label + ", number of sites : " +std::to_string(nb_site_occupied) + ")"); } values.sorption_site_occupied = nb_site_occupied; slist.set_values(id, std::move(values)); std::map compo; - obtain_composition(species, compo); + obtain_composition(species, compo, values.label); double test_charge = 0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); if(idc != no_species) { slist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + slist.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+slist.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { slist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } - } - slist.set_valid(); } -void DataReader::parse_compounds(Json::Value& compounds, CompoundList &clist) +void DataReaderYaml::parse_compounds(const YAML::Node& compounds, CompoundList &clist) { DEBUG << "Parse compounds"; clist = CompoundList(compounds.size(), data->nb_component()); for (auto id: clist.range()) { - Json::Value& species = compounds[static_cast(id)]; + const YAML::Node& species = compounds[static_cast(id)]; - std::string label = obtain_label(species); + std::string label = obtain_label(species, INDB_SECTION_COMPOUNDS); auto is_already_in_the_database = clist.get_id(label); if (is_already_in_the_database != no_species) throw invalid_database("Compounds : " + label + "is already in the database."); clist.set_values(id, label); std::map compo; - obtain_composition(species, compo); + obtain_composition(species, compo, label); double test_charge = 0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); if(idc != no_species) { clist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + clist.get_label(id) +"."); } } } if (std::abs(test_charge) > PRECISION_TEST_CHARGE) { throw db_invalid_data("Total charge is not zero for gas '"+clist.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { clist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } clist.set_valid(); } -void DataReader::parse_elements(Json::Value &elements, ElementList &elist) +void DataReaderYaml::parse_elements(const YAML::Node& elements, ElementList &elist) { if (elements.size() != data->nb_component()) throw db_invalid_data("The number of elements does not corresponds to the number of components"); for (index_t id: data->range_component()) { - Json::Value& elem = elements[static_cast(id)]; - json::check_for_mandatory_member(elem, INDB_ATTRIBUTE_ELEMENT); - json::check_for_mandatory_member(elem, INDB_ATTRIBUTE_COMPONENT); + const YAML::Node& elem = elements[static_cast(id)]; - const std::string elem_label = elem[INDB_ATTRIBUTE_ELEMENT].asString(); - const std::string comp_label = elem[INDB_ATTRIBUTE_COMPONENT].asString(); + const std::string elem_label = io::get_yaml_mandatory( + elem, INDB_ATTRIBUTE_ELEMENT, INDB_SECTION_ELEMENTS); + const std::string comp_label = io::get_yaml_mandatory( + elem, INDB_ATTRIBUTE_COMPONENT, elem_label); index_t id_comp = data->get_id_component(comp_label); if (id_comp == no_species) { throw db_invalid_label("'"+comp_label+"' is not a valid component"); } elist.add_element(elem_label, id_comp); } } -void parse_equation(const std::string& equation, std::map &compo) -{ - std::vector 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; - } -} - -double 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 - } - double 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; - -} - -std::string obtain_label(Json::Value& species) +std::string obtain_label(const YAML::Node& species, const std::string& section) { - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LABEL); - return species[INDB_ATTRIBUTE_LABEL].asString(); + return io::get_yaml_mandatory(species, INDB_ATTRIBUTE_LABEL, section); } -void obtain_composition(Json::Value& species, std::map& compo) +void obtain_composition(const YAML::Node& species, std::map& compo, const std::string& label) { - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_COMPOSITION); - parse_equation(species[INDB_ATTRIBUTE_COMPOSITION].asString(), compo); + const std::string compo_string = io::get_yaml_mandatory(species, INDB_ATTRIBUTE_COMPOSITION, label); + parse_equation(compo_string, compo); } -scalar_t obtain_logk(Json::Value& species) +scalar_t obtain_logk(const YAML::Node& species, const std::string& label) { - json::check_for_mandatory_member(species, INDB_ATTRIBUTE_LOGK); - return species[INDB_ATTRIBUTE_LOGK].asDouble(); + return io::get_yaml_mandatory(species, INDB_ATTRIBUTE_LOGK, label); } - -bool is_kinetic(Json::Value& species) +bool is_kinetic(const YAML::Node& species, const std::string& label) { - bool is_kin {false}; - if (species.isMember(INDB_ATTRIBUTE_FLAG_KINETIC)) - { - is_kin = species[INDB_ATTRIBUTE_FLAG_KINETIC].asBool(); - } - return is_kin; + return io::get_yaml_optional(species, INDB_ATTRIBUTE_FLAG_KINETIC, label, false); } -} // end namespace specmicp -} // end namespace chemy - +} //end namespace database +} //end namespace specmicp diff --git a/src/database/reader.hpp b/src/database/yaml_reader.hpp similarity index 68% copy from src/database/reader.hpp copy to src/database/yaml_reader.hpp index 4ed9c44..bcb034c 100644 --- a/src/database/reader.hpp +++ b/src/database/yaml_reader.hpp @@ -1,140 +1,126 @@ /*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 F. Georget , Princeton University +Copyright (c) 2015 F. Georget , 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. -----------------------------------------------------------------------------*/ -#ifndef DATABASE_READER_H -#define DATABASE_READER_H +#ifndef SPEMCICP_DATABASE_YAMLREADER_HPP +#define SPEMCICP_DATABASE_YAMLREADER_HPP -//! \file reader.hpp Read the database from a json file +//! \file yaml_reader.hpp +//! \brief A reader for a database in yaml format -#include "json/json-forwards.h" #include "module.hpp" -#include + +namespace YAML +{ + class Node; +} namespace specmicp { namespace database { -//! \brief Read a json file containing a database -class SPECMICP_DLL_LOCAL DataReader: public DatabaseModule +class SPECMICP_DLL_LOCAL DataReaderYaml: public DatabaseModule { public: //! \brief Empty constructor - DataReader() {} + DataReaderYaml() {} //! \brief Constructor - DataReader(RawDatabasePtr data): + DataReaderYaml(RawDatabasePtr data): DatabaseModule(data) {} //! \brief Constructor //! //! @param filepath string containing the path to the database - DataReader(const std::string& filepath): + DataReaderYaml(const std::string& filepath): DatabaseModule() { parse(filepath); } //! \brief Constructor //! //! @param input input stream that contains the database - DataReader(std::istream& input): + DataReaderYaml(std::istream& input): DatabaseModule() { parse(input); } //! Return the databes RawDatabasePtr get_database() {return data;} //! \brief Parse the basis section //! //! Contains the list of primary species - void parse_basis(Json::Value& basis_root); + void parse_basis(const YAML::Node& basis_root); //! \brief Parse the aqueous section //! //! Contains the list of secondary species - void parse_aqueous(Json::Value& aqueous_root, AqueousList& alist); + void parse_aqueous(const YAML::Node& aqueous_root, AqueousList& alist); //! \brief Parse the mineral section //! //! Contains the list of minerals void parse_minerals( - Json::Value& minerals, + const YAML::Node& minerals, MineralList &minerals_list, MineralList &minerals_kinetic_list ); //! \brief Parse the gas section - void parse_gas(Json::Value& gas_root, GasList &glist); + void parse_gas(const YAML::Node& gas_root, GasList& glist); //! \brief Parse the sorbed species section - void parse_sorbed(Json::Value& sorbed_root, SorbedList &slist); + void parse_sorbed(const YAML::Node& sorbed_root, SorbedList& slist); //! \brief Parse the compounds - void parse_compounds(Json::Value& compounds, CompoundList &clist); + void parse_compounds(const YAML::Node& compounds, CompoundList& clist); //! \brief Parse the elements - void parse_elements(Json::Value& elements, ElementList &elist); + void parse_elements(const YAML::Node& elements, ElementList& elist); private: //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(std::istream& input); //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(const std::string& filepath); //! \brief Parse the metadata section //! //! we don't do much with them for now.... - void parse_metadata(Json::Value& root); - + void parse_metadata(const YAML::Node& root); }; -//! \brief Parse an equation -void SPECMICP_DLL_LOCAL parse_equation(const std::string &equation, - std::map& compo); - -//! \brief Get the charge of a species by parsing the label -//! -//! Examples : -//! - neutral -> 0 -//! - neutral[] -> 0 -//! - charge[+] -> +1 -//! - charge[-1] -> -1 -//! - charge[+2] -> +2 -//! - charge[2-] -> -2 -double SPECMICP_DLL_LOCAL charge_from_label(const std::string& label); - - -} // end namespace database -} // end namespace specmicp +} //end namespace database +} //end namespace specmicp -#endif // DATABASE_READER_H +#endif // SPEMCICP_DATABASE_YAMLREADER_HPP