diff --git a/src/reactmicp/io/configuration.cpp b/src/reactmicp/io/configuration.cpp index 13dae68..bd757e4 100644 --- a/src/reactmicp/io/configuration.cpp +++ b/src/reactmicp/io/configuration.cpp @@ -1,332 +1,412 @@ /* ============================================================================= Copyright (c) 2014 - 2016 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 "configuration.hpp" -#include "../../utils/io/yaml.hpp" +#include "utils/io/yaml.hpp" +#include "utils/io/safe_config.hpp" -#include "../../dfpmsolver/parabolic_structs.hpp" -#include "../../reactmicp/solver/runner.hpp" -#include "../../reactmicp/solver/reactive_transport_solver_structs.hpp" +#include "dfpmsolver/parabolic_structs.hpp" +#include "reactmicp/solver/runner.hpp" +#include "reactmicp/solver/reactive_transport_solver_structs.hpp" #include "saturated_react.hpp" -#include "../../database/database.hpp" +#include "database/database.hpp" #include #include #define S_DFPM "transport_options" -#define S_DFPM_A_MAX_ITER "maximum_iteration" +#define S_DFPM_A_MAX_ITER "maximum_iterations" #define S_DFPM_A_RES_TOL "residual_tolerance" #define S_DFPM_A_ABS_TOL "absolute_tolerance" #define S_DFPM_A_STEP_TOL "step_tolerance" #define S_DFPM_A_TRSHOLD_STATIONARY "threshold_stationary" #define S_DFPM_A_MAX_STEP_LENGTH "maximum_step_length" -#define S_DFPM_A_MAX_STEP_MAX_ITER "maximum_step_maximum_iteration" +#define S_DFPM_A_MAX_STEP_MAX_ITER "maximum_step_maximum_iterations" #define S_DFPM_A_SPARSE_SOLVER "sparse_solver" #define S_DFPM_A_LINESEARCH "linesearch" #define S_DFPM_A_QUASI_NEWTON "quasi_newton" #define S_REACTMICP "reactmicp_options" #define S_REACTMICP_A_RES_TOL "residual_tolerance" #define S_REACTMICP_A_ABS_TOL "absolute_tolerance" #define S_REACTMICP_A_STEP_TOL "step_tolerance" #define S_REACTMICP_A_GOOD_ENOUGH_TOL "good_enough_tolerance" -#define S_REACTMICP_A_MAX_ITER "maximum_iteration" +#define S_REACTMICP_A_MAX_ITER "maximum_iterations" #define S_REACTMICP_A_IMPL_UPSCALING "implicit_upscaling" #define S_OUTPUT "reactmicp_output" #define S_OUTPUT_A_POROSITY "porosity" #define S_OUTPUT_A_PH "ph" #define S_OUTPUT_A_DIFFUSIVITY "diffusivity" #define S_OUTPUT_A_VOLFRAC_MINERAL "volume_fraction_solid" #define S_OUTPUT_A_TOT_AQ_CONC "total_aqueous_concentration" #define S_OUTPUT_A_TOT_S_CONC "total_solid_concentration" #define S_OUTPUT_A_TOT_CONC "total_concentration" #define S_OUTPUT_A_SATINDEX "saturation_index" #define S_SIMULINFO "simulation" #define S_SIMULINFO_A_NAME "name" #define S_SIMULINFO_A_OUTPUTPREFIX "output_prefix" #define S_SIMULINFO_A_PRINTITER "print_iter_info" #define S_SIMULINFO_A_OUTPUTSTEP "output_step" + + +#define S_TIMESTEP_A_LOWER_BOUND "minimum_dt" +#define S_TIMESTEP_A_UPPER_BOUND "maximum_dt" +#define S_TIMESTEP_A_RESTART_DT "restart_dt" +#define S_TIMESTEP_A_LOWER_TARGET "lower_iterations_target" +#define S_TIMESTEP_A_UPPER_TARGET "upper_iterations_target" +#define S_TIMESTEP_A_AVERAGE_PARAMETER "average_parameter" +#define S_TIMESTEP_A_FACTOR_IF_FAILURE "decrease_factor_if_failure" +#define S_TIMESTEP_A_FACTOR_IF_MINIMUM "increase_factor_if_minumum" +#define S_TIMESTEP_A_FACTOR_IF_DECREASE "decrease_factor" +#define S_TIMESTEP_A_FACTOR_IF_INCREASE "increase_factor" + namespace specmicp { namespace io { std::string clean_label(std::string label); void configure_transport_options( dfpmsolver::ParabolicDriverOptions& options, const YAML::Node& configuration ) { check_mandatory_yaml_node(configuration, S_DFPM, "__main__"); const YAML::Node& conf = configuration[S_DFPM]; options.absolute_tolerance = get_yaml_optional(conf, S_DFPM_A_ABS_TOL, S_DFPM, DFPM_DEFAULT_ABS_TOL); options.residuals_tolerance = get_yaml_optional(conf, S_DFPM_A_RES_TOL, S_DFPM, DFPM_DEFAULT_RES_TOL); options.step_tolerance = get_yaml_optional(conf, S_DFPM_A_STEP_TOL, S_DFPM, DFPM_DEFAULT_STEP_TOL); options.maximum_iterations = get_yaml_optional(conf, S_DFPM_A_MAX_ITER, S_DFPM, DFPM_DEFAULT_MAX_ITER); options.maximum_step_length = get_yaml_optional(conf, S_DFPM_A_MAX_STEP_LENGTH, S_DFPM, DFPM_DEFAULT_MAX_STEP_LENGTH); options.max_iterations_at_max_length = get_yaml_optional(conf, S_DFPM_A_MAX_STEP_MAX_ITER, S_DFPM, DFPM_DEFAULT_MAX_ITER_MAX_LENGTH); options.threshold_stationary_point = get_yaml_optional(conf, S_DFPM_A_TRSHOLD_STATIONARY, S_DFPM, DFPM_DEFAULT_TRSHOLD_STATIONARY); options.quasi_newton = get_yaml_optional(conf, S_DFPM_A_QUASI_NEWTON, S_DFPM, DFPM_PARABOLIC_DEFAULT_QUASI_NEWTON); if (conf[S_DFPM_A_SPARSE_SOLVER]) { std::string sparse_solver = conf[S_DFPM_A_SPARSE_SOLVER].as(); if (sparse_solver == "LU") options.sparse_solver = sparse_solvers::SparseSolver::SparseLU; else if (sparse_solver == "QR") options.sparse_solver = sparse_solvers::SparseSolver::SparseQR; else if (sparse_solver == "GMRES") options.sparse_solver = sparse_solvers::SparseSolver::GMRES; else if (sparse_solver == "BiCGSTAB") options.sparse_solver = sparse_solvers::SparseSolver::BiCGSTAB; else throw std::runtime_error("Invalid argument for the sparse solver : '"+sparse_solver+"'.\n" +"Available solvers : 'LU' / 'QR' / 'GMRES' / 'BiCGSTAB'."); } if (conf[S_DFPM_A_LINESEARCH]) { std::string linesearch = conf[S_DFPM_A_LINESEARCH].as(); if (linesearch == "backtracking") options.linesearch = dfpmsolver::ParabolicLinesearch::Bactracking; else if (linesearch == "strang") options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; else throw std::runtime_error("Invalid argument for the linesearch : '"+linesearch+"'.\n" +"Available options : 'bactracking' / 'strang'."); } } -#define get_attribute(attribute, var, type) \ - if (config[attribute]) { \ - options. var = get_yaml_attribute(config, attribute, S_DFPM); \ - } - -void configure_transport_options_conservative( +void configure_transport_options( dfpmsolver::ParabolicDriverOptions& options, - const YAML::Node& config + io::YAMLConfigHandle&& conf ) { - get_attribute(S_DFPM_A_ABS_TOL, absolute_tolerance, double) - get_attribute(S_DFPM_A_RES_TOL, step_tolerance, double) - get_attribute(S_DFPM_A_MAX_ITER, maximum_iterations, int) - get_attribute(S_DFPM_A_MAX_STEP_LENGTH, maximum_step_length, double) - get_attribute(S_DFPM_A_MAX_STEP_MAX_ITER, max_iterations_at_max_length, int) - get_attribute(S_DFPM_A_TRSHOLD_STATIONARY, threshold_stationary_point, double) - get_attribute(S_DFPM_A_QUASI_NEWTON, quasi_newton, int) - - if (config[S_DFPM_A_SPARSE_SOLVER]) + conf.set_if_attribute_exists(options.absolute_tolerance, S_DFPM_A_ABS_TOL, 0.0); + conf.set_if_attribute_exists(options.residuals_tolerance, S_DFPM_A_RES_TOL, 0.0, 1.0); + conf.set_if_attribute_exists(options.step_tolerance, S_DFPM_A_STEP_TOL, 0.0, 1.0); + conf.set_if_attribute_exists(options.maximum_iterations, S_DFPM_A_MAX_ITER, 0); + conf.set_if_attribute_exists(options.maximum_step_length, S_DFPM_A_MAX_STEP_LENGTH, 0.0); + conf.set_if_attribute_exists(options.max_iterations_at_max_length, S_DFPM_A_MAX_STEP_MAX_ITER, 0); + conf.set_if_attribute_exists(options.threshold_stationary_point, S_DFPM_A_TRSHOLD_STATIONARY, 0.0, 1.0); + conf.set_if_attribute_exists(options.quasi_newton, S_DFPM_A_QUASI_NEWTON); + + if (conf.has_attribute(S_DFPM_A_SPARSE_SOLVER)) { - std::string sparse_solver = config[S_DFPM_A_SPARSE_SOLVER].as(); + std::string sparse_solver = conf.get_attribute(S_DFPM_A_SPARSE_SOLVER); if (sparse_solver == "LU") options.sparse_solver = sparse_solvers::SparseSolver::SparseLU; else if (sparse_solver == "QR") options.sparse_solver = sparse_solvers::SparseSolver::SparseQR; else if (sparse_solver == "GMRES") options.sparse_solver = sparse_solvers::SparseSolver::GMRES; else if (sparse_solver == "BiCGSTAB") options.sparse_solver = sparse_solvers::SparseSolver::BiCGSTAB; else - throw std::runtime_error("Invalid argument for the sparse solver : '"+sparse_solver+"'.\n" - +"Available solvers : 'LU' / 'QR' / 'GMRES' / 'BiCGSTAB'."); + conf.report_error( + YAMLConfigError::InvalidArgument, + "Invalid argument for the sparse solver : '" + + sparse_solver + "'.\n" + "Available solvers :" + "'LU' / 'QR' / 'GMRES' / 'BiCGSTAB'." + ); } - if (config[S_DFPM_A_LINESEARCH]) + if (conf.has_attribute(S_DFPM_A_LINESEARCH)) { - std::string linesearch = config[S_DFPM_A_LINESEARCH].as(); + std::string linesearch = conf.get_attribute(S_DFPM_A_LINESEARCH); if (linesearch == "backtracking") options.linesearch = dfpmsolver::ParabolicLinesearch::Bactracking; else if (linesearch == "strang") options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; else - throw std::runtime_error("Invalid argument for the linesearch : '"+linesearch+"'.\n" - +"Available options : 'bactracking' / 'strang'."); + conf.report_error( + YAMLConfigError::InvalidArgument, + "Invalid argument for the linesearch : '" + + linesearch + "'.\n" + "Available options : 'bactracking' / 'strang'." + ); } } +#define print_options(attr, var) \ + output << " \t - " << attr << " : " << var << std::endl; + +void print_transport_options( + dfpmsolver::ParabolicDriverOptions& options, + std::ostream& output + ) +{ + print_options(S_DFPM_A_RES_TOL, options.residuals_tolerance); + print_options(S_DFPM_A_ABS_TOL, options.absolute_tolerance); + print_options(S_DFPM_A_STEP_TOL, options.step_tolerance); + print_options(S_DFPM_A_MAX_ITER, options.maximum_iterations); + print_options(S_DFPM_A_MAX_STEP_LENGTH, options.maximum_step_length); + print_options(S_DFPM_A_MAX_STEP_MAX_ITER, options.max_iterations_at_max_length); + print_options(S_DFPM_A_TRSHOLD_STATIONARY, options.threshold_stationary_point); + print_options(S_DFPM_A_QUASI_NEWTON, options.quasi_newton); +} + void configure_reactmicp_options( reactmicp::solver::ReactiveTransportOptions& options, - const YAML::Node& configuration + io::YAMLConfigHandle&& conf ) { - check_mandatory_yaml_node(configuration, S_REACTMICP, "__main__"); - const YAML::Node& conf = configuration[S_REACTMICP]; - - options.residuals_tolerance = get_yaml_optional(conf, - S_REACTMICP_A_RES_TOL, S_REACTMICP, REACTMICP_DEFAULT_RES_TOL); - options.absolute_residuals_tolerance = get_yaml_optional(conf, - S_REACTMICP_A_ABS_TOL, S_REACTMICP, REACTMICP_DEFAULT_ABS_TOL); - options.step_tolerance = get_yaml_optional(conf, - S_REACTMICP_A_STEP_TOL, S_REACTMICP, REACTMICP_DEFAULT_STEP_TOL); - options.good_enough_tolerance = get_yaml_optional(conf, - S_REACTMICP_A_GOOD_ENOUGH_TOL, S_REACTMICP, REACTMICP_DEFAULT_GOOD_ENOUTH_TOL); - options.implicit_upscaling = get_yaml_optional(conf, - S_REACTMICP_A_IMPL_UPSCALING, S_REACTMICP, REACTMICP_DEFAULT_IMPL_UPSCALING); - options.maximum_iterations = get_yaml_optional(conf, - S_REACTMICP_A_MAX_ITER, S_REACTMICP, REACTMICP_DEFAULT_MAX_ITER); + conf.set_if_attribute_exists(options.residuals_tolerance, + S_REACTMICP_A_RES_TOL, 0.0, 1.0); + conf.set_if_attribute_exists(options.absolute_residuals_tolerance, + S_REACTMICP_A_ABS_TOL, 0.0); + conf.set_if_attribute_exists(options.step_tolerance, + S_REACTMICP_A_STEP_TOL, 0.0, 1.0); + conf.set_if_attribute_exists(options.good_enough_tolerance, + S_REACTMICP_A_GOOD_ENOUGH_TOL, 0.0); + conf.set_if_attribute_exists(options.implicit_upscaling, + S_REACTMICP_A_IMPL_UPSCALING); + conf.set_if_attribute_exists(options.maximum_iterations, + S_REACTMICP_A_MAX_ITER, 0); } void SPECMICP_DLL_PUBLIC configure_reactmicp_output( io::OutputNodalVariables& output_policy, const reactmicp::solver::SimulationInformation& simul_info, const YAML::Node& configuration ) { if (not configuration[S_OUTPUT]) return; const YAML::Node& conf = configuration[S_OUTPUT]; database::Database db_manager(output_policy.get_database()); if (conf[S_OUTPUT_A_PH] and conf[S_OUTPUT_A_PH].as()) { output_policy.register_pH(simul_info.complete_filepath("ph", "dat")); } if (conf[S_OUTPUT_A_POROSITY] and conf[S_OUTPUT_A_POROSITY].as()) { output_policy.register_porosity(simul_info.complete_filepath("porosity", "dat")); } if (conf[S_OUTPUT_A_DIFFUSIVITY] and conf[S_OUTPUT_A_DIFFUSIVITY].as()) { output_policy.register_diffusion_coefficient(simul_info.complete_filepath("diffusivity", "dat")); } if (conf[S_OUTPUT_A_VOLFRAC_MINERAL]) { for (auto it: conf[S_OUTPUT_A_VOLFRAC_MINERAL]) { auto label = it.as(); index_t id = db_manager.safe_mineral_label_to_id(label); auto simple_label = clean_label(label); output_policy.register_volume_fraction_mineral( id, simul_info.complete_filepath("phi_"+simple_label, "dat")); } } if (conf[S_OUTPUT_A_TOT_CONC]) { for (auto it: conf[S_OUTPUT_A_TOT_CONC]) { auto label = it.as(); index_t id = db_manager.safe_component_label_to_id(label); auto simple_label = clean_label(label); output_policy.register_total_concentration( id, simul_info.complete_filepath("t_"+simple_label, "dat")); } } if (conf[S_OUTPUT_A_TOT_AQ_CONC]) { for (auto it: conf[S_OUTPUT_A_TOT_AQ_CONC]) { auto label = it.as(); index_t id = db_manager.safe_component_label_to_id(label); auto simple_label = clean_label(label); output_policy.register_total_aqueous_concentration( id, simul_info.complete_filepath("c_"+simple_label, "dat")); } } if (conf[S_OUTPUT_A_TOT_S_CONC]) { for (auto it: conf[S_OUTPUT_A_TOT_S_CONC]) { auto label = it.as(); index_t id = db_manager.safe_component_label_to_id(label); auto simple_label = clean_label(label); output_policy.register_total_solid_concentration( id, simul_info.complete_filepath("s_"+simple_label, "dat")); } } if (conf[S_OUTPUT_A_SATINDEX]) { for (auto it: conf[S_OUTPUT_A_SATINDEX]) { auto label = it.as(); index_t id = db_manager.safe_mineral_kinetic_label_to_id(label); auto simple_label = clean_label(label); output_policy.register_saturation_index_mineral_kinetic( id, simul_info.complete_filepath("si_"+simple_label, "dat")); } } } - -reactmicp::solver::SimulationInformation configure_simulation_information( - const YAML::Node& configuration +reactmicp::solver::SimulationInformation SPECMICP_DLL_PUBLIC +configure_simulation_information( + io::YAMLConfigHandle&& conf ) { - check_mandatory_yaml_node(configuration, S_SIMULINFO, "__main__"); - const YAML::Node& conf = configuration[S_SIMULINFO]; reactmicp::solver::SimulationInformation simul_info( - get_yaml_mandatory(conf, S_SIMULINFO_A_NAME, S_SIMULINFO), - get_yaml_mandatory(conf, S_SIMULINFO_A_OUTPUTSTEP, S_SIMULINFO) - ); - if (conf[S_SIMULINFO_A_OUTPUTPREFIX]) - simul_info.output_prefix = conf[S_SIMULINFO_A_OUTPUTPREFIX].as(); - if (conf[S_SIMULINFO_A_PRINTITER]) - simul_info.print_iter_info = conf[S_SIMULINFO_A_PRINTITER].as(); + conf.get_required_attribute(S_SIMULINFO_A_NAME), + conf.get_required_attribute(S_SIMULINFO_A_OUTPUTSTEP) + ); + conf.set_if_attribute_exists(simul_info.output_prefix, S_SIMULINFO_A_OUTPUTPREFIX); + conf.set_if_attribute_exists(simul_info.print_iter_info, S_SIMULINFO_A_PRINTITER); return simul_info; } + std::string clean_label(std::string label) { static std::vector orig {']', '[', '(', ')', '+', '-', ','}; static std::vector repl {'_', '_', '_', '_', 'p', 'm', '_'}; for (auto it = label.begin(); it!=label.end(); ++it) { auto itf = std::find(orig.begin(), orig.end(), *it); if (itf != orig.end()) { *it = repl[itf - orig.begin()]; } } std::transform(label.begin(), label.end(), label.begin(), ::tolower); return label; } + +void SPECMICP_DLL_PUBLIC +configure_reactmicp_timestepper( + reactmicp::solver::TimestepperOptions& options, + io::YAMLConfigHandle&& conf + ) +{ + options.lower_bound = conf.get_required_attribute( + S_TIMESTEP_A_LOWER_BOUND, 0.0); + options.upper_bound = conf.get_required_attribute( + S_TIMESTEP_A_UPPER_BOUND, 0.0); + + if (conf.has_attribute(S_TIMESTEP_A_RESTART_DT)) { + options.restart_timestep = conf.get_attribute( + S_TIMESTEP_A_RESTART_DT, 0.0); + } else { + options.restart_timestep = options.lower_bound; + } + + conf.set_if_attribute_exists(options.iteration_lower_target, + S_TIMESTEP_A_LOWER_TARGET, 0.0); + conf.set_if_attribute_exists(options.iteration_upper_target, + S_TIMESTEP_A_UPPER_TARGET, 0.0); + if (options.iteration_upper_target < options.iteration_lower_target) { + conf.report_error( + YAMLConfigError::InvalidArgument, + "Iterations lower target is greater than the upper target."); + } + + conf.set_if_attribute_exists(options.alpha_average, + S_TIMESTEP_A_AVERAGE_PARAMETER, + 0.0, 1.0); + conf.set_if_attribute_exists(options.decrease_factor, + S_TIMESTEP_A_FACTOR_IF_DECREASE, + 0.0, 1.0); + conf.set_if_attribute_exists(options.increase_factor, + S_TIMESTEP_A_FACTOR_IF_INCREASE, + 1.0); + conf.set_if_attribute_exists(options.increase_error_minimization, + S_TIMESTEP_A_FACTOR_IF_MINIMUM, + 0.0); + conf.set_if_attribute_exists(options.decrease_failure, + S_TIMESTEP_A_FACTOR_IF_FAILURE, + 0.0); + + + +} + } //end namespace io } //end namespace specmicp diff --git a/src/reactmicp/io/configuration.hpp b/src/reactmicp/io/configuration.hpp index 74ef305..784366d 100644 --- a/src/reactmicp/io/configuration.hpp +++ b/src/reactmicp/io/configuration.hpp @@ -1,94 +1,113 @@ /* ============================================================================= Copyright (c) 2014 - 2016 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_REACTMICP_IO_CONFIGURATION_HPP #define SPECMICP_REACTMICP_IO_CONFIGURATION_HPP -#include "../../types.hpp" +//! \file reactmicp/io/configuration.hpp +//! \brief Configure reactmicp + +#include "types.hpp" +#include namespace YAML { class Node; } //end namespace YAML namespace specmicp { struct AdimensionalSystemSolverOptions; namespace dfpmsolver { struct ParabolicDriverOptions; } //end namespace dfpmsolver namespace reactmicp { namespace solver { struct ReactiveTransportOptions; struct SimulationInformation; +struct TimestepperOptions; } //end namespace solver } //end namespace reactmicp namespace io { +class YAMLConfigHandle; class OutputNodalVariables; void SPECMICP_DLL_PUBLIC configure_transport_options( dfpmsolver::ParabolicDriverOptions& options, const YAML::Node& configuration ); +// +void SPECMICP_DLL_PUBLIC configure_transport_options( + dfpmsolver::ParabolicDriverOptions& options, + io::YAMLConfigHandle&& configuration + ); -void SPECMICP_DLL_PUBLIC configure_transport_options_conservative( +void SPECMICP_DLL_PUBLIC print_transport_options( dfpmsolver::ParabolicDriverOptions& options, - const YAML::Node& configuration + std::ostream& output ); void SPECMICP_DLL_PUBLIC configure_reactmicp_options( reactmicp::solver::ReactiveTransportOptions& options, - const YAML::Node& configuration + io::YAMLConfigHandle&& configuration ); void SPECMICP_DLL_PUBLIC configure_reactmicp_output( io::OutputNodalVariables& output_policy, const reactmicp::solver::SimulationInformation& simul_info, const YAML::Node& configuration ); reactmicp::solver::SimulationInformation SPECMICP_DLL_PUBLIC -configure_simulation_information(const YAML::Node& configuration); +configure_simulation_information( + io::YAMLConfigHandle&& configuration + ); +//! \brief Configure the timestepper options +void SPECMICP_DLL_PUBLIC +configure_reactmicp_timestepper( + reactmicp::solver::TimestepperOptions& options, + io::YAMLConfigHandle&& configuration + ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_REACTMICP_IO_CONFIGURATION_HPP diff --git a/src/reactmicp/io/configuration_unsaturated.cpp b/src/reactmicp/io/configuration_unsaturated.cpp index 40bd47d..1265abc 100644 --- a/src/reactmicp/io/configuration_unsaturated.cpp +++ b/src/reactmicp/io/configuration_unsaturated.cpp @@ -1,218 +1,218 @@ /* ============================================================================= Copyright (c) 2014 - 2016 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 "utils/io/yaml.hpp" // to remove #include "utils/io/safe_config.hpp" #include "configuration_unsaturated.hpp" #include "database/data_container.hpp" #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "specmicp/io/configuration.hpp" #include "reactmicp/systems/unsaturated/boundary_conditions.hpp" #include "reactmicp/systems/unsaturated/equilibrium_stagger.hpp" #include "utils/string_algorithms.hpp" #define S_BCS_A_GASNODE "gas_nodes" #define S_BCS_A_FIXEDNODE "fixed_nodes" #define S_BCS_SS_CONSTRAINTS "constraints" #define S_BCS_SS_CONSTRAINTS_A_DEFAULT "default" #define S_BCS_SS_CONSTRAINTS_A_OTHERS "others" #define S_BCS_SS_CONSTRAINTS_A_NAME "name" #define S_BCS_SS_CONSTRAINTS_A_FORK_FROM "fork_from" #define S_BCS_SS_CONSTRAINTS_A_NODE "nodes" #define S_OPTIONS_SS_DEFAULT "default" #define S_OPTIONS_SS_OTHERS "others" #define S_OPTIONS_SS_OTHERS_A_NAME "name" #define S_OPTIONS_SS_OTHERS_A_FORK_FROM "fork_from" #define S_OPTIONS_SS_OTHERS_A_NODE "nodes" namespace specmicp { using reactmicp::systems::unsaturated::BoundaryConditions; using reactmicp::systems::unsaturated::EquilibriumOptionsVector; namespace io { static void configure_bcs_constraints( BoundaryConditions* bcs, const database::DataContainer * const raw_data, YAMLConfigHandle&& conf); //! \brief Configure the boundary condition std::shared_ptr configure_unsaturated_boundary_conditions( uindex_t nb_nodes, const database::DataContainer * const raw_data, YAMLConfigHandle&& configuration ) { auto bcs = BoundaryConditions::make(nb_nodes); if (configuration.has_node(S_BCS_A_FIXEDNODE)) { std::vector fixed_nodes = configuration.list_to_vector(S_BCS_A_FIXEDNODE); bcs->add_fixed_nodes(fixed_nodes); } if (configuration.has_node(S_BCS_A_GASNODE)) { const std::vector gas_nodes = configuration.list_to_vector(S_BCS_A_GASNODE); bcs->add_gas_nodes(gas_nodes); } if (configuration.has_section(S_BCS_SS_CONSTRAINTS)) { configure_bcs_constraints(bcs.get(), raw_data, configuration.get_section(S_BCS_SS_CONSTRAINTS) ); } return bcs; } void configure_bcs_constraints( BoundaryConditions* bcs, const database::DataContainer * const raw_data, - YAMLConfigHandle&& conf) + YAMLConfigHandle&& conf + ) { // default constraints if (conf.has_section(S_BCS_SS_CONSTRAINTS_A_DEFAULT)) { configure_specmicp_constraints( bcs->get_constraint("default"), raw_data, conf.get_section(S_BCS_SS_CONSTRAINTS_A_DEFAULT) ); } // other constraints if (conf.has_section(S_BCS_SS_CONSTRAINTS_A_OTHERS)) { auto others = conf.get_section(S_BCS_SS_CONSTRAINTS_A_OTHERS); for (uindex_t ind=0; ind( S_BCS_SS_CONSTRAINTS_A_NAME ); if (subconf.has_attribute(S_BCS_SS_CONSTRAINTS_A_FORK_FROM)) { auto old_name = subconf.get_attribute( S_BCS_SS_CONSTRAINTS_A_FORK_FROM ); if (not bcs->has_constraint(old_name)) { subconf.report_error( YAMLConfigError::InvalidArgument, "'" + old_name + "' is not an " "existing constraint" ); } bcs->fork_constraint(old_name, name); } else { bcs->add_constraint(name); } if (subconf.has_node(S_BCS_SS_CONSTRAINTS_A_NODE)) { auto nodes = subconf.list_to_vector( S_BCS_SS_CONSTRAINTS_A_NODE); for (const auto& node: nodes) { bcs->set_constraint(node, name); } } configure_specmicp_constraints( bcs->get_constraint(name), raw_data, std::move(subconf)); } } } std::shared_ptr configure_unsaturated_equilibrium_options( uindex_t nb_nodes, const units::UnitsSet& the_units, - const RORichYAMLNode& configuration + YAMLConfigHandle&& configuration ) { auto opts = EquilibriumOptionsVector::make(nb_nodes); - if (configuration.check(S_OPTIONS_SS_DEFAULT)) + if (configuration.has_section(S_OPTIONS_SS_DEFAULT)) { - YAML::Node conf = configuration[S_OPTIONS_SS_DEFAULT].get_raw_node(); auto& def_opts = opts->get("default"); - configure_specmicp_options_conservative(def_opts, conf); - def_opts.units_set = the_units; - + configure_specmicp_options( + def_opts, + the_units, + configuration.get_section(S_OPTIONS_SS_DEFAULT)); } - if (configuration.check(S_OPTIONS_SS_OTHERS)) + if (configuration.has_section(S_OPTIONS_SS_OTHERS)) { - auto subconf = configuration[S_OPTIONS_SS_OTHERS].get_raw_node(); - for (const auto& conf: subconf) { - const auto name = io::get_yaml_mandatory( - conf, S_OPTIONS_SS_OTHERS_A_NAME, S_OPTIONS_SS_OTHERS); - - if (conf[S_OPTIONS_SS_OTHERS_A_FORK_FROM]) { - const auto fork_from = io::get_yaml_attribute( - conf, S_OPTIONS_SS_OTHERS_A_FORK_FROM, S_OPTIONS_SS_OTHERS - ); + auto subconf = configuration.get_section(S_OPTIONS_SS_OTHERS); + const auto size = subconf.size(); + for (uindex_t ind=0; ind( + S_OPTIONS_SS_OTHERS_A_NAME); + + if (conf.has_attribute(S_OPTIONS_SS_OTHERS_A_FORK_FROM)) { + const auto fork_from = conf.get_attribute( + S_OPTIONS_SS_OTHERS_A_FORK_FROM); if (not opts->has_value(fork_from)) { - throw std::invalid_argument("'" + fork_from + "' is not an " - "existing set of options. \n" - "Error occuring while parsing equilibrium options."); + conf.report_error( + YAMLConfigError::InvalidArgument, + "'" + fork_from + "' is not an " + "existing set of options. \n" + ); } - auto& new_opts = opts->fork(fork_from, name); - configure_specmicp_options_conservative(new_opts, conf); - new_opts.units_set = the_units; + opts->fork(fork_from, name); } else { opts->push_back_cache(name, AdimensionalSystemSolverOptions()); - auto& new_opts = opts->get(name); - configure_specmicp_options_conservative(new_opts, conf); - new_opts.units_set = the_units; } - if (subconf[S_OPTIONS_SS_OTHERS_A_NODE]) { - const auto nodes = utils::range_indices( - io::get_yaml_attribute( - conf, S_OPTIONS_SS_OTHERS_A_NODE, S_OPTIONS_SS_OTHERS)); + if (conf.has_node(S_OPTIONS_SS_OTHERS_A_NODE)) { + const auto nodes = conf.list_to_vector( + S_OPTIONS_SS_OTHERS_A_NODE); for (const auto& node: nodes) { opts->set(node, name); } } + auto& new_opts = opts->get(name); + configure_specmicp_options( + new_opts, the_units, std::move(conf)); } } return opts; } } //end namespace io } //end namespace specmicp diff --git a/src/reactmicp/io/configuration_unsaturated.hpp b/src/reactmicp/io/configuration_unsaturated.hpp index 49aacda..afab0d0 100644 --- a/src/reactmicp/io/configuration_unsaturated.hpp +++ b/src/reactmicp/io/configuration_unsaturated.hpp @@ -1,92 +1,92 @@ /* ============================================================================= Copyright (c) 2014 - 2016 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_REACTMICP_IO_CONFIGURATIONUNSATURATED_HPP #define SPECMICP_REACTMICP_IO_CONFIGURATIONUNSATURATED_HPP //! \file io/configuration_unsaturated.hpp //! \brief YAML configuration for the unsaturated system #include "types.hpp" #include namespace specmicp { namespace units { struct UnitsSet; } //end namespace units namespace database { struct DataContainer; } //end namespace database namespace reactmicp { namespace systems { namespace unsaturated { class EquilibriumOptionsVector; class BoundaryConditions; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp namespace io { class RORichYAMLNode; class YAMLConfigHandle; //! \brief Configure the boundary condition std::shared_ptr SPECMICP_DLL_PUBLIC configure_unsaturated_boundary_conditions( uindex_t nb_nodes, const database::DataContainer * const raw_data, YAMLConfigHandle&& configuration ); std::shared_ptr SPECMICP_DLL_PUBLIC configure_unsaturated_equilibrium_options( uindex_t nb_nodes, const units::UnitsSet& the_units, - const RORichYAMLNode& configuration + YAMLConfigHandle&& configuration ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_REACTMICP_IO_CONFIGURATIONUNSATURATED_HPP diff --git a/tests/reactmicp/systems/unsaturated/configuration.cpp b/tests/reactmicp/systems/unsaturated/configuration.cpp index a66dadb..1fafd6b 100644 --- a/tests/reactmicp/systems/unsaturated/configuration.cpp +++ b/tests/reactmicp/systems/unsaturated/configuration.cpp @@ -1,120 +1,124 @@ #include #include "reactmicp/io/configuration_unsaturated.hpp" #include "reactmicp/systems/unsaturated/boundary_conditions.hpp" #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "reactmicp/systems/unsaturated/equilibrium_stagger.hpp" -#include "utils/io/yaml.hpp" +#include "utils/io/safe_config.hpp" #include "database/database.hpp" const char * conf_bcs = R"plop( boundary_conditions: gas_nodes: 0 fixed_nodes: 9 constraints: default: charge_keeper: "H[+]" others: - nodes: 9 name: fixed_node fork_from: default fixed_fugacity: - label_component: "CO2" label_gas: "CO2(g)" amount: 4e-4 )plop"; const char * conf_options = R"plop( equilibrium_options: default: residual_tolerance: 1e-10 step_tolerance: 1e-10 cutoff_total_concentration: 1e-14 others: - name: totally_reacted fork_from: default residual_tolerance: 1e-8 step_tolerance: 1e-8 - name: difficult node: 9 residual_tolerance: 1e-12 step_tolerance: 1e-12 )plop"; using namespace specmicp; static specmicp::database::RawDatabasePtr get_database() { static database::RawDatabasePtr raw_data {nullptr}; if (raw_data == nullptr) { specmicp::database::Database thedatabase(TEST_CEMDATA_PATH); thedatabase.keep_only_components( {"H2O", "H[+]", "Ca[2+]", "Si(OH)4", "HCO3[-]"} ); std::map swap = {{"HCO3[-]", "CO2"},}; thedatabase.swap_components(swap); raw_data = thedatabase.get_database(); raw_data->freeze_db(); } return raw_data; } TEST_CASE("Boundary conditions configuration", "[io],[configuration],[bcs]") { SECTION("Configuration") { - auto bcs_yaml = io::RORichYAMLNode::parse_yaml_string(conf_bcs); + auto bcs_yaml = io::YAMLConfigFile::load_from_string(conf_bcs); auto raw_data = get_database(); auto bcs = io::configure_unsaturated_boundary_conditions( - 10, raw_data, bcs_yaml["boundary_conditions"]); + 10, raw_data.get(), + bcs_yaml.get_section("boundary_conditions") + ); CHECK(bcs->is_gas_node(0) == true); CHECK(bcs->is_fixed_node(9) == true); const auto& default_const = bcs->get_constraint("default"); CHECK(default_const.charge_keeper == raw_data->get_id_component("H[+]")); REQUIRE(bcs->has_constraint("fixed_node")); const auto& other_const = bcs->get_constraint("fixed_node"); CHECK(other_const.charge_keeper == raw_data->get_id_component("H[+]")); const auto& from_node = bcs->get_constraint(9); CHECK(from_node.fixed_fugacity_cs.size() == 1); CHECK(from_node.fixed_fugacity_cs[0].id_gas == other_const.fixed_fugacity_cs[0].id_gas ); } } TEST_CASE("Equilibrium options", "[io],[configuration],[options]") { SECTION("Configuration") { - auto opts_yaml = io::RORichYAMLNode::parse_yaml_string(conf_options); + auto opts_yaml = io::YAMLConfigFile::load_from_string(conf_options); units::UnitsSet units_set; units_set.length = units::LengthUnit::centimeter; auto opts = io::configure_unsaturated_equilibrium_options( - 10, units_set, opts_yaml["equilibrium_options"]); + 10, units_set, + opts_yaml.get_section("equilibrium_options") + ); const AdimensionalSystemSolverOptions& default_opts = opts->get("default"); CHECK(default_opts.solver_options.fvectol == 1e-10); CHECK(default_opts.solver_options.steptol == 1e-10); CHECK(default_opts.system_options.cutoff_total_concentration == 1e-14); const AdimensionalSystemSolverOptions& reacted_opts = opts->get("totally_reacted"); CHECK(reacted_opts.solver_options.fvectol == 1e-8); CHECK(reacted_opts.solver_options.steptol == 1e-8); CHECK(reacted_opts.system_options.cutoff_total_concentration == 1e-14); const AdimensionalSystemSolverOptions& diff_opts = opts->get("difficult"); CHECK(diff_opts.solver_options.fvectol == 1e-12); CHECK(diff_opts.solver_options.steptol == 1e-12); CHECK(diff_opts.system_options.cutoff_total_concentration == AdimensionalSystemOptions().cutoff_total_concentration); } }