diff --git a/src/specmicp/adimensional/adimensional_system_solution_saver.cpp b/src/specmicp/adimensional/adimensional_system_solution_saver.cpp index 82107e6..d62b0e9 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_saver.cpp +++ b/src/specmicp/adimensional/adimensional_system_solution_saver.cpp @@ -1,505 +1,556 @@ /*------------------------------------------------------------------------------- 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 "adimensional_system_solution_saver.hpp" #include "adimensional_system_solution.hpp" -#include "../../../3rdparty/jsoncpp/json/json.h" #include "../../utils/log.hpp" #include "../../utils/dateandtime.hpp" -#include "../../utils/json.hpp" +#include "../../utils/io/yaml.hpp" +#include +#include #include #include #include #include #define SECTION_VALUES "solutions" #define VALUE_META_NAME "name" #define VALUE_META_DATE "date" #define VALUE_META_DATABASE "database" #define VALUE_META_DATABASE_VERSION "database_version" #define SECTION_MAIN "main_variables" #define SECTION_LOGGAMMA "log_gamma" #define SECTION_GAS "gas_fugacities" #define SECTION_SORBED "sorbed_molalities" #define SECTION_AQUEOUS "aqueous_molalities" #define VALUE_FREE_SURFACE "free_surface" #define VALUE_IONIC_STRENGTH "ionic_strength" #define VALUE_INERT "inert_vol_fraction" #define VALUE_COMPONENT "components" #define VALUE_AQUEOUS "aqueous" #define VALUE_MINERAL "minerals" +#include namespace specmicp { -//! \brief Serialize a solution as a JSON-formatted string -std::string format_solution_json( +//! \brief Serialize a solution as a YAML-formatted string +std::string format_solution_yaml( const RawDatabasePtr& the_database, const AdimensionalSystemSolution& the_solution ) { return AdimensionalSystemSolutionSaver(the_database).format_solution(the_solution); } //! \brief Serialize a solution and save it in a file -void save_solution_json( +void save_solution_yaml( const std::string& filename, const RawDatabasePtr& the_database, const AdimensionalSystemSolution& the_solution ) { AdimensionalSystemSolutionSaver(the_database).save_solution(filename, the_solution); } //! \brief Read a solution from a JSON file -AdimensionalSystemSolution parse_solution_json( +AdimensionalSystemSolution parse_solution_yaml( const std::string& filename, const RawDatabasePtr& the_database ) { return AdimensionalSystemSolutionSaver(the_database).parse_solution(filename); } //! \brief Read a solution from a JSON file -AdimensionalSystemSolution parse_solution_json( +AdimensionalSystemSolution parse_solution_yaml( std::istream& input, const RawDatabasePtr& the_database ) { return AdimensionalSystemSolutionSaver(the_database).parse_solution(input); } void AdimensionalSystemSolutionSaver::save_solution( const std::string& filename, const AdimensionalSystemSolution& solution ) { - Json::Value solution_json; - set_json_tree(solution,solution_json); - json::save_json(filename, solution_json); + YAML::Emitter solution_yaml; + set_yaml_emitter(solution, solution_yaml); + io::save_yaml(filename, solution_yaml); } -void AdimensionalSystemSolutionSaver::set_json_tree( +void AdimensionalSystemSolutionSaver::set_yaml_emitter( const AdimensionalSystemSolution& solution, - Json::Value& json_tree + YAML::Emitter& yaml_tree ) { //# Fixme better str for the date - json_tree[VALUE_META_DATE] = dateandtime::now(); - json_tree[VALUE_META_DATABASE] = m_data->metadata.name; - json_tree[VALUE_META_DATABASE_VERSION] = m_data->metadata.version; - - Json::Value& values = json_tree[SECTION_VALUES]; - values.resize(1); - format_solution(values[0], solution); - + yaml_tree.SetDoublePrecision(8); + yaml_tree << YAML::BeginMap; + yaml_tree << YAML::Key << VALUE_META_DATE << YAML::Value << dateandtime::now(); + yaml_tree << YAML::Key << VALUE_META_DATABASE << YAML::Value << m_data->metadata.name; + yaml_tree << YAML::Key << VALUE_META_DATABASE_VERSION << YAML::Value << m_data->metadata.version; + + yaml_tree << YAML::Key << SECTION_VALUES << YAML::Value; + yaml_tree << YAML::BeginSeq; + format_solution(solution, yaml_tree); + yaml_tree << YAML::EndSeq; + yaml_tree << YAML::EndMap; + std::cout << yaml_tree.c_str() << std::endl; } std::string AdimensionalSystemSolutionSaver::format_solution( const AdimensionalSystemSolution& solution ) { - Json::Value solution_json; - set_json_tree(solution, solution_json); - Json::StyledWriter writer; - return writer.write(solution_json); + YAML::Emitter solution_yaml; + set_yaml_emitter(solution, solution_yaml); + if (solution_yaml.good()) + { + throw std::runtime_error("Error in the emitter"); + } + return std::string(solution_yaml.c_str()); } //! \brief Save a set of solutions as a JSON file void AdimensionalSystemSolutionSaver::save_solutions( const std::string& filename, const std::vector& solutions ) { - Json::Value solution_json; + YAML::Emitter yaml_tree; + yaml_tree.SetDoublePrecision(8); - //# Fixme better str for the date - solution_json[VALUE_META_DATE] = dateandtime::now(); - solution_json[VALUE_META_DATABASE] = m_data->metadata.name; - solution_json[VALUE_META_DATABASE_VERSION] = m_data->metadata.version; + yaml_tree << YAML::BeginMap; + yaml_tree << YAML::Key << VALUE_META_DATE << YAML::Value << dateandtime::now(); + yaml_tree << YAML::Key << VALUE_META_DATABASE << YAML::Value << m_data->metadata.name; + yaml_tree << YAML::Key << VALUE_META_DATABASE_VERSION << YAML::Value << m_data->metadata.version; - Json::Value& values = solution_json[SECTION_VALUES]; - values.resize(solutions.size()); + + yaml_tree << YAML::Key << SECTION_VALUES << YAML::Value; + yaml_tree << YAML::BeginSeq; for (int ind=0; ind(yaml_solution, VALUE_INERT, "Solution"); + the_solution.ionic_strength =io::get_yaml_mandatory(yaml_solution, VALUE_IONIC_STRENGTH, "Solution"); the_solution.is_valid = true; } //! \brief Create a solution from a JSON file -void AdimensionalSystemSolutionSaver::parse_solutions(const std::string& filename, - std::vector& solutions_vector) +void AdimensionalSystemSolutionSaver::parse_solutions( + const std::string& filename, + std::vector& solutions_vector + ) { - - Json::Value root; - json::parse_json(filename, root); - - //FIXME error code management + YAML::Node root = io::parse_yaml_file(filename); parse_check_metadata(root); + // TODO : error code management - json::check_for_mandatory_member(root, SECTION_VALUES); - + io::check_mandatory_yaml_node(root, SECTION_VALUES, "__main__"); + if (root[SECTION_VALUES].Type() != YAML::NodeType::Sequence + and root[SECTION_VALUES].size() < 1) + { + throw std::runtime_error("Expecting a non-zero list for section '" SECTION_VALUES "'."); + } int nb_sol = root[SECTION_VALUES].size(); solutions_vector.clear(); solutions_vector.reserve(nb_sol); for (int ind=0; indmetadata.name) + io::check_mandatory_yaml_node(root, VALUE_META_DATABASE, "__main__"); + if (root[VALUE_META_DATABASE].as() != m_data->metadata.name) { WARNING << "SolutionSaver : The name of the database does not match the record in the solution !"; return 1; } - if (root[VALUE_META_DATABASE_VERSION] != m_data->metadata.version) + io::check_mandatory_yaml_node(root, VALUE_META_DATABASE_VERSION, "__main__"); + if (root[VALUE_META_DATABASE_VERSION].as() != m_data->metadata.version) { WARNING << "SolutionSaver : The version of the databases does not match the record in the solution !"; return 2; } return 0; } AdimensionalSystemSolution AdimensionalSystemSolutionSaver::parse_solution(const std::string& filename) { std::ifstream ofile(filename); AdimensionalSystemSolution the_solution = parse_solution(ofile); ofile.close(); return the_solution; } -Json::Value AdimensionalSystemSolutionSaver::format_main_variables( - const AdimensionalSystemSolution& solution) +void AdimensionalSystemSolutionSaver::format_main_variables( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out) { - Json::Value main; - Json::Value components; + out << YAML::Key << SECTION_MAIN << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << VALUE_COMPONENT << YAML::Value; + out << YAML::BeginMap; for (auto component: m_data->range_component()) { - components[m_data->get_label_component(component)] = - solution.main_variables(dof_component(component)); + out << YAML::Key << m_data->get_label_component(component) + << YAML::Value << solution.main_variables(dof_component(component)); } - Json::Value minerals; + out << YAML::EndMap; + out << YAML::Key << VALUE_FREE_SURFACE << YAML::Value << solution.main_variables(dof_surface()); + out << YAML::Key << VALUE_MINERAL << YAML::Value; + out << YAML::BeginMap; for (auto mineral: m_data->range_mineral()) { - minerals[m_data->get_label_mineral(mineral)] = - solution.main_variables(dof_mineral(mineral)); + out << YAML::Key << m_data->get_label_mineral(mineral) + << YAML::Value << solution.main_variables(dof_mineral(mineral)); } - main[VALUE_COMPONENT] = std::move(components); - main[VALUE_FREE_SURFACE] = solution.main_variables(dof_surface()); - main[VALUE_MINERAL] = std::move(minerals); - return main; + out << YAML::EndMap; + out << YAML::EndMap; } -Json::Value AdimensionalSystemSolutionSaver::format_aqueous_molalities( - const AdimensionalSystemSolution& solution +void AdimensionalSystemSolutionSaver::format_aqueous_molalities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ) { - Json::Value aqueous_molalities; + out << YAML::Key << SECTION_AQUEOUS << YAML::Value; + out << YAML::BeginMap; for (auto aqueous: m_data->range_aqueous()) { - aqueous_molalities[m_data->get_label_aqueous(aqueous)] = - solution.secondary_molalities(aqueous); + out << YAML::Key << m_data->get_label_aqueous(aqueous) + << YAML::Value << solution.secondary_molalities(aqueous); } - return aqueous_molalities; + out << YAML::EndMap; } -Json::Value AdimensionalSystemSolutionSaver::format_loggamma( - const AdimensionalSystemSolution& solution +void AdimensionalSystemSolutionSaver::format_loggamma( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ) { - Json::Value gamma; - Json::Value components; + out << YAML::Key << SECTION_LOGGAMMA << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << VALUE_COMPONENT << YAML::Value; + out << YAML::BeginMap; for (auto component: m_data->range_aqueous_component()) { - components[m_data->get_label_component(component)] = - solution.log_gamma(dof_component_gamma(component)); + out << YAML::Key << m_data->get_label_component(component) + << YAML::Value << solution.log_gamma(dof_component_gamma(component)); } - Json::Value aqueous_list; + out << YAML::EndMap; + out << YAML::Key << VALUE_AQUEOUS << YAML::Value; + out << YAML::BeginMap; for (auto aqueous: m_data->range_aqueous()) { - aqueous_list[m_data->get_label_aqueous(aqueous)] = - solution.log_gamma(dof_aqueous_gamma(aqueous)); + out << YAML::Key << m_data->get_label_aqueous(aqueous) + << YAML::Value << solution.log_gamma(dof_aqueous_gamma(aqueous)); } - gamma[VALUE_COMPONENT] = std::move(components); - gamma[VALUE_AQUEOUS] = std::move(aqueous_list); - return gamma; + out << YAML::EndMap; + out << YAML::EndMap; } -Json::Value AdimensionalSystemSolutionSaver::format_gas_fugacities( - const AdimensionalSystemSolution& solution +void AdimensionalSystemSolutionSaver::format_gas_fugacities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ) { - Json::Value gas_fugacities; + out << YAML::Key << SECTION_GAS << YAML::Value; + out << YAML::BeginMap; for (auto gas: m_data->range_gas()) { - gas_fugacities[m_data->get_label_gas(gas)] = - solution.gas_fugacities(gas); + out << YAML::Key << m_data->get_label_gas(gas) + << YAML::Value << solution.gas_fugacities(gas); } - return gas_fugacities; + out << YAML::EndMap; } -Json::Value AdimensionalSystemSolutionSaver::format_sorbed_molalities( - const AdimensionalSystemSolution& solution +void AdimensionalSystemSolutionSaver::format_sorbed_molalities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ) { - Json::Value sorbed_molalities; + out << YAML::Key << SECTION_SORBED << YAML::Value; + out << YAML::BeginMap; for (auto sorbed: m_data->range_sorbed()) { - sorbed_molalities[m_data->get_label_sorbed(sorbed)] = - solution.sorbed_molalities(sorbed); + out << YAML::Key << m_data->get_label_sorbed(sorbed) + << YAML::Value << solution.sorbed_molalities(sorbed); } - return sorbed_molalities; + out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::read_main_variables( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ) { // Initialization // -------------- solution.main_variables = Vector(total_dofs()); solution.main_variables(dof_water()) = 0; solution.main_variables(dof_electron()) = - INFINITY; for (auto id: m_data->range_aqueous_component()) { solution.main_variables(dof_component(id)) = - INFINITY; } solution.main_variables(dof_surface()) = - INFINITY; for (auto mineral: m_data->range_mineral()) { solution.main_variables(dof_mineral(mineral)) = 0; } // Parsing values // -------------- - json::check_for_mandatory_member(root, SECTION_MAIN); - const Json::Value& main = root[SECTION_MAIN]; + io::check_mandatory_yaml_node(root, SECTION_MAIN, SECTION_VALUES); + const YAML::Node& main = root[SECTION_MAIN]; // components - json::check_for_mandatory_member(main, VALUE_COMPONENT); - const Json::Value& components = main[VALUE_COMPONENT]; - for (auto& it: components.getMemberNames()) + io::check_mandatory_yaml_node(main, VALUE_COMPONENT, SECTION_VALUES); + const YAML::Node& components = main[VALUE_COMPONENT]; + for (auto& it: components) { - index_t id = m_data->get_id_component(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_component(label); if (id == no_species) { - throw std::invalid_argument("Component '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Component '" + label + "' does not exist in the database !"); + } + try + { + solution.main_variables(dof_component(id)) = it.second.as(); + } + catch (YAML::BadConversion) + { + if (it.second.as() == "-inf") + { + solution.main_variables(dof_component(id)) = - INFINITY; + } } - solution.main_variables(dof_component(id)) = components[it].asDouble(); } // sorption - if (main.isMember(VALUE_FREE_SURFACE) and not main[VALUE_FREE_SURFACE].isNull()) - { - solution.main_variables(dof_surface()) = main[VALUE_FREE_SURFACE].asDouble(); - } + solution.main_variables(dof_surface()) = + io::get_yaml_optional(main, VALUE_FREE_SURFACE, SECTION_MAIN, -INFINITY); // minerals - json::check_for_mandatory_member(main, VALUE_MINERAL); - const Json::Value& minerals = main[VALUE_MINERAL]; - for (auto& it: minerals.getMemberNames()) + io::check_mandatory_yaml_node(main, VALUE_MINERAL, SECTION_VALUES); + const YAML::Node& minerals = main[VALUE_MINERAL]; + for (auto& it: minerals) { - index_t id = m_data->get_id_mineral(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_mineral(label); if (id == no_species) { - throw std::invalid_argument("Mineral '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Mineral '" + label + "' does not exist in the database !"); } - solution.main_variables(dof_mineral(id)) = minerals[it].asDouble(); + solution.main_variables(dof_mineral(id)) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_loggamma( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.log_gamma = Vector::Zero(m_data->nb_component()+m_data->nb_aqueous()); - json::check_for_mandatory_member(root, SECTION_LOGGAMMA); - const Json::Value& loggamma = root[SECTION_LOGGAMMA]; + io::check_mandatory_yaml_node(root, SECTION_LOGGAMMA, SECTION_VALUES); + const YAML::Node& loggamma = root[SECTION_LOGGAMMA]; // components - json::check_for_mandatory_member(loggamma, VALUE_COMPONENT); - const Json::Value& components = loggamma[VALUE_COMPONENT]; - for (auto& it: components.getMemberNames()) + io::check_mandatory_yaml_node(loggamma, VALUE_COMPONENT, SECTION_LOGGAMMA); + const YAML::Node& components = loggamma[VALUE_COMPONENT]; + for (auto& it: components) { - index_t id = m_data->get_id_component(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_component(label); if (id == no_species) { - throw std::invalid_argument("Component '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Component '" + label + "' does not exist in the database !"); } - solution.log_gamma(dof_component_gamma(id)) = components[it].asDouble(); + solution.log_gamma(dof_component_gamma(id)) = it.second.as(); } // aqueous - json::check_for_mandatory_member(loggamma, VALUE_AQUEOUS); - const Json::Value& aqueous = loggamma[VALUE_AQUEOUS]; - for (auto& it: aqueous.getMemberNames()) + io::check_mandatory_yaml_node(loggamma, VALUE_AQUEOUS, SECTION_LOGGAMMA); + const YAML::Node& aqueous = loggamma[VALUE_AQUEOUS]; + for (auto& it: aqueous) { - index_t id = m_data->get_id_aqueous(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_aqueous(label); if (id == no_species) { - throw std::invalid_argument("Aqueous '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Aqueous '" + label + "' does not exist in the database !"); } - solution.log_gamma(dof_aqueous_gamma(id)) = aqueous[it].asDouble(); + solution.log_gamma(dof_aqueous_gamma(id)) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_aqueous_molalities( - const Json::Value &root, + const YAML::Node& root, AdimensionalSystemSolution &solution ) { solution.secondary_molalities = Vector::Zero(m_data->nb_aqueous()); - json::check_for_mandatory_member(root, SECTION_AQUEOUS); - const Json::Value& aqueous_section = root[SECTION_AQUEOUS]; - for (auto& it: aqueous_section.getMemberNames()) + io::check_mandatory_yaml_node(root, SECTION_AQUEOUS, SECTION_VALUES); + const YAML::Node& aqueous_section = root[SECTION_AQUEOUS]; + for (auto& it: aqueous_section) { - index_t id = m_data->get_id_aqueous(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_aqueous(label); if (id == no_species) { - throw std::invalid_argument("Secondary aqueous species '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Secondary aqueous species '" + label + "' does not exist in the database !"); } - solution.secondary_molalities(id) = aqueous_section[it].asDouble(); + solution.secondary_molalities(id) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_gas_fugacities( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.gas_fugacities = Vector::Zero(m_data->nb_gas()); - json::check_for_mandatory_member(root, SECTION_GAS); - if (root[SECTION_GAS].isNull()) return; - const Json::Value& gas_section = root[SECTION_GAS]; - for (auto& it: gas_section.getMemberNames()) + io::check_mandatory_yaml_node(root, SECTION_GAS, SECTION_VALUES); + const YAML::Node& gas_section = root[SECTION_GAS]; + for (auto& it: gas_section) { - index_t id = m_data->get_id_gas(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_gas(label); if (id == no_species) { - throw std::invalid_argument("Gas '" + it + "' does not exist in the database !"); + throw std::invalid_argument("Gas '" + label + "' does not exist in the database !"); } - solution.gas_fugacities(id) = gas_section[it].asDouble(); + solution.gas_fugacities(id) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_sorbed_molalities( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.sorbed_molalities = Vector::Zero(m_data->nb_sorbed()); - json::check_for_mandatory_member(root, SECTION_SORBED); - if (root[SECTION_SORBED].isNull()) return; - const Json::Value& sorbed_section = root[SECTION_SORBED]; - for (auto& it: sorbed_section.getMemberNames()) + io::check_mandatory_yaml_node(root, SECTION_SORBED, SECTION_VALUES); + const YAML::Node& sorbed_section = root[SECTION_SORBED]; + for (auto& it: sorbed_section) { - index_t id = m_data->get_id_sorbed(it); + const std::string label = it.first.as(); + const index_t id = m_data->get_id_sorbed(label); if (id == no_species) { - throw std::invalid_argument("sorbed species '" + it + "' does not exist in the database !"); + throw std::invalid_argument("sorbed species '" + label + "' does not exist in the database !"); } - solution.sorbed_molalities(id) = sorbed_section[it].asDouble(); + solution.sorbed_molalities(id) = it.second.as(); } } } //end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_solution_saver.hpp b/src/specmicp/adimensional/adimensional_system_solution_saver.hpp index 95e0bdd..a8dc79a 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_saver.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution_saver.hpp @@ -1,189 +1,196 @@ /*------------------------------------------------------------------------------- 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_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONSAVER_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONSAVER_HPP #include "../../types.hpp" #include "../../database.hpp" #include "adimensional_system_numbering.hpp" #include -// forward declaration -namespace Json { - class Value; -} + +namespace YAML { + class Node; + class Emitter; +} //end namespace YAML namespace specmicp { struct AdimensionalSystemSolution; //! \brief This is a serializer for the AdimensionalSystemSolution //! //! This class format the solution is a JSON-formatted string. class SPECMICP_DLL_PUBLIC AdimensionalSystemSolutionSaver : AdimemsionalSystemNumbering { public: AdimensionalSystemSolutionSaver(const RawDatabasePtr& the_database): AdimemsionalSystemNumbering(the_database) {} - //! \brief Format the solution as a JSON-formatted string + //! \brief Format the solution as a YAML-formatted string std::string format_solution(const AdimensionalSystemSolution& solution); - //! \brief Save the solution as a JSON file + //! \brief Save the solution as a YAML file void save_solution( const std::string& filename, const AdimensionalSystemSolution& solution ); - //! \brief Save a set of solutions as a JSON file + //! \brief Save a set of solutions as a YAML file void save_solutions( const std::string& filename, const std::vector& solutions ); - - //! \brief Create a solution from a JSON input + //! \brief Create a solution from a YAML input AdimensionalSystemSolution parse_solution(std::istream& input); - //! \brief Create a solution from a JSON file + //! \brief Create a solution from a YAML file AdimensionalSystemSolution parse_solution(const std::string& filename); - //! \brief Create a solution from a JSON file + //! \brief Create a solution from a YAML file void parse_solutions(const std::string& filename, std::vector& solutions_vector); private: //! \brief Build the Json::Value tree corresponding to the solution (+metadata) - void SPECMICP_DLL_LOCAL set_json_tree( + void SPECMICP_DLL_LOCAL set_yaml_emitter( const AdimensionalSystemSolution& solution, - Json::Value& json_tree + YAML::Emitter& yaml_tree ); //! \brief Build the Json::Value tree corresponding to the solution (w/o metadata) void SPECMICP_DLL_LOCAL format_solution( - Json::Value& root_solution, - const AdimensionalSystemSolution& solution + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ); //! \brief Format the main variables - Json::Value SPECMICP_DLL_LOCAL format_main_variables( - const AdimensionalSystemSolution& solution); + void SPECMICP_DLL_LOCAL format_main_variables( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out + ); //! \brief Format the main variables - Json::Value SPECMICP_DLL_LOCAL format_aqueous_molalities( - const AdimensionalSystemSolution& solution); + void SPECMICP_DLL_LOCAL format_aqueous_molalities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out + ); //! \brief Format the log of activity coefficients - Json::Value SPECMICP_DLL_LOCAL format_loggamma( - const AdimensionalSystemSolution& solution + void SPECMICP_DLL_LOCAL format_loggamma( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ); //! \brief Format the gas fugacities - Json::Value SPECMICP_DLL_LOCAL format_gas_fugacities( - const AdimensionalSystemSolution& solution + void SPECMICP_DLL_LOCAL format_gas_fugacities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ); //! \brief Format the sorbed molalities - Json::Value SPECMICP_DLL_LOCAL format_sorbed_molalities( - const AdimensionalSystemSolution& solution + void SPECMICP_DLL_LOCAL format_sorbed_molalities( + const AdimensionalSystemSolution& solution, + YAML::Emitter& out ); //! \brief Check the metatada : issue warnings if the metadata does not look correct - int parse_check_metadata(const Json::Value& root); + int parse_check_metadata(const YAML::Node& root); //! \brief Parse one solution from the JSON tree void parse_one_solution( - const Json::Value& json_solution, + const YAML::Node& yaml_solution, AdimensionalSystemSolution& the_solution ); //! \brief Parse the main variables void SPECMICP_DLL_LOCAL read_main_variables( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the activity coefficients void SPECMICP_DLL_LOCAL read_aqueous_molalities( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the activity coefficients void SPECMICP_DLL_LOCAL read_loggamma( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the gas fugacities void SPECMICP_DLL_LOCAL read_gas_fugacities( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parsed the sorbed molalities void SPECMICP_DLL_LOCAL read_sorbed_molalities( - const Json::Value& root, + const YAML::Node& root, AdimensionalSystemSolution& solution ); }; //! \brief Serialize a solution as a JSON-formatted string std::string SPECMICP_DLL_PUBLIC -format_solution_json( +format_solution_yaml( const RawDatabasePtr& the_database, const AdimensionalSystemSolution& the_solution ); //! \brief Serialize a solution and save it in a file void SPECMICP_DLL_PUBLIC -save_solution_json( +save_solution_yaml( const std::string& filename, const RawDatabasePtr& the_database, const AdimensionalSystemSolution& the_solution ); //! \brief Read a solution from a JSON file AdimensionalSystemSolution SPECMICP_DLL_PUBLIC -parse_solution_json( +parse_solution_yaml( const std::string& filename, const RawDatabasePtr& the_database ); //! \brief Read a solution from a JSON file AdimensionalSystemSolution SPECMICP_DLL_PUBLIC -parse_solution_json( +parse_solution_yaml( std::istream& input, const RawDatabasePtr& the_database ); } //end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONSAVER_HPP diff --git a/tests/specmicp/adim/adimensional_system_solver.cpp b/tests/specmicp/adim/adimensional_system_solver.cpp index 9e51306..b9727fd 100644 --- a/tests/specmicp/adim/adimensional_system_solver.cpp +++ b/tests/specmicp/adim/adimensional_system_solver.cpp @@ -1,176 +1,176 @@ #include "catch.hpp" #include #include "utils/log.hpp" #include "specmicp/adimensional/adimensional_system.hpp" #include "micpsolver/micpsolver.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/adimensional_system_solution_saver.hpp" #include "database/database.hpp" specmicp::RawDatabasePtr get_test_simple_database() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, }); thedatabase.swap_components(swapping); std::vector to_keep = {"HO[-]", "Ca[2+]"}; thedatabase.keep_only_components(to_keep); thedatabase.remove_half_cell_reactions(std::vector({"H2O", "HO[-]",})) ; return thedatabase.get_database(); } using namespace specmicp; TEST_CASE("Solving adimensional system", "[specmicp, MiCP, program, adimensional, solver]") { specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Error; specmicp::RawDatabasePtr thedatabase = get_test_simple_database(); auto id_h2o = database::DataContainer::water_index(); auto id_oh = thedatabase->get_id_component("HO[-]"); auto id_ca = thedatabase->get_id_component("Ca[2+]"); auto id_ch = thedatabase->get_id_mineral("Portlandite"); SECTION("Solving simple case") { Vector total_concentration = Vector::Zero(thedatabase->nb_component()); total_concentration(id_h2o) = 3.0e4; total_concentration(id_oh) = 2.0e4; total_concentration(id_ca) = 1.0e4; specmicp::AdimensionalSystemConstraints constraints(total_concentration); specmicp::micpsolver::MiCPSolverOptions options; options.maxstep = 100; options.maxiter_maxstep = 100; options.disable_crashing(); options.enable_scaling(); options.disable_descent_direction(); std::shared_ptr system= std::make_shared(thedatabase, constraints); specmicp::micpsolver::MiCPSolver solver(system); solver.set_options(options); Vector x = Vector::Zero(system->total_variables()); x(system->ideq_w()) = 0.8; x(system->ideq_paq(id_oh)) = -2.0; x(system->ideq_paq(id_ca)) = -2.3; system->compute_log_gamma(x); system->set_secondary_concentration(x); solver.solve(x); CHECK(x(system->ideq_w()) == Approx(0.542049).epsilon(1e-4)); CHECK(x(system->ideq_paq(id_oh)) == Approx(-1.480977).epsilon(1e-4)); CHECK(x(system->ideq_paq(id_ca)) == Approx(-1.85413).epsilon(1e-4)); CHECK(x(system->ideq_min(id_ch)) == Approx(0.32966).epsilon(1e-4)); } SECTION("Solving simple case - volum in cm^3") { Vector total_concentration = Vector::Zero(thedatabase->nb_component()); total_concentration(id_h2o) = 0.03; total_concentration(id_oh) = 0.02; total_concentration(id_ca) = 0.01; specmicp::AdimensionalSystemConstraints constraints(total_concentration); specmicp::micpsolver::MiCPSolverOptions options; options.maxstep = 10; options.maxiter_maxstep = 100; options.disable_crashing(); options.enable_scaling(); options.disable_descent_direction(); std::shared_ptr system= std::make_shared(thedatabase, constraints); units::UnitsSet unit_set; unit_set.length = units::LengthUnit::centimeter; system->set_units(unit_set); specmicp::micpsolver::MiCPSolver solver(system); solver.set_options(options); Vector x = Vector::Zero(system->total_variables()); x(system->ideq_w()) = 0.8; x(system->ideq_paq(id_oh)) = -2.0; x(system->ideq_paq(id_ca)) = -2.3; system->compute_log_gamma(x); system->set_secondary_concentration(x); solver.solve(x); CHECK(x(system->ideq_w()) == Approx(0.542049).epsilon(1e-4)); CHECK(x(system->ideq_paq(id_oh)) == Approx(-1.480977).epsilon(1e-4)); CHECK(x(system->ideq_paq(id_ca)) == Approx(-1.85413).epsilon(1e-4)); CHECK(x(system->ideq_min(id_ch)) == Approx(0.32966).epsilon(1e-4)); } SECTION("Automatic solver") { Vector total_concentration = Vector::Zero(thedatabase->nb_component()); total_concentration(id_h2o) = 0.03; total_concentration(id_oh) = 0.02; total_concentration(id_ca) = 0.01; specmicp::Vector x; specmicp::AdimensionalSystemConstraints constraints(total_concentration); specmicp::AdimensionalSystemSolver solver(thedatabase, constraints); solver.initialise_variables(x, 0.8, -2.0); //x(solver.dof_surface()) = -HUGE_VAL; solver.get_options().units_set.length = specmicp::units::LengthUnit::centimeter; solver.get_options().solver_options.maxstep = 10.0; solver.get_options().solver_options.maxiter_maxstep = 100; solver.get_options().solver_options.use_crashing = false; solver.get_options().solver_options.use_scaling = true; solver.get_options().solver_options.disable_descent_direction(); solver.get_options().solver_options.factor_gradient_search_direction = 100; solver.solve(x); AdimensionalSystemSolution solution = solver.get_raw_solution(x); AdimensionalSystemSolutionExtractor extr(solution, thedatabase, solver.get_options().units_set); CHECK(extr.volume_fraction_water() == Approx(0.542049).epsilon(1e-4)); CHECK(extr.log_molality_component(id_oh) == Approx(-1.480977).epsilon(1e-4)); CHECK(extr.log_molality_component(id_ca) == Approx(-1.85413).epsilon(1e-4)); //CHECK(extr.free_surface_concentration() == -HUGE_VAL); CHECK(extr.volume_fraction_mineral(id_ch) == Approx(0.32966).epsilon(1e-4)); AdimensionalSystemSolutionSaver saver(thedatabase); - saver.save_solution("test_solution.js", solution); + saver.save_solution("test_solution.yaml", solution); - AdimensionalSystemSolution solution2 = saver.parse_solution("test_solution.js"); + AdimensionalSystemSolution solution2 = saver.parse_solution("test_solution.yaml"); REQUIRE(solution.main_variables(0) == Approx(solution2.main_variables(0))); REQUIRE(solution.main_variables(id_oh) == Approx(solution2.main_variables(id_oh))); REQUIRE(solution.main_variables(id_ca) == Approx(solution2.main_variables(id_ca))); REQUIRE(extr.volume_fraction_mineral(id_ch) == Approx(solution2.main_variables(extr.dof_mineral(id_ch)))); REQUIRE(solution.log_gamma.norm() == Approx(solution2.log_gamma.norm())); } }