diff --git a/COPYING b/COPYING index ee0d1b5..110e3e8 100644 --- a/COPYING +++ b/COPYING @@ -1,27 +1,33 @@ -Copyright (c) 2014,2015 F. Georget , Princeton University -All rights reserved. +/* ============================================================================= + + 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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + +============================================================================= */ diff --git a/examples/reactmicp/equilibrium_curve.cpp b/examples/reactmicp/equilibrium_curve.cpp index 4d1e243..a503878 100644 --- a/examples/reactmicp/equilibrium_curve.cpp +++ b/examples/reactmicp/equilibrium_curve.cpp @@ -1,369 +1,402 @@ +/* ============================================================================= + + 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 #include "utils/log.hpp" #include "reactmicp/equilibrium_curve/chemistry.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "reactmicp/equilibrium_curve/eqcurve_extractor.hpp" #include "reactmicp/equilibrium_curve/eqcurve_coupler.hpp" #include "dfpm/meshes/axisymmetric_uniform_mesh1d.hpp" #include "dfpm/meshes/uniform_mesh1d.hpp" #include "reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp" #include "database/database.hpp" specmicp::Matrix test_chemistry() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, }); thedatabase.swap_components(swapping); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); specmicp::Formulation formulation; specmicp::scalar_t mult = 6.5e3; specmicp::scalar_t m_c3s = mult*0.7; specmicp::scalar_t m_c2s = mult*0.3; specmicp::scalar_t wc = 0.5; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::index_t id_h2o = thedatabase.component_label_to_id("H2O"); specmicp::index_t id_ho = thedatabase.component_label_to_id("HO[-]"); specmicp::index_t id_ca = thedatabase.component_label_to_id("Ca[2+]"); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-6; options.solver_options.steptol = 1e-14; options.system_options.non_ideality_tolerance = 1e-10; specmicp::reactmicp::eqcurve::EquilibriumCurveSpeciation spec_solver(raw_data, constraints, id_ca, options); return spec_solver.get_equilibrium_curve(0.05, -500); } specmicp::Matrix test_chemistry_with_al() { specmicp::database::Database thedatabase("../data/cemdata_specmicp.js"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"} }); thedatabase.swap_components(swapping); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); specmicp::Formulation formulation; specmicp::scalar_t mult = 6.5e3; specmicp::scalar_t m_c3s = mult*0.6; specmicp::scalar_t m_c2s = mult*0.2; specmicp::scalar_t m_c3a = mult*0.10; specmicp::scalar_t m_gypsum = mult*0.10; specmicp::scalar_t wc = 0.8; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Al(OH)3,am", "Monosulfoaluminate", "Straetlingite", "Gypsum", "Ettringite", }; for (specmicp::index_t component: raw_data->range_component()) { std::cout << raw_data->get_label_component(component) << std::endl; } specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); //specmicp::index_t id_h2o = thedatabase.component_label_to_id("H2O"); specmicp::index_t id_ho = thedatabase.component_label_to_id("HO[-]"); specmicp::index_t id_ca = thedatabase.component_label_to_id("Ca[2+]"); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 20.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-6; options.solver_options.steptol = 1e-14; options.system_options.non_ideality_tolerance = 1e-10; specmicp::reactmicp::eqcurve::EquilibriumCurveSpeciation spec_solver(raw_data, constraints, id_ca, options); return spec_solver.get_equilibrium_curve(0.05, -500.0); } void test_eqcurve_extractor() { specmicp::reactmicp::eqcurve::EquilibriumCurveExtractor extract(test_chemistry_with_al()); specmicp::index_t index = extract.find_point(111.0); std::cout << "111.0 \t " << extract.totsolid_concentration(index) << "\t" << extract.totaq_concentration(index) << "\t" << extract.porosity(index) << "\t" << extract.diffusion_coefficient(index) << std::endl; } void test_diffeqcurve() { specmicp::Matrix eqcurve = test_chemistry_with_al(); eqcurve.col(0) *= 1e-6; //mol/m3 -> mol/cm3 eqcurve.col(1) *= 1e-3; //mol/kg -> mol/cm3 std::cout << eqcurve << std::endl; specmicp::scalar_t radius = 3.5; //cm specmicp::scalar_t height = 8.0; //cm specmicp::scalar_t dx = 0.005; specmicp::index_t additional_nodes = 1; radius = radius + additional_nodes*dx; specmicp::index_t nb_nodes =25+additional_nodes; specmicp::mesh::Mesh1DPtr the_mesh = specmicp::mesh::axisymmetric_uniform_mesh1d(nb_nodes, radius, dx, height); specmicp::dfpmsolver::ParabolicDriverOptions options; options.step_tolerance = 1e-10; options.residuals_tolerance = 1e-8; options.quasi_newton = 1; specmicp::reactmicp::eqcurve::EquilibriumCurveCoupler solver(eqcurve, the_mesh, options); specmicp::scalar_t sum_0 =0; for (specmicp::index_t node=0; node< the_mesh->nb_nodes(); ++node) { sum_0 += solver.solid_concentrations()(node)*the_mesh->get_volume_cell(node); std::cout << the_mesh->get_volume_cell(node) << std::endl; } specmicp::scalar_t dt = 0.4; specmicp::scalar_t total = 0; std::cout << total << "\t" << 0.0 << "\t" << sum_0 << "\t" << 0.0 << std::endl; specmicp::index_t k=0; while (total < 65) { solver.run_step(dt); total += dt/3600/24; if (k % 5000 == 0) { specmicp::scalar_t sum =0; for (specmicp::index_t node=0; node< the_mesh->nb_nodes(); ++node) { sum += solver.solid_concentrations()(node)*the_mesh->get_volume_cell(node); } std::cout << total << "\t" << std::sqrt(total) << "\t" << sum << "\t" << (sum_0 -sum)/(1.75929e-2) << std::endl; } ++k; } //std::cout << solver.solid_concentrations() << std::endl; } void test_eqcurve_solid() { //specmicp::Matrix eq_curve = test_chemistry(); specmicp::Matrix eq_curve = test_chemistry_with_al(); eq_curve.col(0) *= 1e-6; //mol/m3 -> mol/cm3 eq_curve.col(1) *= 1e-3; //mol/kg -> mol/cm3 for (specmicp::index_t ind=1; ind= eq_curve(ind-1, 1)) eq_curve(ind, 1) = eq_curve(ind-1, 1); } std::cout << eq_curve << std::endl; specmicp::scalar_t radius = 3.5; //cm specmicp::scalar_t height = 8.0; //cm specmicp::scalar_t dx = 0.005; specmicp::index_t additional_nodes = 1; radius = radius + additional_nodes*dx; specmicp::index_t nb_nodes = 50+additional_nodes; specmicp::mesh::Mesh1DPtr the_mesh = specmicp::mesh::axisymmetric_uniform_mesh1d(nb_nodes, radius, dx, height); //specmicp::mesh::Mesh1DPtr the_mesh = specmicp::mesh::uniform_mesh1d(nb_nodes, dx, 5); specmicp::dfpmsolver::ParabolicDriverOptions options; options.step_tolerance = 1e-12; options.residuals_tolerance = 1e-6; options.sparse_solver = specmicp::SparseSolver::GMRES; //options.linesearch = specmicp::dfpmsolver::ParabolicLinesearch::Strang; options.alpha = 1.0; options.quasi_newton = 1; options.maximum_step_length = 10; specmicp::reactmicp::eqcurve::SolidDiffusion program(the_mesh, eq_curve, {0,}); specmicp::dfpmsolver::ParabolicDriver< specmicp::reactmicp::eqcurve::SolidDiffusion> solver(program); solver.get_options() = options; solver.set_scaling(specmicp::Vector::Constant(program.get_neq(), 1e6)); specmicp::Vector variables(nb_nodes); variables(0) = eq_curve(eq_curve.rows()-10, 0); for (specmicp::index_t node=1; nodenb_nodes(); ++node) { variables(node) = eq_curve(10, 0); } specmicp::scalar_t sum_0 =0; for (specmicp::index_t node=0; node< the_mesh->nb_nodes(); ++node) { sum_0 += variables(node)*the_mesh->get_volume_cell(node); std::cout << the_mesh->get_volume_cell(node) << std::endl; } specmicp::scalar_t dt = 10.0; specmicp::scalar_t total = 0; std::cout << total << "\t" << 0.0 << "\t" << sum_0 << "\t" << 0.0 << std::endl; specmicp::index_t k=0; while (total < 50) { //std::cout << " ==== TIMESTEP === " << std::endl; solver.solve_timestep(dt, variables); for (int node=0; nodenb_nodes(); ++node) if (variables(node) < 1e-6) variables(node) = 0; //std::cout << solver.get_perfs().nb_iterations << std::endl; total += dt/3600/24; if (k % 5000 == 0) { specmicp::scalar_t sum =0; for (specmicp::index_t node=0; node< the_mesh->nb_nodes(); ++node) { sum += variables(node)*the_mesh->get_volume_cell(node); } std::cout << total << "\t" << std::sqrt(total) << "\t" << sum << "\t" << (sum_0 -sum)/(1.75929e-2) << std::endl; } ++k; } std::cout << variables << std::endl; } void test_interpolator() { specmicp::Matrix mat(5,4); mat << 1, 1, 1, 1, 2, 1, 2, 0, 3, 1, 3, -1, 4, 1, 4, -2, 5, 1, 5, -3; specmicp::reactmicp::eqcurve::EquilibriumCurveExtractor interpolator(mat); std::cout << " " << interpolator.slope(0, 1) << " ?== " << 0 << std::endl; std::cout << " " << interpolator.slope(0, 2) << " ?== " << 1 << std::endl; std::cout << interpolator.slope(0, 3) << " ?== " << -1 << std::endl; std::cout << interpolator.find_point(1.5) << " ? == " << 0 << std::endl; std::cout << interpolator.find_point(3.5) << " ? == " << 2 << std::endl; std::cout << interpolator.interpolate(2, 3.5, 2) << " ? == " << 3.5 << std::endl; std::cout << interpolator.interpolate(2, 3.5, 3) << " ? == " << -1.5 << std::endl; specmicp::Matrix mat2(5,4); mat2 << 5, 1, 1, 1, 4, 1, 2, 0, 3, 1, 3, -1, 2, 1, 4, -2, 1, 1, 5, -3; specmicp::reactmicp::eqcurve::EquilibriumCurveExtractor interpolator2(mat2); std::cout << " " << interpolator2.slope(0, 1) << " ?== " << 0 << std::endl; std::cout << " " << interpolator2.slope(0, 2) << " ?== " << -1 << std::endl; std::cout << interpolator2.slope(0, 3) << " ?== " << +1 << std::endl; std::cout << interpolator2.find_point(1.5) << " ? == " << 3 << std::endl; std::cout << interpolator2.find_point(3.5) << " ? == " << 1 << std::endl; std::cout << interpolator2.interpolate(1, 3.5, 2) << " ? == " << 2.5 << std::endl; std::cout << interpolator2.interpolate(1, 3.5, 3) << " ? == " << -0.5 << std::endl; std::cout << interpolator2.interpolate(4, 1.0, 2) << " ? == " << 5 << std::endl; std::cout << interpolator2.interpolate(4, 1.0, 3) << " ? == " << -3 << std::endl; } int main() { specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; specmicp::logger::ErrFile::stream() = &std::cerr; //test_chemistry(); //std::cout << test_chemistry_with_al() << std::endl; //test_eqcurve_extractor(); test_diffeqcurve(); //test_eqcurve_solid(); //test_interpolator(); return EXIT_SUCCESS; } diff --git a/examples/reactmicp/saturated_react/carbonation.cpp b/examples/reactmicp/saturated_react/carbonation.cpp index ec51856..e7814a2 100644 --- a/examples/reactmicp/saturated_react/carbonation.cpp +++ b/examples/reactmicp/saturated_react/carbonation.cpp @@ -1,512 +1,546 @@ +/* ============================================================================= + + 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. * + +============================================================================= */ + // ====================================================== // Leaching of a cement paste in CO2-saturated water // ======================================================= // This file can be used to learn how to use ReactMiCP // Include ReactMiCP #include "reactmicp.hpp" // Other includes that would be needed later : #include #include "physics/laws.hpp" #include "utils/timer.hpp" #include #include #include // we use the following namespaces using namespace specmicp; using namespace reactmicp; using namespace reactmicp::systems; using namespace specmicp::reactmicp::systems::satdiff; using namespace reactmicp::solver; // We declare some functions that we will be using : // Boundary and initial conditions // =============================== // Return the chemistry constraints for the inital condition AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); // return the chemistry constraints for the boundary condition AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); Vector initial_compo(const Vector& publi); void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species); // The mesh // ======== // There is two version // a uniform mesh (cf config) // and a non uniform mesh mesh::Mesh1DPtr get_mesh(); // =================== // MAIN // =================== int main() { // initialize eigen // This is needed if OpenMP is used Eigen::initParallel(); // Setup the log // The output will be on cerr specmicp::logger::ErrFile::stream() = &std::cerr; // And only Warning and error messages will be printed specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; // Configuration auto config = specmicp::io::parse_yaml_file("carbonation.yaml"); // The database // ------------- // Obtain the database RawDatabasePtr the_database = specmicp::io::configure_database(config); // SpecMiCP options // ---------------- // Set the options AdimensionalSystemSolverOptions specmicp_options; specmicp::io::configure_specmicp_options(specmicp_options, config); units::UnitsSet units_set = specmicp_options.units_set; // The mesh // -------- // Obtain the mesh mesh::Mesh1DPtr the_mesh = specmicp::io::configure_mesh(config); index_t nb_nodes = the_mesh->nb_nodes(); // just boilerplate to make things easier // Print the mesh io::print_mesh("out_carbo_mesh.dat", the_mesh, units::LengthUnit::centimeter); // Initial and boundary conditions // -------------------------------- // Obtain the initial constraints // Note : the database is modified at this point // Only the relevant components are kept at this point AdimensionalSystemConstraints cement_constraints = get_cement_initial_constraints(the_database, units_set); // Freeze the database the_database->freeze_db(); // Obtain the initial condition AdimensionalSystemSolution cement_solution = solve_equilibrium( the_database, cement_constraints, specmicp_options); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the initial condition computation"); database::Database db_manager(the_database); db_manager.save("out_carbo_db.js"); // Just to check that everything is ok ! AdimensionalSystemSolutionExtractor extractor(cement_solution, the_database, units_set); std::cout << "Porosity : " << extractor.porosity() << std::endl; std::cout << "Water volume fraction " << extractor.volume_fraction_water() << std::endl; //return EXIT_SUCCESS; // Obtain the boundary conditions AdimensionalSystemConstraints bc_constraints = get_bc_initial_constraints( the_database, specmicp_options.units_set ); AdimensionalSystemSolution bc_solution = solve_equilibrium( the_database, bc_constraints, specmicp_options ); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the boundary conditions computation"); // The constraints // -------------- // Boundary condition // 'list_fixed_nodes' lists the node with fixed composition std::vector list_fixed_nodes = {0}; // list_constraints lists the different speciation constraints in the system // Note : the total concentrations are computed from the initial solution, // and thus different total concentrations do not constitute a reason to create different constraints std::vector list_constraints = {cement_constraints, bc_constraints}; // index_constraints links a node to the set of constraints that will be used std::vector index_constraints(nb_nodes, 0); index_constraints[0] = 1; // Boundary conditions // This is the list of initial composition std::vector list_initial_composition = {cement_solution, bc_solution}; // This list links a node to its initial conditions std::vector index_initial_state(nb_nodes, 0); index_initial_state[0] = 1; // boundary condition // Variables // ----------- // Create the main set of variables // They will be initialized using the list of initial composition satdiff::SaturatedVariablesPtr variables = satdiff::init_variables(the_mesh, the_database, units_set, list_fixed_nodes, list_initial_composition, index_initial_state); // Staggers // --------- // This section initialize the staggers // The equilibrium stagger // - - - - - - - - - - - - std::shared_ptr equilibrium_stagger = std::make_shared(list_constraints, index_constraints, specmicp_options); // The transport stagger // - - - - - - - - - - - std::vector list_fixed_component {0, 1, the_database->get_id_component("Si(OH)4")}; std::map slave_nodes {}; std::shared_ptr transport_stagger = std::make_shared( variables, list_fixed_nodes, slave_nodes, list_fixed_component ); specmicp::io::configure_transport_options(transport_stagger->options_solver(), config); // The upscaling stagger // - - - - - - - - - - - CappedPowerLawParameters upscaling_param; upscaling_param.d_eff_0 = 2.726e-12*1e4; upscaling_param.cap = 1e10*1e6; upscaling_param.exponent = 3.32; upscaling_param.porosity_0 = 0.25; upscaling_param.porosity_res = 0.02; CappedPowerLaw upscaling_law(upscaling_param); UpscalingStaggerPtr upscaling_stagger = std::make_shared(upscaling_law.get_law(),the_database, units_set); // Solver // ------ // This section initialize the reactive transport solver ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); specmicp::io::configure_reactmicp_options(solver.get_options(), config); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); // Some basic information about the simulation SimulationInformation simul_info = specmicp::io::configure_simulation_information(config); // Runner // ------- // Create the runner : loop through the timestep specmicp::io::check_mandatory_yaml_node(config, "run", "__main__"); scalar_t min_dt = specmicp::io::get_yaml_mandatory(config["run"], "minimum_dt", "run"); scalar_t max_dt = specmicp::io::get_yaml_mandatory(config["run"], "maximum_dt", "run"); scalar_t total = specmicp::io::get_yaml_mandatory(config["run"], "total_execution_time", "run"); ReactiveTransportRunner runner(solver, min_dt, max_dt, simul_info); // Output // ------ io::OutputNodalVariables output_policy(the_database, the_mesh, specmicp_options.units_set); io::configure_reactmicp_output(output_policy, simul_info, config); // and bind it to the runner runner.set_output_policy(output_policy.get_output_for_reactmicp()); // Solve the problem // ----------------- runner.run_until(total, cast_var_to_base(variables)); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the computation"); AdimensionalSystemSolutionSaver saver(the_database); saver.save_solutions(simul_info.complete_filepath("solutions", "dat"), variables->equilibrium_solutions()); // output information at the end of the timestep io::print_minerals_profile(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("profiles_end", "dat")); io::print_components_total_aqueous_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("c_profiles_end", "dat")); io::print_components_total_solid_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("s_profiles_end", "dat")); return EXIT_SUCCESS; } AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { Vector oxyde_compo(4); oxyde_compo << 66.98, 21.66, 7.19, 2.96; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); scalar_t mult = 1e-6; //species_compo *= 0.947e-2; // poro 0.47 //species_compo *= 1.08e-2; // poro 0.4 //species_compo *= 1.25e-2; // poro 0.3 species_compo *= 1.1e-2; Formulation formulation; formulation.mass_solution = 1.0; formulation.amount_minerals = { {"C3S", species_compo(0)}, {"C2S", species_compo(1)}, {"C3A", species_compo(2)}, {"Gypsum", species_compo(3)}, {"Calcite", species_compo(0)*1e-3} }; formulation.extra_components_to_keep = {"HCO3[-]"}; formulation.concentration_aqueous = { {"NaOH", mult*1.0298}, {"KOH", mult*0.0801}, {"Cl[-]", mult*0.0001} }; Dissolver dissolver(the_database); dissolver.set_units(units_set); AdimensionalSystemConstraints constraints; constraints.set_charge_keeper(the_database->get_id_component("HO[-]")); constraints.total_concentrations = dissolver.dissolve(formulation); std::cout << constraints.total_concentrations << std::endl; constraints.set_saturated_system(); return constraints; } AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { const scalar_t rho_w = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); const scalar_t nacl = 0.3*rho_w; const scalar_t kcl = 0.28*rho_w; Vector total_concentrations; total_concentrations.setZero(the_database->nb_component()); total_concentrations(the_database->get_id_component("K[+]")) = kcl; total_concentrations(the_database->get_id_component("Cl[-]")) = nacl + kcl; total_concentrations(the_database->get_id_component("Na[+]")) = nacl; //total_concentrations(the_database->get_id_component("Si(OH)4")) = 0.0001*rho_w; AdimensionalSystemConstraints constraints; constraints.add_fixed_activity_component(the_database->get_id_component("HO[-]"), -10.3); constraints.set_charge_keeper(the_database->get_id_component("HCO3[-]")); constraints.total_concentrations = total_concentrations; constraints.set_saturated_system(); constraints.disable_surface_model(); constraints.fixed_fugacity_cs ={}; return constraints; } AdimensionalSystemSolution get_bc_initial_compo( RawDatabasePtr the_database, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { Vector variables; AdimensionalSystemSolver solver(the_database, constraints, options); micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve initial composition"); std::cout << variables << std::endl; return solver.get_raw_solution(variables); } void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species) { constexpr double M_CaO = 56.08; constexpr double M_SiO2 = 60.09; constexpr double M_Al2O3 = 101.96; constexpr double M_SO3 = 80.06; Eigen::MatrixXd compo_in_oxyde(4, 4); Vector molar_mass(4); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); //C3S C2S C3A Gypsum compo_in_oxyde << 3, 2, 3, 1, // CaO 1, 1, 0, 0, // SiO2 0, 0, 1, 0, // Al2O3 0, 0, 0, 1; // SO3 Eigen::ColPivHouseholderQR solver(compo_in_oxyde); compo_species = solver.solve(compo_oxyde); } Vector initial_compo(const Vector& publi) { Matrix publi_stochio(5,5); publi_stochio << 1, 0, 0, 0, 0, 9, 6, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Matrix cemdata_stochio(5, 5); cemdata_stochio << 1, 0, 0, 0, 0, 1.0/0.6, 1.0, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Vector oxyde; Eigen::ColPivHouseholderQR solver(publi_stochio); oxyde = solver.solve(publi); Vector for_cemdata = cemdata_stochio*oxyde; return for_cemdata; } mesh::Mesh1DPtr get_mesh() { Vector radius(71); const scalar_t height = 20; radius << 3.751, 3.750, 3.745, 3.740, 3.735, 3.730, 3.720, 3.710, 3.700, 3.690, 3.680, 3.670, 3.660, 3.645, 3.630, 3.615, 3.600, 3.580, 3.560, 3.540, 3.520, 3.500, 3.475, 3.450, 3.425, 3.400, 3.375, 3.350, 3.325, 3.300, 3.275, 3.250, 3.225, 3.200, 3.175, 3.150, 3.125, 3.100, 3.050, 3.025, 3.000, 2.950, 2.900, 2.850, 2.800, 2.750, 2.700, 2.650, 2.600, 2.550, 2.500, 2.450, 2.400, 2.350, 2.300, 2.250, 2.200, 2.150, 2.100, 2.050, 2.000, 1.950, 1.900, 1.850, 1.800, 1.750, 1.700, 1.650, 1.600, 1.550, 1.500 ; radius = radius/10; return mesh::axisymmetric_mesh1d(radius, height); } diff --git a/examples/reactmicp/saturated_react/carbonationfe.cpp b/examples/reactmicp/saturated_react/carbonationfe.cpp index a11e051..6d52628 100644 --- a/examples/reactmicp/saturated_react/carbonationfe.cpp +++ b/examples/reactmicp/saturated_react/carbonationfe.cpp @@ -1,768 +1,801 @@ +/* ============================================================================= + + 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. * + +============================================================================= */ // ============================================ // Saturated carbonation of a cement past // ============================================= // This file can be used to learn how to use ReactMiCP // Include ReactMiCP #include "reactmicp.hpp" // Physical laws #include "physics/laws.hpp" // A simple timer #include "utils/timer.hpp" #include #include #include // we use the following namespaces using namespace specmicp; using namespace reactmicp; using namespace reactmicp::systems; using namespace specmicp::reactmicp::systems::satdiff; using namespace reactmicp::solver; // We declare some functions that we will be using : // Database // ======== // Parse and Prepare the database RawDatabasePtr get_database(const std::string& path_to_database); // Boundary and initial conditions // =============================== // Return the chemistry constraints for the inital condition AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); // return the chemistry constraints for the boundary condition AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); void compo_oxyde_to_mole(Vector& compo_oxyde); // The mesh // ======== // There is two version // a uniform mesh mesh::Mesh1DPtr get_mesh(scalar_t dx); // and a non uniform mesh mesh::Mesh1DPtr get_mesh(); // Options // ======= // Speciation solver options AdimensionalSystemSolverOptions get_specmicp_options(); // Transport options void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options); // Reactive Solver options void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options); // Upscaling // ========= // Upscaling is the stagger in charge of finding the porosity and transport properties // This is a class that is dependant on the problem to solve and should be defined by the user // The following class is an example on how to define such a class // The Upscaling class should inherit from UpscalingStaggerBase class CarboUspcaling: public solver::UpscalingStaggerBase { public: // Initiation // This is not call automatically so can be adjusted by the user CarboUspcaling(RawDatabasePtr the_database, units::UnitsSet the_units): m_data(the_database), m_units_set(the_units), m_dt(HUGE_VAL) { } void initialize(std::shared_ptr& var) { return initialize(var.get()); } // Initialize the stagger at the beginning of the computation // The porosity and transport properties should be initialized here virtual void initialize(VariablesBase * var) override { SaturatedVariables * true_var = static_cast(var); true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } // Initialize the stagger at the beginning of a timestep // Typically do nothing but erase the "dot" variable (velocity such as the vel_porosity) virtual void initialize_timestep(scalar_t dt, VariablesBase * var) override { SaturatedVariables* true_var = static_cast(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! This is the main function called during a timestep virtual StaggerReturnCode restart_timestep(VariablesBase * var) override { SaturatedVariables * true_var = static_cast(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } return StaggerReturnCode::ResidualMinimized; // This is the value that should be returned if everything is ok } // A function that return the diffusion coefficient when porosity is equal to 'porosity' scalar_t coeff_diffusion_law(scalar_t porosity) { static constexpr scalar_t de_0 = 2.726e-12; //1e-11; static constexpr scalar_t factor = 1e4; static constexpr scalar_t porosity_r = 0.02; const scalar_t ratio = ((porosity - porosity_r)/(0.25 - porosity_r)); const scalar_t d_e = factor*de_0*std::pow(ratio, 3.32); return std::min(d_e, 1e4*1e-10); } // Compute the upscaling for 'node' void upscaling_one_node(index_t node, SaturatedVariables* true_var) { // AdimensionalSystemSolutionExtractor is the class to use to // extract information from a SpecMiCP solution // To obtain correct information the correct units must be used AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), m_data, m_units_set); // We can obtain the porosity very easily : scalar_t porosity = extractor.porosity(); true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = coeff_diffusion_law(porosity); } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; }; // ============== // Output // ============== // Many information is generated throughout a computation and we can't save everything // The reactmicp runner can call a function to output the desired information // Here the output function is a member function for convenience class OutputPolicy { public: // Initialise the output // SimulationInformation contain basic information from the simulation OutputPolicy(const SimulationInformation& simul_info, mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units): m_mesh(the_mesh), m_database(the_database), m_units(the_units) { // Open the files // Save the pH out_c_ph.open(simul_info.complete_filepath("ph", suffix)); // Save the total aqueous concentration of HCO3[-] out_c_hco3.open(simul_info.complete_filepath("c_hco3", suffix)); // save the total solid concentration of s_ca out_s_ca.open(simul_info.complete_filepath("s_ca", suffix)); // Save the volume fraction of calcite out_calcite.open(simul_info.complete_filepath("calcite", suffix)); // Save the porosity out_poro.open(simul_info.complete_filepath("poro", suffix)); // save useful indices from the database m_id_hco3 = m_database->get_id_component("HCO3[-]"); m_id_ca = m_database->get_id_component("Ca[2+]"); m_id_calcite = m_database->get_id_mineral("Calcite"); } void output(scalar_t time, VariablesBasePtr variables) { SaturatedVariablesPtr true_var = cast_var_from_base(variables); out_c_ph << time; out_c_hco3 << time; out_s_ca << time; out_calcite << time; out_poro << time; for (index_t node: m_mesh->range_nodes()) { // Again AdimensionalSystemSolutionExtractor is used to obtain information about the speciation system AdimensionalSystemSolutionExtractor extractor(true_var ->equilibrium_solution(node), m_database, m_units); out_c_ph << "\t" << extractor.pH(); out_c_hco3 << "\t" << true_var->aqueous_concentration(node, m_id_hco3); out_s_ca << "\t" << true_var->solid_concentration(node, m_id_ca); out_calcite << "\t" << extractor.volume_fraction_mineral(m_id_calcite); out_poro << "\t" << extractor.porosity(); } out_c_hco3 << std::endl; out_c_ph << std::endl; out_s_ca << std::endl; out_calcite << std::endl; out_poro << std::endl; } private: mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; units::UnitsSet m_units; std::string suffix { "dat" }; std::ofstream out_c_ph; std::ofstream out_c_hco3; std::ofstream out_s_ca; std::ofstream out_calcite; std::ofstream out_poro; index_t m_id_hco3; index_t m_id_ca; index_t m_id_calcite; }; // =================== // MAIN // =================== int main() { // initialize eigen // This is needed if OpenMP is used Eigen::initParallel(); // Setup the log // The output will be on cerr specmicp::logger::ErrFile::stream() = &std::cerr; // And only Warning and error messages will be printed specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; // The database // ------------- // Obtain the database RawDatabasePtr the_database = get_database("../data/cemdata.yaml"); // SpecMiCP options // ---------------- // Set the options AdimensionalSystemSolverOptions specmicp_options = get_specmicp_options(); units::UnitsSet units_set = specmicp_options.units_set; // The mesh // -------- // Obtain the mesh mesh::Mesh1DPtr the_mesh = get_mesh(0.0050); // uniform //mesh::Mesh1DPtr the_mesh = get_mesh(); // non uniform index_t nb_nodes = the_mesh->nb_nodes(); // just boilerplate to make things easier // Print the mesh io::print_mesh("out_carbo_mesh.dat", the_mesh, units::LengthUnit::centimeter); // Initial and boundary conditions // -------------------------------- // Obtain the initial constraints // Note : the database is modified at this point // Only the relevant components are kept at this point AdimensionalSystemConstraints cement_constraints = get_cement_initial_constraints(the_database, units_set); // Obtain the initial condition AdimensionalSystemSolution cement_solution = solve_equilibrium( the_database, cement_constraints, specmicp_options); // Just to check that everything is ok ! AdimensionalSystemSolutionExtractor extractor(cement_solution, the_database, units_set); std::cout << "Porosity : " << extractor.porosity() << std::endl; std::cout << "Water volume fraction " << extractor.volume_fraction_water() << std::endl; //return EXIT_SUCCESS; // Obtain the boundary conditions AdimensionalSystemConstraints bc_constraints = get_bc_initial_constraints( the_database, specmicp_options.units_set ); AdimensionalSystemSolution bc_solution = solve_equilibrium( the_database, bc_constraints, specmicp_options ); // The constraints // -------------- // Boundary condition // 'list_fixed_nodes' lists the node with fixed composition std::vector list_fixed_nodes = {0}; // list_constraints lists the different speciation constraints in the system // Note : the total concentrations are computed from the initial solution, // and thus different total concentrations do not constitute a reason to create different constraints std::vector list_constraints = {cement_constraints, bc_constraints}; // index_constraints links a node to the set of constraints that will be used std::vector index_constraints(nb_nodes, 0); index_constraints[0] = 1; // Boundary conditions // This is the list of initial composition std::vector list_initial_composition = {cement_solution, bc_solution}; // This list links a node to its initial conditions std::vector index_initial_state(nb_nodes, 0); index_initial_state[0] = 1; // boundary condition // Variables // ----------- // Create the main set of variables // They will be initialized using the list of initial composition satdiff::SaturatedVariablesPtr variables = satdiff::init_variables(the_mesh, the_database, units_set, list_fixed_nodes, list_initial_composition, index_initial_state); // Staggers // --------- // This section initialize the staggers std::shared_ptr equilibrium_stagger = std::make_shared(list_constraints, index_constraints, specmicp_options); std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); set_transport_options(transport_stagger->options_solver()); UpscalingStaggerPtr upscaling_stagger = std::make_shared(the_database, units_set); // Solver // ------ // This section initialize the reactive transport solver ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); set_reactive_solver_options(solver.get_options()); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); // Some basic information about the simulation // First argument : the name of the simulation // Second argument : the output function will be called every 3600s SimulationInformation simul_info("carbo", 3600); simul_info.output_prefix = "out_carbo_"; // Runner // ------- // Create the runner : loop through the timestep ReactiveTransportRunner runner(solver, 0.1, 100.0, simul_info); // Create the output class OutputPolicy output_policy(simul_info, the_mesh, the_database, specmicp_options.units_set); // and bind it to the runner runner.set_output_policy(std::bind(&OutputPolicy::output, &output_policy, std::placeholders::_1, std::placeholders::_2)); // Solve the problem runner.run_until(30*24*3600, cast_var_to_base(variables)); // output information at the end of the timestep io::print_minerals_profile(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("profiles_end", "dat")); io::print_components_total_aqueous_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("c_profiles_end", "dat")); io::print_components_total_solid_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("s_profiles_end", "dat")); } AdimensionalSystemSolverOptions get_specmicp_options() { AdimensionalSystemSolverOptions options; options.solver_options.maxiter_maxstep = 100; options.solver_options.maxstep = 50.0; options.solver_options.threshold_cycling_linesearch = 1e-6; options.solver_options.set_tolerance(1e-8, 1e-16); options.solver_options.disable_condition_check(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.solver_options.enable_scaling(); options.system_options.non_ideality_tolerance = 1e-14; options.system_options.cutoff_total_concentration = 1e-10; options.system_options.scaling_electron = 1e4; options.units_set.length = units::LengthUnit::centimeter; return options; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-8; transport_options.step_tolerance = 1e-14; transport_options.absolute_tolerance = 1e-18; transport_options.alpha = 1.0; //transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-4; } void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options) { reactive_options.maximum_iterations = 50; //500; reactive_options.residuals_tolerance = 1e-2; reactive_options.good_enough_tolerance = 1.0; reactive_options.absolute_residuals_tolerance = 1e-14; reactive_options.implicit_upscaling = true; } RawDatabasePtr get_database(const std::string& path_to_database) { database::Database the_database(path_to_database); std::map swapping({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, {"Fe[2+]", "Fe(OH)4[-]"} }); the_database.swap_components(swapping); the_database.remove_gas_phases(); return the_database.get_database(); } AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { Vector oxyde_compo(5); oxyde_compo << 66.98, 21.66, 2.78, 2.96, 4.41; compo_oxyde_to_mole(oxyde_compo); scalar_t mult = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); //oxyde_compo *= 0.01098; //= 1e-2; //poro 0.4 oxyde_compo *= 0.00967; //= 1e-2; //poro 0.47 Formulation formulation; formulation.mass_solution = 1.0; formulation.amount_minerals = { {"CaO(ox)", oxyde_compo(0)}, {"SiO2(ox)", oxyde_compo(1)}, {"Al2O3(ox)", oxyde_compo(2)}, {"SO3(ox)", oxyde_compo(3)}, {"Fe2O3(ox)", oxyde_compo(4)}, {"Calcite", oxyde_compo(0)*1e-4} }; formulation.extra_components_to_keep = {"HCO3[-]"}; formulation.concentration_aqueous = { {"Na[+]", mult*1.0298}, {"K[+]", mult*0.0801}, {"Cl[-]", mult*0.0001}, {"HO[-]", mult*1.8298} }, formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "C3AH6", "C4AH13", "C2AH8", "CAH10", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", //"Straetlingite", "Gypsum", "Ettringite", //"Thaumasite", "C3FH6", "C4FH13", "C2FH8", "Fe(OH)3(mic)", "Fe-Ettringite", "Fe-Monosulfate", "Fe-Monocarbonate", "Fe-Hemicarbonate", //"Fe-Straetlingite", }; Dissolver dissolver(the_database); dissolver.set_units(units_set); AdimensionalSystemConstraints constraints; constraints.set_charge_keeper(1); constraints.total_concentrations = dissolver.dissolve(formulation); std::cout << constraints.total_concentrations << std::endl; constraints.set_saturated_system(); return constraints; } AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { const scalar_t rho_w = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); const scalar_t nacl = 0.3*rho_w; const scalar_t kcl = 0.28*rho_w; Vector total_concentrations; total_concentrations.setZero(the_database->nb_component()); total_concentrations(the_database->get_id_component("K[+]")) = kcl; total_concentrations(the_database->get_id_component("Cl[-]")) = nacl + kcl; total_concentrations(the_database->get_id_component("Na[+]")) = nacl; total_concentrations(the_database->get_id_component("SiO(OH)3[-]")) = 0.0001*rho_w; AdimensionalSystemConstraints constraints; constraints.add_fixed_activity_component(the_database->get_id_component("HO[-]"), -10.3); constraints.set_charge_keeper(the_database->get_id_component("HCO3[-]")); constraints.total_concentrations = total_concentrations; constraints.set_saturated_system(); constraints.disable_surface_model(); constraints.fixed_fugacity_cs ={}; return constraints; } AdimensionalSystemSolution get_bc_initial_compo( RawDatabasePtr the_database, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { Vector variables; AdimensionalSystemSolver solver(the_database, constraints, options); micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve initial composition"); //std::cout << variables << std::endl; return solver.get_raw_solution(variables); } void compo_oxyde_to_mole(Vector& compo_oxyde) { constexpr double M_CaO = 56.08; constexpr double M_SiO2 = 60.09; constexpr double M_Al2O3 = 101.96; constexpr double M_SO3 = 80.06; constexpr double M_FE2O3 = 159.7; Vector molar_mass(5); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3, 1.0/M_FE2O3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); } mesh::Mesh1DPtr get_mesh(scalar_t dx) { mesh::UniformAxisymmetricMesh1DGeometry geometry; geometry.dx = dx; geometry.radius = 0.75/2.0 + dx; //cm geometry.height = 20.0; geometry.nb_nodes = geometry.radius/dx + 1; return mesh::uniform_axisymmetric_mesh1d(geometry); } mesh::Mesh1DPtr get_mesh() { Vector radius(71); const scalar_t height = 20; // radius << // 3.751, // 3.750, // 3.749, // 3.748, // 3.747, // 3.745, // 3.740, // 3.735, // 3.730, // 3.720, // 3.710, // 3.700, // 3.675, // 3.650, // 3.625, // 3.600, // 3.575, // 3.550, // 3.525, // 3.500, // 3.475, // 3.450, // 3.425, // 3.400, // 3.375, // 3.350, // 3.325, // 3.300, // 3.250, // 3.200, // 3.150, // 3.100, // 3.050, // 3.000, // 2.975, // 2.950, // 2.925, // 2.900, // 2.875, // 2.850, // 2.825, // 2.800, // 2.775, // 2.750, // 2.700, // 2.650; radius << 3.751, 3.750, 3.745, 3.740, 3.735, 3.730, 3.720, 3.710, 3.700, 3.690, 3.680, 3.670, 3.660, 3.645, 3.630, 3.615, 3.600, 3.580, 3.560, 3.540, 3.520, 3.500, 3.475, 3.450, 3.425, 3.400, 3.375, 3.350, 3.325, 3.300, 3.275, 3.250, 3.225, 3.200, 3.175, 3.150, 3.125, 3.100, 3.050, 3.025, 3.000, 2.950, 2.900, 2.850, 2.800, 2.750, 2.700, 2.650, 2.600, 2.550, 2.500, 2.450, 2.400, 2.350, 2.300, 2.250, 2.200, 2.150, 2.100, 2.050, 2.000, 1.950, 1.900, 1.850, 1.800, 1.750, 1.700, 1.650, 1.600, 1.550, 1.500 ; radius = radius/10; return mesh::axisymmetric_mesh1d(radius, height); } diff --git a/examples/reactmicp/saturated_react/leaching_kinetic.cpp b/examples/reactmicp/saturated_react/leaching_kinetic.cpp index e082a3a..f5bf458 100644 --- a/examples/reactmicp/saturated_react/leaching_kinetic.cpp +++ b/examples/reactmicp/saturated_react/leaching_kinetic.cpp @@ -1,878 +1,911 @@ +/* ============================================================================= + + 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. * + +============================================================================= */ // ============================================ // Leaching of a cement paste // with kinetic dissolution of C3S // ============================================= // This file can be used to learn how to use ReactMiCP // Include ReactMiCP #include "reactmicp.hpp" #include "specmicp/adimensional/adimensional_system_solution_saver.hpp" #include "reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp" #include "reactmicp/systems/saturated_react/kinetic_stagger.hpp" // Other includes that would be needed later : #include #include "physics/laws.hpp" #include "utils/timer.hpp" #include #include #include // we use the following namespaces using namespace specmicp; using namespace reactmicp; using namespace reactmicp::systems; using namespace specmicp::reactmicp::systems::satdiff; using namespace reactmicp::solver; // We declare some functions that we will be using : // Database // ======== // Parse and Prepare the database RawDatabasePtr get_database(const std::string& path_to_database); // Boundary and initial conditions // =============================== // Return the chemistry constraints for the inital condition AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); // return the chemistry constraints for the boundary condition AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); Vector initial_compo(const Vector& publi); void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species); // The mesh // ======== // There is two version // a uniform mesh mesh::Mesh1DPtr get_mesh(scalar_t dx); // and a non uniform mesh mesh::Mesh1DPtr get_mesh(); // Options // ======= // Speciation solver options AdimensionalSystemSolverOptions get_specmicp_options(); // Transport options void set_transport_options( dfpmsolver::ParabolicDriverOptions& transport_options ); // Reactive Solver options void set_reactive_solver_options( reactmicp::solver::ReactiveTransportOptions& reactive_options ); // Kinetic model and variables // =========================== // Kinetic variables class C3SKineticVariables : public KineticSaturatedVariablesBase { public: Vector amount_minerals; // concentration of C3S Vector predictor; // Initial amount Vector velocity; // dC_c3s/dt Vector volume_fractions; }; using C3SKineticVariablesPtr = std::shared_ptr; // The dissolution model class C3SDissolutionModel : public KineticModelBase { public: C3SDissolutionModel(RawDatabasePtr the_database, const units::UnitsSet the_units): m_database(the_database), m_units(the_units), id_c3s(the_database->get_id_mineral_kinetic("C3S")) { if (id_c3s == no_species) throw database::invalid_database("The database do not contain C3S !"); } KineticSaturatedVariablesBasePtr initialize_variables( mesh::Mesh1DPtr the_mesh, scalar_t init_vol_fraction ); //! \brief Initialize a timestep virtual void initialize_timestep( scalar_t dt, KineticSaturatedVariablesBasePtr kinetic_variables ) override; //! \brief Restart a timestep virtual void restart_timestep( index_t node, const AdimensionalSystemSolution& eq_solution, KineticSaturatedVariablesBasePtr kinetic_variables ) override; //! \brief Return the volume fraction of kinetic (or inert) phases virtual scalar_t get_volume_fraction_kinetic( index_t node, KineticSaturatedVariablesBasePtr kinetic_variables ) override; //! \brief Return the velocity of the total immobile kinetic concentration for component virtual scalar_t get_velocity_kinetic( index_t node, index_t component, KineticSaturatedVariablesBasePtr kinetic_variables ) override; private: scalar_t volume_fraction(scalar_t concentration); scalar_t dy_dt(scalar_t log_IAP, scalar_t Aeff); scalar_t m_dt {-1.0}; RawDatabasePtr m_database; units::UnitsSet m_units; index_t id_c3s; }; KineticSaturatedVariablesBasePtr C3SDissolutionModel::initialize_variables( mesh::Mesh1DPtr the_mesh, scalar_t init_vol_fraction ) { C3SKineticVariablesPtr var = std::make_shared(); var->predictor.setZero(the_mesh->nb_nodes()); var->velocity.setZero(the_mesh->nb_nodes()); var->volume_fractions.setConstant(the_mesh->nb_nodes(), init_vol_fraction); var->amount_minerals.setConstant(the_mesh->nb_nodes(), init_vol_fraction/m_database->molar_volume_mineral_kinetic(id_c3s, m_units.length)); var->volume_fractions(0) = 0.0; var->amount_minerals(0) = 0.0; return std::static_pointer_cast(var); } void C3SDissolutionModel::initialize_timestep( scalar_t dt, KineticSaturatedVariablesBasePtr kinetic_variables ) { m_dt = dt; C3SKineticVariablesPtr true_kin_var = std::static_pointer_cast(kinetic_variables); true_kin_var->predictor = true_kin_var->amount_minerals; true_kin_var->velocity.setZero(); } void C3SDissolutionModel::restart_timestep( index_t node, const AdimensionalSystemSolution &eq_solution, KineticSaturatedVariablesBasePtr kinetic_variables ) { C3SKineticVariablesPtr true_kin_var = std::static_pointer_cast(kinetic_variables); AdimensionalSystemSolutionExtractor extr(eq_solution, m_database, m_units); scalar_t log_IAP = 0; for (index_t component: m_database->range_component()) { if (m_database->nu_mineral_kinetic(id_c3s, component) == 0.0) continue; log_IAP += m_database->nu_mineral_kinetic(id_c3s, component)*extr.log_molality_component(component); } scalar_t tmp = 0; scalar_t Aeff = 0; scalar_t porosity = extr.porosity(); if (porosity > 0.6) { Aeff= 1400*1e-4/1e-3*m_database->molar_mass_mineral_kinetic(id_c3s)/m_database->molar_volume_mineral_kinetic(id_c3s)*true_kin_var->volume_fractions(node); tmp = 1e-6*dy_dt(log_IAP, Aeff); } true_kin_var->velocity(node) = tmp; tmp = true_kin_var->predictor(node) + m_dt*true_kin_var->velocity(node); if (tmp < 1e-20) { tmp =0.0; true_kin_var->velocity(node) = - true_kin_var->predictor(node) / m_dt; } true_kin_var->amount_minerals(node) = tmp; true_kin_var->volume_fractions(node) = tmp*m_database->molar_volume_mineral_kinetic(id_c3s, m_units.length); } scalar_t C3SDissolutionModel::dy_dt(scalar_t log_IAP, scalar_t Aeff) { scalar_t res = (-57.0 -std::log(10)*log_IAP)/21.5; scalar_t tmp_2 = std::pow(res, 3.73); res = - 125.3e-6*Aeff*(1.0 - std::exp(-tmp_2)); return res; } scalar_t C3SDissolutionModel::get_volume_fraction_kinetic( index_t node, KineticSaturatedVariablesBasePtr kinetic_variables ) { C3SKineticVariablesPtr true_kin_var = std::static_pointer_cast(kinetic_variables); return true_kin_var->volume_fractions(node); } scalar_t C3SDissolutionModel::get_velocity_kinetic( index_t node, index_t component, KineticSaturatedVariablesBasePtr kinetic_variables ) { C3SKineticVariablesPtr true_kin_var = std::static_pointer_cast(kinetic_variables); return m_database->nu_mineral_kinetic(id_c3s, component)*true_kin_var->velocity(node); } // ============== // Output // ============== // Many information is generated throughout a computation and we can't save everything // The reactmicp runner can call a function to output the desired information // Here the output function is a member function for convenience class OutputPolicy { public: // Initialise the output // SimulationInformation contain basic information from the simulation OutputPolicy(const SimulationInformation& simul_info, mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units): m_mesh(the_mesh), m_database(the_database), m_units(the_units) { // Open the files // Save the pH out_c_ph.open(simul_info.complete_filepath("ph", suffix)); // Save the total aqueous concentration of HCO3[-] out_c_hco3.open(simul_info.complete_filepath("c_hco3", suffix)); // save the total solid concentration of s_ca out_s_ca.open(simul_info.complete_filepath("s_ca", suffix)); // Save the volume fraction of calcite out_calcite.open(simul_info.complete_filepath("calcite", suffix)); // Save the porosity out_poro.open(simul_info.complete_filepath("poro", suffix)); out_kin_vol_frac.open(simul_info.complete_filepath("kin_vol_frac", suffix)); // save useful indices from the database m_id_hco3 = m_database->get_id_component("HCO3[-]"); m_id_ca = m_database->get_id_component("Ca[2+]"); m_id_calcite = m_database->get_id_mineral("Calcite"); } void output(scalar_t time, VariablesBasePtr variables) { SaturatedVariablesPtr true_var = cast_var_from_base(variables); out_c_ph << time; out_c_hco3 << time; out_s_ca << time; out_calcite << time; out_poro << time; out_kin_vol_frac << time; for (index_t node: m_mesh->range_nodes()) { // Again AdimensionalSystemSolutionExtractor is used to obtain information about the speciation system AdimensionalSystemSolutionExtractor extractor(true_var ->equilibrium_solution(node), m_database, m_units); out_c_ph << "\t" << extractor.pH(); out_c_hco3 << "\t" << true_var->aqueous_concentration(node, m_id_hco3); out_s_ca << "\t" << true_var->solid_concentration(node, m_id_ca); out_calcite << "\t" << extractor.volume_fraction_mineral(m_id_calcite); out_poro << "\t" << extractor.porosity(); out_kin_vol_frac << "\t" << std::static_pointer_cast(true_var->kinetic_variables())->volume_fractions(node); } out_c_hco3 << std::endl; out_c_ph << std::endl; out_s_ca << std::endl; out_calcite << std::endl; out_poro << std::endl; out_kin_vol_frac << std::endl; } private: mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; units::UnitsSet m_units; std::string suffix { "dat" }; std::ofstream out_c_ph; std::ofstream out_c_hco3; std::ofstream out_s_ca; std::ofstream out_calcite; std::ofstream out_poro; std::ofstream out_kin_vol_frac; index_t m_id_hco3; index_t m_id_ca; index_t m_id_calcite; }; // =================== // MAIN // =================== int main() { // initialize eigen // This is needed if OpenMP is used Eigen::initParallel(); // Setup the log // The output will be on cerr specmicp::logger::ErrFile::stream() = &std::cerr; // And only Warning and error messages will be printed specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; // The database // ------------- // Obtain the database RawDatabasePtr the_database = get_database("../data/cemdata.yaml"); // SpecMiCP options // ---------------- // Set the options AdimensionalSystemSolverOptions specmicp_options = get_specmicp_options(); units::UnitsSet units_set = specmicp_options.units_set; // The mesh // -------- // Obtain the mesh mesh::Mesh1DPtr the_mesh = get_mesh(0.0050); // uniform //mesh::Mesh1DPtr the_mesh = get_mesh(); // non uniform index_t nb_nodes = the_mesh->nb_nodes(); // just boilerplate to make things easier // Print the mesh io::print_mesh("out_carbo_mesh.dat", the_mesh, units::LengthUnit::centimeter); // Initial and boundary conditions // -------------------------------- // Obtain the initial constraints // Note : the database is modified at this point // Only the relevant components are kept at this point AdimensionalSystemConstraints cement_constraints = get_cement_initial_constraints(the_database, units_set); // Freeze the database the_database->freeze_db(); // Obtain the initial condition AdimensionalSystemSolution cement_solution = solve_equilibrium( the_database, cement_constraints, specmicp_options); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the initial condition computation"); // Just to check that everything is ok ! AdimensionalSystemSolutionExtractor extractor(cement_solution, the_database, units_set); std::cout << "Porosity : " << extractor.porosity() << std::endl; std::cout << "Water volume fraction " << extractor.volume_fraction_water() << std::endl; //return EXIT_SUCCESS; // Obtain the boundary conditions AdimensionalSystemConstraints bc_constraints = get_bc_initial_constraints( the_database, specmicp_options.units_set ); AdimensionalSystemSolution bc_solution = solve_equilibrium( the_database, bc_constraints, specmicp_options ); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the boundary conditions computation"); // The constraints // -------------- // Boundary condition // 'list_fixed_nodes' lists the node with fixed composition std::vector list_fixed_nodes = {0}; // list_constraints lists the different speciation constraints in the system // Note : the total concentrations are computed from the initial solution, // and thus different total concentrations do not constitute a reason to create different constraints std::vector list_constraints = {cement_constraints, bc_constraints}; // index_constraints links a node to the set of constraints that will be used std::vector index_constraints(nb_nodes, 0); index_constraints[0] = 1; // Boundary conditions // This is the list of initial composition std::vector list_initial_composition = {cement_solution, bc_solution}; // This list links a node to its initial conditions std::vector index_initial_state(nb_nodes, 0); index_initial_state[0] = 1; // boundary condition // Variables // ----------- // Create the main set of variables // They will be initialized using the list of initial composition satdiff::SaturatedVariablesPtr variables = satdiff::init_variables(the_mesh, the_database, units_set, list_fixed_nodes, list_initial_composition, index_initial_state); std::shared_ptr kinetic_model = std::make_shared(the_database, units_set); variables->kinetic_variables() = kinetic_model->initialize_variables(the_mesh, 0.2); // Staggers // --------- // This section initialize the staggers // The equilibrium stagger // - - - - - - - - - - - - std::shared_ptr kinetic_stagger = std::make_shared(kinetic_model, list_constraints, index_constraints, specmicp_options); // The transport stagger // - - - - - - - - - - - std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); set_transport_options(transport_stagger->options_solver()); // The upscaling stagger // - - - - - - - - - - - CappedPowerLawParameters upscaling_param; upscaling_param.d_eff_0 = 2.726e-12*1e4; upscaling_param.cap = 1e10*1e6; upscaling_param.exponent = 3.32; upscaling_param.porosity_0 = 0.25; upscaling_param.porosity_res = 0.02; CappedPowerLaw upscaling_law(upscaling_param); UpscalingStaggerPtr upscaling_stagger = std::make_shared(upscaling_law.get_law(),the_database, units_set); // Solver // ------ // This section initialize the reactive transport solver ReactiveTransportSolver solver(transport_stagger, kinetic_stagger, upscaling_stagger); set_reactive_solver_options(solver.get_options()); transport_stagger->initialize(variables); kinetic_stagger->initialize(variables); upscaling_stagger->initialize(variables); // Some basic information about the simulation // First argument : the name of the simulation // Second argument : the output function will be called every 3600s SimulationInformation simul_info("kincarbo", 1800); simul_info.output_prefix = "out_kincarbo_"; // Runner // ------- // Create the runner : loop through the timestep ReactiveTransportRunner runner(solver, 0.1, 100.0, simul_info); // Create the output class OutputPolicy output_policy(simul_info, the_mesh, the_database, specmicp_options.units_set); // and bind it to the runner runner.set_output_policy(std::bind(&OutputPolicy::output, &output_policy, std::placeholders::_1, std::placeholders::_2)); // Solve the problem runner.run_until(10*24*3600, cast_var_to_base(variables)); if(not the_database->is_valid()) throw std::runtime_error("The database has been changed during the computation"); AdimensionalSystemSolutionSaver saver(the_database); saver.save_solutions(simul_info.complete_filepath("solutions", "dat"), variables->equilibrium_solutions()); // output information at the end of the timestep io::print_minerals_profile(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("profiles_end", "dat")); io::print_components_total_aqueous_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("c_profiles_end", "dat")); io::print_components_total_solid_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("s_profiles_end", "dat")); } AdimensionalSystemSolverOptions get_specmicp_options() { AdimensionalSystemSolverOptions options; options.solver_options.maxiter_maxstep = 100; options.solver_options.maxstep = 20.0; options.solver_options.threshold_cycling_linesearch = 1e-6; options.solver_options.set_tolerance(1e-8, 1e-14); options.solver_options.disable_condition_check(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.solver_options.enable_scaling(); options.system_options.non_ideality_tolerance = 1e-14; options.system_options.cutoff_total_concentration = 1e-10; options.units_set.length = units::LengthUnit::centimeter; return options; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-8; transport_options.step_tolerance = 1e-14; transport_options.absolute_tolerance = 1e-18; transport_options.alpha = 1.0; //transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-4; } void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options) { reactive_options.maximum_iterations = 100; //500; reactive_options.residuals_tolerance = 1e-2; reactive_options.good_enough_tolerance = 1.0; reactive_options.absolute_residuals_tolerance = 1e-14; reactive_options.implicit_upscaling = true; } RawDatabasePtr get_database(const std::string& path_to_database) { database::Database the_database(path_to_database); std::map swapping({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"} }); the_database.swap_components(swapping); the_database.remove_gas_phases(); return the_database.get_database(); } AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { Vector oxyde_compo(4); oxyde_compo << 66.98, 21.66, 7.19, 2.96; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); scalar_t mult = 1e-6; species_compo *= 0.85e-2; Formulation formulation; formulation.mass_solution = 1.0; formulation.amount_minerals = { {"C3S", species_compo(0)}, {"C2S", species_compo(1)}, {"C3A", species_compo(2)}, {"Gypsum", species_compo(3)}, {"Calcite", species_compo(0)*1e-3} }; formulation.extra_components_to_keep = {"HCO3[-]"}; formulation.concentration_aqueous = { {"Na[+]", mult*1.0298}, {"K[+]", mult*0.0801}, {"Cl[-]", mult*0.0001}, {"HO[-]", mult*1.8298} }, formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2(am)", "Calcite", "Al(OH)3(mic)", "C3AH6", "C3ASO_41H5_18", "C3ASO_84H4_32", "C4AH19", "C4AH13", "C2AH7_5", "CAH10", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", "Straetlingite", "Gypsum", "Ettringite", //"Thaumasite" }; Dissolver dissolver(the_database); dissolver.set_units(units_set); AdimensionalSystemConstraints constraints; constraints.set_charge_keeper(1); constraints.total_concentrations = dissolver.dissolve(formulation); std::cout << constraints.total_concentrations << std::endl; constraints.set_saturated_system(); constraints.set_inert_volume_fraction(0.2); return constraints; } AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { const scalar_t rho_w = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); const scalar_t nacl = 0.3*rho_w; const scalar_t kcl = 0.28*rho_w; Vector total_concentrations; total_concentrations.setZero(the_database->nb_component()); total_concentrations(the_database->get_id_component("K[+]")) = kcl; total_concentrations(the_database->get_id_component("Cl[-]")) = nacl + kcl; total_concentrations(the_database->get_id_component("Na[+]")) = nacl; total_concentrations(the_database->get_id_component("SiO(OH)3[-]")) = 0.0001*rho_w; AdimensionalSystemConstraints constraints; constraints.add_fixed_activity_component(the_database->get_id_component("HO[-]"), -10.3); constraints.set_charge_keeper(the_database->get_id_component("HCO3[-]")); constraints.total_concentrations = total_concentrations; constraints.set_saturated_system(); constraints.disable_surface_model(); constraints.fixed_fugacity_cs ={}; return constraints; } AdimensionalSystemSolution get_bc_initial_compo( RawDatabasePtr the_database, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { Vector variables; AdimensionalSystemSolver solver(the_database, constraints, options); micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve initial composition"); std::cout << variables << std::endl; return solver.get_raw_solution(variables); } void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species) { constexpr double M_CaO = 56.08; constexpr double M_SiO2 = 60.09; constexpr double M_Al2O3 = 101.96; constexpr double M_SO3 = 80.06; Eigen::MatrixXd compo_in_oxyde(4, 4); Vector molar_mass(4); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); //C3S C2S C3A Gypsum compo_in_oxyde << 3, 2, 3, 1, // CaO 1, 1, 0, 0, // SiO2 0, 0, 1, 0, // Al2O3 0, 0, 0, 1; // SO3 Eigen::ColPivHouseholderQR solver(compo_in_oxyde); compo_species = solver.solve(compo_oxyde); } Vector initial_compo(const Vector& publi) { Matrix publi_stochio(5,5); publi_stochio << 1, 0, 0, 0, 0, 9, 6, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Matrix cemdata_stochio(5, 5); cemdata_stochio << 1, 0, 0, 0, 0, 1.0/0.6, 1.0, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Vector oxyde; Eigen::ColPivHouseholderQR solver(publi_stochio); oxyde = solver.solve(publi); Vector for_cemdata = cemdata_stochio*oxyde; return for_cemdata; } mesh::Mesh1DPtr get_mesh(scalar_t dx) { mesh::UniformAxisymmetricMesh1DGeometry geometry; geometry.dx = dx; geometry.radius = 0.75/2.0 + dx; //cm geometry.height = 20.0; geometry.nb_nodes = geometry.radius/dx + 1; return mesh::uniform_axisymmetric_mesh1d(geometry); } mesh::Mesh1DPtr get_mesh() { Vector radius(71); const scalar_t height = 20; radius << 3.751, 3.750, 3.745, 3.740, 3.735, 3.730, 3.720, 3.710, 3.700, 3.690, 3.680, 3.670, 3.660, 3.645, 3.630, 3.615, 3.600, 3.580, 3.560, 3.540, 3.520, 3.500, 3.475, 3.450, 3.425, 3.400, 3.375, 3.350, 3.325, 3.300, 3.275, 3.250, 3.225, 3.200, 3.175, 3.150, 3.125, 3.100, 3.050, 3.025, 3.000, 2.950, 2.900, 2.850, 2.800, 2.750, 2.700, 2.650, 2.600, 2.550, 2.500, 2.450, 2.400, 2.350, 2.300, 2.250, 2.200, 2.150, 2.100, 2.050, 2.000, 1.950, 1.900, 1.850, 1.800, 1.750, 1.700, 1.650, 1.600, 1.550, 1.500 ; radius = radius/10; return mesh::axisymmetric_mesh1d(radius, height); } diff --git a/examples/reactmicp/saturated_react/momas_benchmark.cpp b/examples/reactmicp/saturated_react/momas_benchmark.cpp index b0c43dd..128258e 100644 --- a/examples/reactmicp/saturated_react/momas_benchmark.cpp +++ b/examples/reactmicp/saturated_react/momas_benchmark.cpp @@ -1,561 +1,594 @@ +/* ============================================================================= + + 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 "reactmicp.hpp" #include "database/aqueous_selector.hpp" #include #include #include #include // parameters #define DX 0.05 #define IS_ADVECTIVE true #define MIN_DT 0.001 #define MAX_DT 100.0 #define RESTART_DT MIN_DT using namespace specmicp; RawDatabasePtr get_momas_db() { database::Database thedatabase("../data/momas_benchmark.yaml"); return thedatabase.get_database(); } void prepare_db_for_easy_case(RawDatabasePtr raw_data) { database::Database db_handler(raw_data); db_handler.remove_components({"X5",}); if (raw_data->nb_component() != 6) { throw std::runtime_error("Not enough or Too many component"); } db_handler.remove_solid_phases(); if (not raw_data->is_valid()) { throw std::runtime_error("Database is not valid."); } //std::cout << selector.aqueous_label_to_id("C6") << " - " << selector.aqueous_label_to_id("C7") << std::endl; database::AqueousSelector selector(raw_data); selector.remove_aqueous({selector.aqueous_label_to_id("C6"), selector.aqueous_label_to_id("C7")}); std::cout << raw_data->aqueous.get_nu_matrix() << std::endl; if (raw_data->nb_aqueous() != 5) { throw std::runtime_error("Not enough or Too many aqueous."); } if (not raw_data->is_valid()) { throw std::runtime_error("Database is not valid."); } } AdimensionalSystemSolution easy_material_a( RawDatabasePtr raw_data, const AdimensionalSystemConstraints& constraints, // const AdimensionalSystemSolution& initial_solution, const AdimensionalSystemSolverOptions& options ) { specmicp::Vector variables ; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); specmicp::micpsolver::MiCPPerformance current_perf = solver.solve(variables, true); if (current_perf.return_code != micpsolver::MiCPSolverReturnCode::ResidualMinimized) throw std::runtime_error("Failed to solve initial solution for material A."); return solver.get_raw_solution(variables); } AdimensionalSystemSolution easy_material_b( RawDatabasePtr raw_data, const AdimensionalSystemConstraints& constraints, const specmicp::AdimensionalSystemSolverOptions& options ) { specmicp::Vector variables; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); specmicp::micpsolver::MiCPPerformance current_perf = solver.solve(variables, true); if (current_perf.return_code != micpsolver::MiCPSolverReturnCode::ResidualMinimized) throw std::runtime_error("Failed to solve initial solution for material B."); return solver.get_raw_solution(variables); } AdimensionalSystemSolution easy_bc( RawDatabasePtr raw_data, const AdimensionalSystemConstraints& constraints, const specmicp::AdimensionalSystemSolverOptions& options ) { specmicp::Vector variables; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(variables, 1.0, -4.0); solver.run_pcfm(variables); specmicp::micpsolver::MiCPPerformance current_perf = solver.solve(variables, false); if (current_perf.return_code != micpsolver::MiCPSolverReturnCode::ResidualMinimized) throw std::runtime_error("Failed to solve initial solution for BC."); return solver.get_raw_solution(variables); } using namespace specmicp::reactmicp; using namespace specmicp::reactmicp::solver; using namespace specmicp::reactmicp::systems::satdiff; class MoMasUspcaling: public solver::UpscalingStaggerBase { public: MoMasUspcaling( RawDatabasePtr the_database, units::UnitsSet the_units, bool advective ): m_data(the_database), m_units_set(the_units), m_advective(advective) { } //! \brief Initialize the stagger at the beginning of the computation void initialize(VariablesBasePtr var) { return initialize(var.get()); } virtual void initialize(VariablesBase * const var) override { SaturatedVariables * const true_var = static_cast(var); database::Database db_handler(m_data); true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { // if material b const scalar_t coord = true_var->get_mesh()->get_position(node); if (coord < 1.1 and coord >= 1.0) { true_var->porosity(node) = 0.5; true_var->permeability(node) = 1e-5; if (m_advective) true_var->diffusion_coefficient(node) = 3.3e-4; else true_var->diffusion_coefficient(node) = 330e-3; true_var->fluid_velocity(node) = 5.5e-3; } else // material a { true_var->porosity(node) = 0.25; true_var->permeability(node) = 1e-2; if (m_advective) true_var->diffusion_coefficient(node) = 5.5e-5; else true_var->diffusion_coefficient(node) = 55e-3; true_var->fluid_velocity(node) = 5.5e-3; } std::cout << "node : " << node << " - porosity : " << true_var->porosity(node) << std::endl; } } //! \brief Initialize the stagger at the beginning of an iteration virtual void initialize_timestep(scalar_t _, VariablesBase * const __) override { } //! \brief Solve the equation for the timestep virtual StaggerReturnCode restart_timestep(VariablesBase * const _) override { return StaggerReturnCode::ResidualMinimized; } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; bool m_advective; }; AdimensionalSystemConstraints get_constraints_easy_a(RawDatabasePtr& raw_data) { Vector total_concentrations(Vector::Zero(raw_data->nb_component())); total_concentrations(raw_data->get_id_component("X2")) = -2.0; total_concentrations(raw_data->get_id_component("X4")) = 2.0; AdimensionalSystemConstraints constraints_a(0.25*total_concentrations); constraints_a.disable_conservation_water(); constraints_a.surface_model.model_type = SurfaceEquationType::Equilibrium; constraints_a.surface_model.concentration = 0.25*1.0; constraints_a.inert_volume_fraction = 0.75; return constraints_a; } AdimensionalSystemConstraints get_constraints_easy_b(RawDatabasePtr& raw_data) { Vector total_concentrations(Vector::Zero(raw_data->nb_component())); total_concentrations(raw_data->get_id_component("X2")) = -2.0; total_concentrations(raw_data->get_id_component("X4")) = 2.0; AdimensionalSystemConstraints constraints_b(0.5*total_concentrations); constraints_b.disable_conservation_water(); constraints_b.surface_model.model_type = SurfaceEquationType::Equilibrium; constraints_b.surface_model.concentration = 0.5*10.0; constraints_b.inert_volume_fraction = 0.5; return constraints_b; } AdimensionalSystemConstraints get_constraints_easy_bc(RawDatabasePtr& raw_data) { Vector total_concentrations(Vector::Zero(raw_data->nb_component())); total_concentrations(raw_data->get_id_component("X1")) = 0.3; total_concentrations(raw_data->get_id_component("X2")) = 0.3; total_concentrations(raw_data->get_id_component("X3")) = 0.3; AdimensionalSystemConstraints constraints_bc(total_concentrations); constraints_bc.disable_conservation_water(); constraints_bc.surface_model.model_type = SurfaceEquationType::NoEquation; constraints_bc.surface_model.concentration = 0.0; constraints_bc.inert_volume_fraction = 0.0; return constraints_bc; } AdimensionalSystemSolverOptions get_specmicp_options() { AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 1.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.non_monotone_linesearch = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-10; options.solver_options.steptol = 1e-14; options.solver_options.threshold_cycling_linesearch = 1e-8; options.system_options.non_ideality_tolerance = 1e-10; options.system_options.non_ideality = false; options.system_options.restart_concentration = -2; options.use_pcfm = true; return options; } mesh::Mesh1DPtr get_mesh(scalar_t dx) { scalar_t tot_length = 2.1+dx; index_t nb_nodes = tot_length/dx +2; return mesh::uniform_mesh1d(nb_nodes, dx, 1.0); } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-8; transport_options.step_tolerance = 1e-12; transport_options.absolute_tolerance = 1e-6; transport_options.alpha = 1.0; //transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-2; } void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options) { reactive_options.maximum_iterations = 50; //500; reactive_options.residuals_tolerance = 1e-2; reactive_options.good_enough_tolerance = 1.0; reactive_options.absolute_residuals_tolerance = 1e-6; reactive_options.implicit_upscaling = false; } int main() { Eigen::initParallel(); Timer global_timer; global_timer.start(); io::OutFile output_gen("out_momas_out.txt"); io::print_reactmicp_header(output_gen); specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; RawDatabasePtr database = get_momas_db(); prepare_db_for_easy_case(database); units::UnitsSet the_units = units::UnitsSet(); the_units.length = units::LengthUnit::decimeter; // so that rho_w ~ 1 scalar_t dx=DX; mesh::Mesh1DPtr the_mesh = get_mesh(dx); AdimensionalSystemConstraints constraints_a = get_constraints_easy_a(database); AdimensionalSystemConstraints constraints_b = get_constraints_easy_b(database); AdimensionalSystemConstraints constraints_bc = get_constraints_easy_bc(database); AdimensionalSystemSolverOptions options = get_specmicp_options(); options.units_set = the_units; AdimensionalSystemSolution mat_bc = easy_bc(database, constraints_bc, options); AdimensionalSystemSolution mat_a = easy_material_a(database, constraints_a, options); AdimensionalSystemSolution mat_b = easy_material_b(database, constraints_b, options); options.solver_options.maxstep = 1.0; options.solver_options.use_scaling = true; options.solver_options.non_monotone_linesearch = true; index_t nb_nodes = the_mesh->nb_nodes(); std::vector list_constraints = {constraints_a, constraints_b, constraints_bc}; std::vector list_initial_composition = {mat_a, mat_b, mat_bc}; std::vector index_initial_state(nb_nodes, 0); std::vector index_constraints(nb_nodes, 0); index_t start_mat_b = 1.0/dx; index_t end_mat_b = 1.1/dx; for (index_t node=start_mat_b; node list_fixed_nodes = {0, }; std::map list_slaves_nodes = {{nb_nodes-1, nb_nodes-2}}; std::vector list_immobile_components = {0, 1}; systems::satdiff::SaturatedVariablesPtr variables = systems::satdiff::init_variables(the_mesh, database, the_units, list_fixed_nodes, list_initial_composition, index_initial_state); ChemistryStaggerPtr equilibrium_stagger = std::make_shared(list_constraints, index_constraints, options); std::shared_ptr transport_stagger = std::make_shared( variables, list_fixed_nodes, list_slaves_nodes, list_immobile_components); set_transport_options(transport_stagger->options_solver()); const bool is_advective = IS_ADVECTIVE; UpscalingStaggerPtr upscaling_stagger = std::make_shared(database, the_units, is_advective); ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); set_reactive_solver_options(solver.get_options()); // mesh output io::print_mesh("out_momas_mesh.dat", the_mesh, the_units.length); //std::cout << variables->displacement() << std::endl; io::OutFile output_iter("out_momas_iter.dat"); std::ofstream output_x1, output_x2, output_x3, output_x4; std::ofstream output_sx1, output_sx2, output_sx3, output_sx4; std::ofstream output_c1, output_c2, output_s; output_x1.open("out_momas_x1.dat"); output_x2.open("out_momas_x2.dat"); output_x3.open("out_momas_x3.dat"); output_x4.open("out_momas_x4.dat"); output_sx1.open("out_momas_sx1.dat"); output_sx2.open("out_momas_sx2.dat"); output_sx3.open("out_momas_sx3.dat"); output_sx4.open("out_momas_sx4.dat"); output_c1.open("out_momas_c1.dat"); output_c2.open("out_momas_c2.dat"); output_s.open("out_momas_s.dat"); index_t cnt = 0; scalar_t dt=RESTART_DT; reactmicp::solver::Timestepper timestepper(MIN_DT, MAX_DT, 5000, 2.0); timestepper.get_options().alpha_average = 0.3; timestepper.get_options().decrease_failure = 0.1; timestepper.get_options().increase_factor = 1.05; timestepper.get_options().decrease_factor = 0.50; timestepper.get_options().iteration_lower_target = 1.001; io::print_reactmicp_performance_long_header(output_iter); while (timestepper.get_total() < timestepper.get_total_target()) { output_gen << "dt : " << dt << std::endl; Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); // if (retcode > reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) //{ io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total()+dt, solver.get_perfs()); //} dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = RESTART_DT; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } output_gen << "Time : " << timestepper.get_total() << std::endl; io::print_reactmicp_performance_short(output_gen, solver.get_perfs()); scalar_t total = timestepper.get_total(); if (cnt % 10== 0) { output_x1 << total; output_x2 << total; output_x3 << total; output_x4 << total; output_sx1 << total; output_sx2 << total; output_sx3 << total; output_sx4 << total; output_c1 << total; output_c2 << total; output_s << total; for (index_t node: the_mesh->range_nodes()) { output_x1 << "\t" << variables->aqueous_concentration(node, 1, variables->displacement()); output_x2 << "\t" << variables->aqueous_concentration(node, 2, variables->displacement()); output_x3 << "\t" << variables->aqueous_concentration(node, 3, variables->displacement()); output_x4 << "\t" << variables->aqueous_concentration(node, 4, variables->displacement()); output_sx1 << "\t" << variables->solid_concentration(node, 1, variables->displacement()); output_sx2 << "\t" << variables->solid_concentration(node, 2, variables->displacement()); output_sx3 << "\t" << variables->solid_concentration(node, 3, variables->displacement()); output_sx4 << "\t" << variables->solid_concentration(node, 4, variables->displacement()); output_c1 << "\t" << variables->equilibrium_solution(node).secondary_molalities(0); output_c2 << "\t" << variables->equilibrium_solution(node).secondary_molalities(1); output_s << "\t" << pow10(variables->equilibrium_solution(node).main_variables(5)); } output_x1 << std::endl; output_x2 << std::endl; output_x3 << std::endl; output_x4 << std::endl; output_sx1 << std::endl; output_sx2 << std::endl; output_sx3 << std::endl; output_sx4 << std::endl; output_c1 << std::endl; output_c2 << std::endl; output_s << std::endl; } ++ cnt; } variables->displacement()(database->get_id_component("X1")) = 0; variables->displacement()(database->get_id_component("X2")) = -2.0; variables->displacement()(database->get_id_component("X3")) = 0; variables->displacement()(database->get_id_component("X4")) = 2.0; timestepper.set_total_target(6000); dt = RESTART_DT; transport_stagger->options_solver().absolute_tolerance = 1e-10; solver.get_options().absolute_residuals_tolerance = 1e-6; while (timestepper.get_total() < timestepper.get_total_target()) { output_gen << "dt : " << dt << std::endl; Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); // if (retcode > reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) //{ io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total()+dt, solver.get_perfs()); //} dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = RESTART_DT; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } output_gen << "Time : " << timestepper.get_total() << std::endl; io::print_reactmicp_performance_short(output_gen, solver.get_perfs()); scalar_t total = timestepper.get_total(); if (cnt % 10== 0) { output_x1 << total; output_x2 << total; output_x3 << total; output_x4 << total; output_sx1 << total; output_sx2 << total; output_sx3 << total; output_sx4 << total; output_c1 << total; output_c2 << total; output_s << total; for (index_t node: the_mesh->range_nodes()) { output_x1 << "\t" << variables->aqueous_concentration(node, 1, variables->displacement()); output_x2 << "\t" << variables->aqueous_concentration(node, 2, variables->displacement()); output_x3 << "\t" << variables->aqueous_concentration(node, 3, variables->displacement()); output_x4 << "\t" << variables->aqueous_concentration(node, 4, variables->displacement()); output_sx1 << "\t" << variables->solid_concentration(node, 1, variables->displacement()); output_sx2 << "\t" << variables->solid_concentration(node, 2, variables->displacement()); output_sx3 << "\t" << variables->solid_concentration(node, 3, variables->displacement()); output_sx4 << "\t" << variables->solid_concentration(node, 4, variables->displacement()); output_c1 << "\t" << variables->equilibrium_solution(node).secondary_molalities(0); output_c2 << "\t" << variables->equilibrium_solution(node).secondary_molalities(1); output_s << "\t" << pow10(variables->equilibrium_solution(node).main_variables(5)); } output_x1 << std::endl; output_x2 << std::endl; output_x3 << std::endl; output_x4 << std::endl; output_sx1 << std::endl; output_sx2 << std::endl; output_sx3 << std::endl; output_sx4 << std::endl; output_c1 << std::endl; output_c2 << std::endl; output_s << std::endl; } ++ cnt; } reactmicp::solver::ReactiveTransportTimer timer = solver.get_timer(); io::print_reactmicp_timer(output_gen, timer); global_timer.stop(); output_gen << "Total computation time : " << global_timer.elapsed_time() << "s." << std::endl; return EXIT_SUCCESS; } diff --git a/examples/reactmicp/saturated_react/react_leaching.cpp b/examples/reactmicp/saturated_react/react_leaching.cpp index 36ec63d..09699ee 100644 --- a/examples/reactmicp/saturated_react/react_leaching.cpp +++ b/examples/reactmicp/saturated_react/react_leaching.cpp @@ -1,731 +1,764 @@ +/* ============================================================================= + + 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 "reactmicp.hpp" #include #include #include using namespace specmicp; // Initial conditions // ================== specmicp::RawDatabasePtr leaching_database() { specmicp::database::Database thedatabase("../data/cemdata_specmicp.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"} }); thedatabase.remove_gas_phases(); thedatabase.swap_components(swapping); return thedatabase.get_database(); } const double M_CaO = 56.08; const double M_SiO2 = 60.09; const double M_Al2O3 = 101.96; const double M_SO3 = 80.06; void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species) { Eigen::MatrixXd compo_in_oxyde(4, 4); Vector molar_mass(4); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); //C3S C2S C3A Gypsum compo_in_oxyde << 3, 2, 3, 1, // CaO 1, 1, 0, 0, // SiO2 0, 0, 1, 0, // Al2O3 0, 0, 0, 1; // SO3 Eigen::FullPivLU solver(compo_in_oxyde); compo_species = solver.solve(compo_oxyde); } AdimensionalSystemSolution initial_leaching_pb( RawDatabasePtr raw_data, scalar_t mult, units::UnitsSet the_units) { Formulation formulation; Vector oxyde_compo(4); oxyde_compo << 62.9, 20.6, 5.8, 3.1; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); std::cout << species_compo << std::endl; scalar_t m_c3s = mult*species_compo(0); //0.6; scalar_t m_c2s = mult*species_compo(1); //0.2; scalar_t m_c3a = mult*species_compo(2); //0.1; scalar_t m_gypsum = mult*species_compo(3); //0.1; scalar_t wc = 0.5; scalar_t m_water = wc*1.0e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = 1; constraints.set_saturated_system(); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 100.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.set_tolerance(1e-10, 1e-14); options.solver_options.disable_crashing(); options.solver_options.enable_scaling(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.system_options.non_ideality_tolerance = 1e-10; options.units_set = the_units; specmicp::Vector x; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(x, 0.8, -3.0); specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); std::cout << "Initial return code : " << (int) perf.return_code << std::endl; if ((int) perf.return_code <= (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet) { throw std::runtime_error("Initial solution has not converged"); } return solver.get_raw_solution(x); } AdimensionalSystemSolution initial_blank_leaching_pb( RawDatabasePtr raw_data, scalar_t mult, units::UnitsSet the_units) { Formulation formulation; Vector oxyde_compo(4); oxyde_compo << 62.9, 20.6, 5.8, 3.1; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); std::cout << species_compo << std::endl; scalar_t m_c3s = 0.6; scalar_t m_c2s = 0.2; scalar_t m_c3a = 0.1; scalar_t m_gypsum = 0.1; scalar_t wc = 0.8; scalar_t m_water = wc*1.0e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"SiO2,am", mult}, }; // formulation.concentration_aqueous = { // {"Ca[2+]", 1e-7}, // {"Al(OH)4[-]", 1e-7}, // {"SO4[2-]", 1e-7} // }; formulation.extra_components_to_keep = {"Ca[2+]", "SO4[2-]", "Al(OH)4[-]"}; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = 1; constraints.set_saturated_system(); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.factor_descent_condition = -1.0; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-4; options.solver_options.steptol = 1e-14; options.solver_options.non_monotone_linesearch = true; options.system_options.non_ideality_tolerance = 1e-10; options.units_set = the_units; Vector x; AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(x, 0.75, -4.0); micpsolver::MiCPPerformance perf = solver.solve(x, false); std::cout << "Initial return code : " << (int) perf.return_code << std::endl; if ((int) perf.return_code <= (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet) { throw std::runtime_error("Initial solution has not converged"); } AdimensionalSystemSolution solution = solver.get_raw_solution(x); AdimensionalSystemSolutionModificator extractor(solution, raw_data, the_units); extractor.remove_solids(); Vector totconc(raw_data->nb_component()); totconc(0) = extractor.density_water()*extractor.total_aqueous_concentration(0); for (index_t component: raw_data->range_aqueous_component()) { totconc(component) = 0.01*extractor.density_water()*extractor.total_aqueous_concentration(component); } constraints.total_concentrations = totconc; solver = AdimensionalSystemSolver(raw_data, constraints, options); perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) micpsolver::MiCPSolverReturnCode::NotConvergedYet); return solver.get_raw_solution(x); } // Upscaling // ========= using namespace specmicp::reactmicp; using namespace specmicp::reactmicp::solver; using namespace specmicp::reactmicp::systems::satdiff; class LeachingUspcaling: public solver::UpscalingStaggerBase { public: LeachingUspcaling(RawDatabasePtr the_database, units::UnitsSet the_units): m_data(the_database), m_units_set(the_units) { } //! \brief Initialize the stagger at the beginning of the computation void initialize(VariablesBasePtr var) { return initialize(var.get()); } virtual void initialize(VariablesBase * const var) override { SaturatedVariables * const true_var = static_cast(var); database::Database db_handler(m_data); m_dt = 1; m_id_cshj = db_handler.mineral_label_to_id("CSH,j"); m_initial_sat_cshj = true_var->equilibrium_solution(1).main_variables( m_data->nb_component()+m_id_cshj); //m_initial_sat_cshj = 0.36; std::cout << m_initial_sat_cshj << std::endl; true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } //! \brief Initialize the stagger at the beginning of an iteration virtual void initialize_timestep(scalar_t dt, VariablesBase * const var) override { SaturatedVariables * const true_var = static_cast(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! \brief Solve the equation for the timestep virtual StaggerReturnCode restart_timestep(VariablesBase * const var) override { SaturatedVariables* true_var = static_cast(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } return StaggerReturnCode::ResidualMinimized; } scalar_t diffusion_coefficient(scalar_t porosity) { const scalar_t factor = 1e4; scalar_t poro = factor*std::exp(9.85*porosity-29.08); // const scalar_t de_0 = 2.76e-12; // const scalar_t porosity_r = 0.02; // const scalar_t exponent = 3.32; //if (porosity > 0.7) // return factor*4.0*1e-10; // else // { // const scalar_t ratio = ((porosity - porosity_r)/(0.25 - porosity_r)); // poro = factor*de_0*std::pow(ratio, exponent); // } return std::min(poro,factor*1e-10); } void upscaling_one_node(index_t node, SaturatedVariables * const true_var) { AdimensionalSystemSolutionExtractor extractor( true_var->equilibrium_solution(node), m_data, m_units_set ); scalar_t porosity = extractor.porosity(); //- true_var->equilibrium_solution(node).main_variables(m_data->nb_component)/m_initial_sat_cshj*0.05; //std::cout << "porosity : " << porosity // << " - saturation water" << true_var->equilibrium_solution(node).main_variables(0) << std::endl; true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = diffusion_coefficient(porosity); } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; }; // void set_specmicp_options(AdimensionalSystemSolverOptions& options) { options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-16; options.solver_options.fvectol = 1e-10; options.solver_options.steptol = 1e-14; options.solver_options.non_monotone_linesearch = true; options.system_options.non_ideality_tolerance = 1e-12; options.system_options.non_ideality_max_iter = 100; options.solver_options.threshold_cycling_linesearch = 1e-5; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-6; transport_options.step_tolerance = 1e-14; transport_options.alpha = 1; transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-2; transport_options.absolute_tolerance = 1e-16; } void set_reactive_solver_options(ReactiveTransportOptions& solver_options) { solver_options.maximum_iterations = 100; solver_options.residuals_tolerance = 1e-2; solver_options.good_enough_tolerance = 1.0; solver_options.absolute_residuals_tolerance = 1e-16; solver_options.implicit_upscaling = true; } mesh::Mesh1DPtr get_mesh(scalar_t dx, index_t nb_nodes, index_t additional_nodes) { mesh::UniformAxisymmetricMesh1DGeometry geometry; geometry.dx = dx; geometry.radius = 3.5 + additional_nodes*dx; //cm geometry.height = 8.0; geometry.nb_nodes = nb_nodes + additional_nodes; return mesh::uniform_axisymmetric_mesh1d(geometry); } mesh::Mesh1DPtr get_mesh() { Vector radius(66); const scalar_t height = 8.0; radius << 3.5005, 3.5000, 3.4995, 3.4990, 3.4980, 3.4970, 3.4960, 3.4950, 3.4925, 3.4900, 3.4875, 3.4850, 3.4825, 3.4800, 3.4775, 3.4750, 3.4725, 3.4700, 3.4675, 3.4650, 3.4625, 3.4600, 3.4575, 3.4550, 3.4525, 3.4500, 3.4475, 3.445, 3.4425, 3.440, 3.4375, 3.435, 3.4325, 3.430, 3.4275, 3.425, 3.4225, 3.420, 3.4175, 3.415, 3.4125, 3.410, 3.4075, 3.405, 3.4025, 3.400, 3.3975, 3.395, 3.3925, 3.390, 3.3875, 3.385, 3.3825, 3.38, 3.3775, 3.3750, 3.3725, 3.3700, 3.3675, 3.365, 3.3625, 3.36, 3.3575, 3.355, 3.325, 3.3 ; return mesh::axisymmetric_mesh1d(radius, height); } void output_mesh(mesh::Mesh1DPtr the_mesh) { std::ofstream output_mesh; output_mesh.open("out_leaching_mesh.dat"); output_mesh << "Node\tPosition" << std::endl; for (index_t node: the_mesh->range_nodes()) { output_mesh << node << "\t" << the_mesh->get_position(node) << std::endl; } output_mesh.close(); } void print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const std::string& filepath ) { std::ofstream ofile(filepath); ofile << "Radius"; for (index_t mineral: the_database->range_mineral()) { ofile << "\t" << the_database->get_label_mineral(mineral); } ofile << "\t" << "Porosity"; ofile << "\t" << "pH"; ofile << std::endl; for (index_t node: the_mesh->range_nodes()) { ofile << the_mesh->get_position(node); AdimensionalSystemSolutionExtractor extractor(variables->equilibrium_solution(node), the_database, units::UnitsSet()); for (index_t mineral: the_database->range_mineral()) { ofile << "\t" << extractor.volume_fraction_mineral(mineral); } ofile << "\t" << variables->porosity(node); ofile << "\t" << extractor.pH(); ofile << std::endl; } ofile.close(); } // Main // ==== int main() { Eigen::initParallel(); specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; RawDatabasePtr raw_data = leaching_database(); units::UnitsSet the_units; the_units.length = units::LengthUnit::centimeter; AdimensionalSystemSolution initial = initial_leaching_pb(raw_data, 0.015, the_units); AdimensionalSystemSolutionModificator extractor(initial, raw_data, the_units); index_t id_ca = raw_data->get_id_component("Ca[2+]"); index_t id_si = raw_data->get_id_component("SiO(OH)3[-]"); std::cout << extractor.total_solid_concentration(id_ca) << " - " << extractor.porosity() << std::endl; extractor.scale_total_concentration(id_ca, 0.0145); std::cout << extractor.total_solid_concentration(id_ca) << " - " << extractor.porosity() << std::endl; std::cout << initial.main_variables << std::endl; AdimensionalSystemSolution blank = initial_blank_leaching_pb(raw_data, 0.005, the_units); std::cout << blank.main_variables << std::endl; scalar_t dx = 0.0005; index_t nb_nodes = 150; index_t additional_nodes = 1; //mesh::Mesh1DPtr the_mesh = get_mesh(dx, nb_nodes, additional_nodes); mesh::Mesh1DPtr the_mesh = get_mesh(); nb_nodes = the_mesh->nb_nodes(); std::vector list_initial_composition = {initial, blank}; std::vector index_initial_state(nb_nodes, 0); for (int i=0; i< additional_nodes; ++i) index_initial_state[i] = 1; std::vector list_fixed_nodes = {0, }; systems::satdiff::SaturatedVariablesPtr variables = systems::satdiff::init_variables(the_mesh, raw_data, the_units, list_fixed_nodes, list_initial_composition, index_initial_state); specmicp::AdimensionalSystemConstraints constraints; constraints.charge_keeper = 1; constraints.set_saturated_system(); constraints.inert_volume_fraction = 0.0; AdimensionalSystemSolverOptions options; set_specmicp_options(options); options.units_set = the_units; ChemistryStaggerPtr equilibrium_stagger = std::make_shared(nb_nodes, constraints, options); std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); dfpmsolver::ParabolicDriverOptions& transport_options = transport_stagger->options_solver(); set_transport_options(transport_options); UpscalingStaggerPtr upscaling_stagger = std::make_shared(raw_data, the_units); ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); set_reactive_solver_options(solver.get_options()); io::OutFile output_iter("out_leaching_iter.dat"); std::ofstream output_c_ca, output_s_ca, output_s_si; std::ofstream output_poro; std::ofstream output_loss_ca; output_c_ca.open("out_c_ca.dat"); output_s_ca.open("out_s_ca.dat"); output_s_si.open("out_s_si.dat"); output_poro.open("out_poro.dat"); output_loss_ca.open("out_loss_ca.dat"); scalar_t initial_ca = 0; for (index_t node: the_mesh->range_nodes()) { initial_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); } scalar_t dt=2.0; io::print_reactmicp_performance_long_header(output_iter); Timestepper timestepper(1.0, 500.0, 25*24*3600, 2); int cnt =0; while (timestepper.get_total() < timestepper.get_total_target()) { Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total() , solver.get_perfs()); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = 1.0; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } // std::cout << "time : " << total/3600/24 << std::endl // << "Iter : " << solver.get_perfs().nb_iterations << std::endl // << "Residuals : " << solver.get_perfs().residuals << std::endl; if (cnt % 100 == 0) { scalar_t time = timestepper.get_total()/3600.0/24.0; scalar_t sqrt_time = std::sqrt(time); output_c_ca << time; output_s_ca << time; output_s_si << time; output_loss_ca << time << "\t" << sqrt_time; output_poro << time; scalar_t amount_ca = 0.0; for (index_t node: the_mesh->range_nodes()) { amount_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); output_c_ca << "\t" << variables->aqueous_concentration(node, id_ca, variables->displacement()); output_s_ca << "\t" << variables->solid_concentration( node, id_ca, variables->displacement()); output_s_si << "\t" << variables->solid_concentration( node, id_si, variables->displacement()); output_poro << "\t" << variables->porosity(node); } output_poro << std::endl; output_loss_ca << "\t" << (initial_ca - amount_ca)/1.75929e-2 << std::endl; output_c_ca << std::endl; output_s_ca << std::endl; output_s_si << std::endl; } ++cnt; } print_minerals_profile(raw_data, variables, the_mesh, "out_leaching_minerals_profile_25d.dat"); timestepper.set_total_target(90*24*3600); while (timestepper.get_total() < timestepper.get_total_target()) { Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total() , solver.get_perfs()); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = 1.0; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } // std::cout << "time : " << total/3600/24 << std::endl // << "Iter : " << solver.get_perfs().nb_iterations << std::endl // << "Residuals : " << solver.get_perfs().residuals << std::endl; if (cnt % 100 == 0) { scalar_t time = timestepper.get_total()/3600.0/24.0; scalar_t sqrt_time = std::sqrt(time); output_c_ca << time; output_s_ca << time; output_s_si << time; output_loss_ca << time << "\t" << sqrt_time; output_poro << time; scalar_t amount_ca = 0.0; for (index_t node: the_mesh->range_nodes()) { amount_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); output_c_ca << "\t" << variables->aqueous_concentration(node, id_ca, variables->displacement()); output_s_ca << "\t" << variables->solid_concentration( node, id_ca, variables->displacement()); output_s_si << "\t" << variables->solid_concentration( node, id_si, variables->displacement()); output_poro << "\t" << variables->porosity(node); } output_poro << std::endl; output_loss_ca << "\t" << (initial_ca - amount_ca)/1.75929e-2 << std::endl; output_c_ca << std::endl; output_s_ca << std::endl; output_s_si << std::endl; } ++cnt; } io::print_reactmicp_timer(output_iter, solver.get_timer()); } diff --git a/examples/reactmicp/unsaturated/acc_carbo.cpp b/examples/reactmicp/unsaturated/acc_carbo.cpp index b6e3340..a2c4d7d 100644 --- a/examples/reactmicp/unsaturated/acc_carbo.cpp +++ b/examples/reactmicp/unsaturated/acc_carbo.cpp @@ -1,534 +1,536 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ //! \file acc_carbo.cpp //! \brief Accelerated carbonation example //! //! This is an example to show the features of the unsaturated //! reactive transport solver //! It is a simple study of the accelerated carbonation of cement paste //! (with drying) //! //! #include "reactmicp_unsaturated.hpp" #include "reactmicp/systems/unsaturated/variables.hpp" #include #include "reactmicp/io/hdf5_unsaturated.hpp" #include "utils/io/specmicp_hdf5.hpp" #include "dfpm/io/hdf5_mesh.hpp" #include "database/io/hdf5_database.hpp" #include "dfpmsolver/parabolic_structs.hpp" #include "physics/unsaturated_laws.hpp" #include "utils/cli/parser.hpp" #include using namespace specmicp; using namespace specmicp::reactmicp; using namespace specmicp::reactmicp::systems::unsaturated; using VariablesBase = solver::VariablesBase; using StaggerReturnCode = solver::StaggerReturnCode; class UpscalingStagger; database::RawDatabasePtr get_database(); AdimensionalSystemSolution get_initial_condition( database::RawDatabasePtr the_database, const units::UnitsSet& units_set ); // Upscaling stagger -> user models class UpscalingStagger: public solver::UpscalingStaggerBase { public: UpscalingStagger() {} ~UpscalingStagger() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables virtual void initialize(VariablesBase * const var) override; //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables virtual void initialize_timestep( scalar_t dt, VariablesBase * const var) override; //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables virtual StaggerReturnCode restart_timestep( VariablesBase * const var) override; // User models scalar_t capillary_pressure(index_t node, scalar_t saturation); scalar_t vapor_pressure(index_t node, scalar_t saturation); scalar_t relative_liquid_diffusivity(index_t node, scalar_t saturation); scalar_t relative_liquid_permeability(index_t node, scalar_t saturation); scalar_t relative_gas_diffusivity(index_t node, scalar_t saturation); scalar_t intrinsic_permeability(scalar_t porosity); scalar_t intrinsic_liquid_diffusivity(scalar_t porosity); scalar_t resistance_gas_diffusivity(scalar_t porosity); private: scalar_t m_a {37.5479e6}; scalar_t m_b {2.1684}; scalar_t m_alpha {7.27}; scalar_t m_beta {0.440}; scalar_t m_pv_sat {3170}; scalar_t m_exp_r_l_d {3.00}; scalar_t m_exp_i_g_d {2.74}; scalar_t m_exp_r_g_d {4.20}; scalar_t m_exp_r_l_k {0.4191}; scalar_t m_k_0 {1e-21*1e4}; scalar_t m_d_0 {2.3e-13*1e4}; scalar_t m_phi_0 {0.2}; }; // implementations int main(int argc, char* argv[]) { cli::CommandLineParser cli_parser; cli_parser.add_option('n', "min_dt", 0.01, "minimum timestep (s)"); cli_parser.add_option('m', "max_dt", 10.0, "maximum timestep (s)"); cli_parser.add_option('d', "dx", 0.05, "space step (cm)"); cli_parser.add_option('r', "run_until", 10.0*24.0*3600.0, "run simulation until s"); cli_parser.add_option('p', "p_h20", 1800.0, "vapor pressure at the boundary"); cli_parser.set_help_message("Atmospheric carbonation"); cli_parser.parse(argc, argv); init_logger(&std::cout, logger::Warning); index_t nb_nodes = 50; scalar_t dx = cli_parser.get_option("dx"); // cm scalar_t cross_section = 5; // cm^2 units::UnitsSet units_set; units_set.length = units::LengthUnit::centimeter; specmicp::RawDatabasePtr the_database = get_database(); AdimensionalSystemSolution init = get_initial_condition( the_database, units_set); AdimensionalSystemSolutionExtractor extr(init, the_database, units_set); std::cout << extr.porosity() << " - " << extr.saturation_water() << std::endl; //return EXIT_SUCCESS; mesh::Mesh1DPtr the_mesh = mesh::uniform_mesh1d({dx, nb_nodes, cross_section}); index_t id_co2 = the_database->get_id_component("CO2"); VariablesInterface variable_interface(the_mesh, the_database, {0, id_co2}, units_set); variable_interface.set_binary_gas_diffusivity(0, 0.240); variable_interface.set_binary_gas_diffusivity(id_co2, 0.160); std::shared_ptr upscaling_stagger = std::make_shared(); auto* call_ptr = upscaling_stagger.get(); variable_interface.set_vapor_pressure_model( [call_ptr](index_t node, scalar_t sat) -> scalar_t { return call_ptr->vapor_pressure(node, sat); }); for (index_t node=1; nodenb_nodes(); ++node) { variable_interface.initialize_variables(node, extr); } variable_interface.set_porosity(0, 1.0); variable_interface.set_liquid_saturation(0, 0.0); variable_interface.set_partial_pressure(id_co2, 0, 100.0); variable_interface.set_partial_pressure(0, 0, cli_parser.get_option("p_h20")); std::shared_ptr vars = variable_interface.get_variables(); vars->set_aqueous_scaling(0, 1.0e3/18.3e-3*1e-6); for (auto aqc: the_database->range_aqueous_component()) { vars->set_aqueous_scaling(aqc, 100e-6); } //vars->set_gaseous_scaling(0, 1.0/vars->get_rt()); //vars->set_gaseous_scaling(id_co2, 1.0/vars->get_rt()); std::cout << "Youpla : " << vars->get_rt() << std::endl; std::shared_ptr eq_constraints = equilibrium_constraints(the_mesh); eq_constraints->add_fixed_node(0); eq_constraints->set_constraint_for_all(eq_constraints->new_constraints()); eq_constraints->get_options().units_set = units_set; micpsolver::MiCPSolverOptions& copts = eq_constraints->get_options().solver_options; copts.set_maximum_iterations(200); copts.set_maximum_step_length(10, 200); copts.set_tolerance(1e-8, 1e-14); eq_constraints->get_options().system_options.non_ideality_tolerance = 1e-12; std::shared_ptr chemistry_stagger = equilibrium_stagger(vars, eq_constraints); upscaling_stagger->initialize(vars.get()); vars->set_relative_variables(0); chemistry_stagger->initialize(vars.get()); TransportConstraints transport_constraints; transport_constraints.add_gas_node(0); transport_constraints.add_fixed_node(0); std::shared_ptr transport_stagger = unsaturated_transport_stagger(vars, transport_constraints, true, true); transport_stagger->initialize(vars.get()); ((*eq_constraints)[0]).set_water_partial_pressure_model( std::bind(&UpscalingStagger::vapor_pressure, upscaling_stagger.get(), 1, std::placeholders::_1) ); auto check = variable_interface.check_variables(); if (check >= VariablesValidity::error) { throw std::runtime_error("Invalid variables"); } solver::ReactiveTransportSolver react_solver(transport_stagger, chemistry_stagger, upscaling_stagger); solver::ReactiveTransportOptions& opts = react_solver.get_options(); opts.residuals_tolerance = 1e-2; opts.good_enough_tolerance = 0.99; opts.maximum_iterations = 100; transport_stagger->get_saturation_options()->maximum_iterations = 500; transport_stagger->get_saturation_options()->step_tolerance = 1e-14; transport_stagger->get_saturation_options()->residuals_tolerance = 1e-8; //transport_stagger->get_gas_options(3)->maximum_iterations = 5000; opts.step_tolerance = 1e-10; io::HDF5File save_file("out_acc_carbo.hdf5", io::HDF5_OpenMode::CreateTruncate); io::save_database_labels(save_file, "database", "/", the_database); io::save_mesh_coordinates(save_file, "mesh", "/", the_mesh); io::UnsaturatedHDF5Saver saver(vars); saver.save_timepoint(save_file, "0", "/"); save_file.close(); solver::SimulationInformation simul_info("acc_carbo", 900); auto out_pol = [&saver]( scalar_t timestep, solver::VariablesBasePtr vars) { io::HDF5File file("out_acc_carbo.hdf5", io::HDF5_OpenMode::OpenReadWrite); saver.save_timepoint(file, std::to_string(timestep), "/"); }; //solver::ReactiveTransportReturnCode retcode = react_solver.solve_timestep(0.01, vars); //retcode = react_solver.solve_timestep(1.0, vars); //std::cout << (int) retcode << std::endl; // retcode = react_solver.solve_timestep(5.0, vars); // std::cout << (int) retcode << std::endl; // retcode = react_solver.solve_timestep(10.0, vars); // std::cout << (int) retcode << std::endl; // retcode = react_solver.solve_timestep(10.0, vars); // std::cout << (int) retcode << std::endl; solver::ReactiveTransportRunner runner( react_solver, cli_parser.get_option("min_dt"), cli_parser.get_option("max_dt"), simul_info); runner.set_output_policy(out_pol); runner.run_until(cli_parser.get_option("run_until"), vars); std::cout << vars->get_liquid_saturation().variable << std::endl; std::cout << vars->get_liquid_saturation()(1) - vars->get_liquid_saturation()(2) << std::endl; std::cout << vars->get_pressure_main_variables(id_co2).variable << std::endl; } void UpscalingStagger::initialize(VariablesBase * const var) { UnsaturatedVariables * const true_var = static_cast(var); // set relative models true_var->set_capillary_pressure_model( [this](index_t x, scalar_t sat){ return this->capillary_pressure(x, sat); }); true_var->set_relative_liquid_permeability_model( [this](index_t x, scalar_t sat){ return this->relative_liquid_permeability(x, sat); }); true_var->set_relative_liquid_diffusivity_model( [this](index_t x, scalar_t sat){ return this->relative_liquid_diffusivity(x, sat); }); true_var->set_relative_gas_diffusivity_model( [this](index_t x, scalar_t sat){ return this->relative_gas_diffusivity(x, sat); }); true_var->set_vapor_pressure_model( [this](index_t x, scalar_t sat){ return this->vapor_pressure(x, sat); }); // initialization SecondaryTransientVariable& porosity = true_var->get_porosity(); SecondaryVariable& permeability = true_var->get_liquid_permeability(); SecondaryVariable& liq_diffusivity = true_var->get_liquid_diffusivity(); SecondaryVariable& gas_diffusivity = true_var->get_resistance_gas_diffusivity(); true_var->set_relative_variables(); gas_diffusivity(0) = resistance_gas_diffusivity(1.0); true_var->get_relative_gas_diffusivity()(0) = relative_gas_diffusivity(0, 1.0); for (index_t node=1; nodeget_mesh()->nb_nodes(); ++node) { scalar_t phi = porosity(node); permeability(node) = intrinsic_permeability(phi); liq_diffusivity(node) = intrinsic_liquid_diffusivity(phi); gas_diffusivity(node) = resistance_gas_diffusivity(phi); //true_var->set_relative_variables(node); } } scalar_t UpscalingStagger::capillary_pressure(index_t node, scalar_t saturation) { if (saturation == 0.0) return 0.0; return laws::capillary_pressure_BaroghelBouny(saturation, m_a, m_b); } scalar_t UpscalingStagger::vapor_pressure(index_t node, scalar_t saturation) { scalar_t pv; if (saturation == 0.0) pv = 0.0; else if (saturation >= 1.0) pv = m_pv_sat; else pv = m_pv_sat*laws::invert_kelvin_equation( capillary_pressure(node, saturation)); return pv; } scalar_t UpscalingStagger::relative_liquid_diffusivity( index_t node, scalar_t saturation ) { if (saturation == 0.0) return 0.0; return std::pow(saturation, m_exp_r_l_d); } scalar_t UpscalingStagger::relative_liquid_permeability( index_t node, scalar_t saturation ) { if (saturation == 0.0) return 0.0; return laws::relative_liquid_permeability_Mualem(saturation, 1.0/m_b); } scalar_t UpscalingStagger::relative_gas_diffusivity(index_t node, scalar_t saturation) { if (saturation == 0.0) return 1.0; return std::pow(1.0 - saturation, m_exp_r_g_d); } scalar_t UpscalingStagger::intrinsic_permeability(scalar_t porosity) { scalar_t tmp_1 = porosity / m_phi_0; scalar_t tmp_2 = (1.0 - m_phi_0) / (1.0 - porosity); tmp_1 = std::pow(tmp_1, 3); tmp_2 = std::pow(tmp_2, 2); return m_k_0 * tmp_1 * tmp_2; } scalar_t UpscalingStagger::intrinsic_liquid_diffusivity(scalar_t porosity) { return m_d_0 * std::exp(-9.95*porosity); } scalar_t UpscalingStagger::resistance_gas_diffusivity(scalar_t porosity) { return std::pow(porosity, m_exp_i_g_d); } void UpscalingStagger::initialize_timestep( scalar_t dt, VariablesBase * const var ) { } StaggerReturnCode UpscalingStagger::restart_timestep(VariablesBase * const var) { UnsaturatedVariables* true_var = static_cast(var); SecondaryTransientVariable& porosity = true_var->get_porosity(); SecondaryVariable& permeability = true_var->get_liquid_permeability(); SecondaryVariable& liq_diffusivity = true_var->get_liquid_diffusivity(); SecondaryVariable& gas_diffusivity = true_var->get_resistance_gas_diffusivity(); for (index_t node=1; nodeget_mesh()->nb_nodes(); ++node) { scalar_t phi = porosity(node); permeability(node) = intrinsic_permeability(phi); liq_diffusivity(node) = intrinsic_liquid_diffusivity(phi); gas_diffusivity(node) = resistance_gas_diffusivity(phi); true_var->set_relative_variables(node); } return StaggerReturnCode::ResidualMinimized; } specmicp::RawDatabasePtr get_database() { specmicp::database::Database thedatabase(CEMDATA_PATH); std::map swap = {{"HCO3[-]", "CO2"},}; thedatabase.swap_components(swap); database::RawDatabasePtr raw_data = thedatabase.get_database(); return raw_data; } AdimensionalSystemSolution get_initial_condition( database::RawDatabasePtr the_database, const units::UnitsSet& units_set ) { Formulation initial_formulation; scalar_t scaling = 0.9e-3; initial_formulation.set_mass_solution(0.6*scaling); initial_formulation.add_mineral("C3S", 5.5*scaling); initial_formulation.add_mineral("C2S", 1.25*scaling); initial_formulation.add_mineral("Calcite", 0.05*scaling); Dissolver dissolver(the_database); UpscalingStagger upsstag_init; // just for vapor pressure model AdimensionalSystemConstraints constraints; constraints.set_total_concentrations( dissolver.dissolve(initial_formulation, true) ); //constraints.set_inert_volume_fraction(0.1); AdimensionalSystemSolver the_solver(the_database, constraints); the_solver.get_options().units_set = units_set; the_solver.get_options().system_options.non_ideality_tolerance = 1e-12; micpsolver::MiCPSolverOptions* solver_options = &the_solver.get_options().solver_options; //solver_options.maxstep = 10.0; solver_options->maxiter_maxstep = 200; solver_options->set_tolerance(1e-9); Vector x; the_solver.initialise_variables(x, 0.8, -4); micpsolver::MiCPPerformance perf = the_solver.solve(x); if (perf.return_code < micpsolver::MiCPSolverReturnCode::Success) { throw std::runtime_error("Error : failed to solve initial conditions"); } constraints.set_water_partial_pressure_model( std::bind(&UpscalingStagger::vapor_pressure, &upsstag_init, 1, std::placeholders::_1) ); the_solver = AdimensionalSystemSolver (the_database, constraints); the_solver.get_options().units_set = units_set; the_solver.get_options().system_options.non_ideality_tolerance = 1e-12; solver_options = &the_solver.get_options().solver_options; //solver_options.maxstep = 10.0; solver_options->maxiter_maxstep = 200; solver_options->set_tolerance(1e-9); perf = the_solver.solve(x); if (perf.return_code < micpsolver::MiCPSolverReturnCode::Success) { throw std::runtime_error("Error : failed to solve initial conditions"); } return the_solver.get_raw_solution(x); } diff --git a/examples/reactmicp/unsaturated/drying.cpp b/examples/reactmicp/unsaturated/drying.cpp index f31766a..37dde57 100644 --- a/examples/reactmicp/unsaturated/drying.cpp +++ b/examples/reactmicp/unsaturated/drying.cpp @@ -1,578 +1,580 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ // ====================================================== // // // // Drying example // // ============== // // // // ====================================================== // // // // This is a simple example to show how the unsaturated // system of ReactMiCP is able to solve a complex drying // equation. // // It implements a special chemistry stagger (DryingStagger) // which only computes the vapor pressure. // Macro to define the problem // =========================== #define NB_NODES 50 #define DX 0.05*1e-2 // cm #define CROSS_SECTION 5.0*1e-4 // cm^2 #define GAMMA_WATER_GLASS 0.1 // N/m #define GAMMA_WATER_AIR 71.97e-3 // N/m = kg/s^2 #define R_SMALL_BEAD 0.015*1e-2 // cm #define R_BIG_BEAD 0.04*1e-2 // cm #define M_v 18.015e-3 // kg/mol // Includes // ======== #include "database/database.hpp" #include "reactmicp/systems/unsaturated/variables.hpp" #include "reactmicp/systems/unsaturated/variables_sub.hpp" #include "reactmicp/systems/unsaturated/transport_stagger.hpp" #include "reactmicp/systems/unsaturated/transport_constraints.hpp" #include "reactmicp/solver/staggers_base/chemistry_stagger_base.hpp" #include "reactmicp/solver/staggers_base/upscaling_stagger_base.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #include "reactmicp/solver/runner.hpp" #include "dfpm/meshes/generic_mesh1d.hpp" #include "physics/laws.hpp" #include "physics/units.hpp" #include "utils/log.hpp" #include "utils/io/csv_formatter.hpp" #include #include // Namespace // ========= using namespace specmicp; using namespace specmicp::reactmicp; using namespace specmicp::reactmicp::systems; using namespace specmicp::reactmicp::systems::unsaturated; // Declarations // ============ // Constants // ========== static const scalar_t rho_l_si = constants::water_density_25; static const scalar_t rho_l = 1e-6*constants::water_density_25; static const scalar_t cw_tilde_si = rho_l_si / M_v; static const scalar_t cw_tilde = 1e-6*cw_tilde_si; int main(); database::RawDatabasePtr get_database(); mesh::Mesh1DPtr get_mesh(); scalar_t leverett_function(scalar_t s_eff); scalar_t big_bead_cap_pressure(scalar_t saturation); scalar_t small_bead_cap_pressure(scalar_t saturation); scalar_t vapor_pressure(scalar_t pc); // Drying Stagger // ============== // // This stagger computes the exchange between water vapor and liquid water class DryingStagger: public solver::ChemistryStaggerBase { public: DryingStagger() {} virtual void initialize(solver::VariablesBase * const var) override {} //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables virtual void initialize_timestep( scalar_t dt, solver::VariablesBase * const var ) override { m_dt = dt; } //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables virtual solver::StaggerReturnCode restart_timestep( solver::VariablesBase * const var) override; void compute_one_node(index_t node, UnsaturatedVariables * const vars); private: scalar_t m_dt {-1.0}; }; // Upscaling Stagger // ================= // // Define how we compute capillary pressure, vapor pressure, ... class UpscalingDryingStagger: public solver::UpscalingStaggerBase { public: UpscalingDryingStagger(std::vector& is_big_bead): m_is_big_bead(is_big_bead) {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables virtual void initialize(solver::VariablesBase * const var) override; //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables virtual void initialize_timestep( scalar_t dt, solver::VariablesBase * const var ) override {} //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables virtual solver::StaggerReturnCode restart_timestep( solver::VariablesBase * const var) override { return solver::StaggerReturnCode::ResidualMinimized; } scalar_t capillary_pressure_model(index_t node, scalar_t saturation); scalar_t vapor_pressure_model(index_t node, scalar_t saturation); scalar_t relative_liquid_permeability_model(index_t node, scalar_t saturation); scalar_t relative_liquid_diffusivity_model(index_t node, scalar_t saturation); scalar_t relative_gas_diffusivity_model(index_t node, scalar_t saturation); private: std::vector m_is_big_bead; }; // Implementation // ============== scalar_t UpscalingDryingStagger::capillary_pressure_model(index_t node, scalar_t saturation) { scalar_t pc = 0.0; if (m_is_big_bead[node]) { pc = big_bead_cap_pressure(saturation); } else pc = small_bead_cap_pressure(saturation); return pc; } scalar_t UpscalingDryingStagger::vapor_pressure_model(index_t node, scalar_t saturation) { return vapor_pressure(capillary_pressure_model(node, saturation)); } scalar_t UpscalingDryingStagger::relative_liquid_permeability_model(index_t node, scalar_t saturation) { return std::pow(saturation, 3); } scalar_t UpscalingDryingStagger::relative_liquid_diffusivity_model(index_t node, scalar_t saturation) { return saturation; } scalar_t UpscalingDryingStagger::relative_gas_diffusivity_model(index_t node, scalar_t saturation) { return (1.0 - saturation); } void UpscalingDryingStagger::initialize(solver::VariablesBase * const var) { UnsaturatedVariables * const true_vars = static_cast(var); true_vars->set_capillary_pressure_model( [this](index_t node, scalar_t sat) -> scalar_t { return this->capillary_pressure_model(node, sat);}); true_vars->set_vapor_pressure_model(std::bind(std::mem_fn( &UpscalingDryingStagger::vapor_pressure_model ), this, std::placeholders::_1, std::placeholders::_2)); true_vars->set_relative_liquid_permeability_model(std::bind(std::mem_fn( &UpscalingDryingStagger::relative_liquid_permeability_model ), this, std::placeholders::_1, std::placeholders::_2)); true_vars->set_relative_liquid_diffusivity_model(std::bind(std::mem_fn( &UpscalingDryingStagger::relative_liquid_diffusivity_model ), this, std::placeholders::_1, std::placeholders::_2)); true_vars->set_relative_gas_diffusivity_model(std::bind(std::mem_fn( &UpscalingDryingStagger::relative_gas_diffusivity_model ), this, std::placeholders::_1, std::placeholders::_2)); MainVariable& vapor_pressure = true_vars->get_pressure_main_variables(0); MainVariable& saturation = true_vars->get_liquid_saturation(); SecondaryTransientVariable& porosity = true_vars->get_porosity(); SecondaryVariable& liquid_diffusivity = true_vars->get_liquid_diffusivity(); SecondaryVariable& liquid_permeability = true_vars->get_liquid_permeability(); SecondaryVariable& resistance_gas_diffusivity = true_vars->get_resistance_gas_diffusivity(); true_vars->get_binary_gas_diffusivity(0) = 0.282*1e-4; porosity(0) = 1; resistance_gas_diffusivity(0) = 1.0; for (index_t node=1; nodeget_mesh()->nb_nodes(); ++node) { vapor_pressure(node) = vapor_pressure_model(node, saturation(node)); if (m_is_big_bead[node]) { porosity(node) = 0.371; liquid_diffusivity(node) = 0; liquid_permeability(node) = 3.52e-11; resistance_gas_diffusivity(node) = 2*0.371/(3-0.371); } else { porosity(node) = 0.387; liquid_diffusivity(node) = 0; liquid_permeability(node) = 8.41e-12; resistance_gas_diffusivity(node) = 2*0.387/(3-0.387); } } porosity.predictor = porosity.variable; true_vars->set_relative_variables(); } solver::StaggerReturnCode DryingStagger::restart_timestep( solver::VariablesBase * const var) { UnsaturatedVariables * const true_vars = static_cast(var); for (index_t node=1; nodeget_mesh()->nb_nodes(); ++node) { compute_one_node(node, true_vars); } return solver::StaggerReturnCode::ResidualMinimized; } void DryingStagger::compute_one_node( index_t node, UnsaturatedVariables * const vars) { MainVariable& satvars = vars->get_liquid_saturation(); MainVariable& presvars = vars->get_pressure_main_variables(0); scalar_t rt = vars->get_rt(); scalar_t saturation = satvars(node); scalar_t pressure = presvars(node); scalar_t porosity = vars->get_porosity()(node); auto vapor_pressure_f = vars->get_vapor_pressure_model(); const scalar_t tot_conc = cw_tilde_si*saturation + (1.0-saturation)*pressure/rt; pressure = vapor_pressure_f(node, saturation); scalar_t cw_hat = pressure/rt; saturation = (tot_conc - cw_hat) / (cw_tilde_si-cw_hat); pressure = vapor_pressure_f(node, saturation); cw_hat = pressure/rt; scalar_t res = tot_conc - cw_tilde_si*saturation - (1.0-saturation)*cw_hat; while (std::abs(res)/tot_conc > 1e-12) { saturation = (tot_conc - cw_hat) / (cw_tilde_si-cw_hat); pressure = vapor_pressure_f(node, saturation); cw_hat = pressure/rt; res = tot_conc - cw_tilde_si*saturation - (1.0-saturation)*cw_hat; } satvars(node) = saturation; satvars.velocity(node) = (saturation - satvars.predictor(node))/m_dt; presvars(node) = pressure; presvars.velocity(node) = (pressure - presvars.predictor(node))/m_dt; presvars.chemistry_rate(node) = - porosity/(rt*m_dt) * ( (pressure*(1.0-saturation)) - (presvars.predictor(node)*(1.0-satvars.predictor(node))) ) + presvars.transport_fluxes(node); } database::RawDatabasePtr get_database() { specmicp::database::Database thedatabase(CEMDATA_PATH); std::vector to_keep = {"H2O", "H[+]"}; thedatabase.keep_only_components(to_keep); thedatabase.remove_gas_phases(); database::RawDatabasePtr raw_data = thedatabase.get_database(); raw_data->freeze_db(); return raw_data; } mesh::Mesh1DPtr get_mesh() { mesh::Uniform1DMeshGeometry geom; geom.dx = DX; geom.nb_nodes = NB_NODES; geom.section = CROSS_SECTION; return mesh::uniform_mesh1d(geom); } scalar_t big_bead_cap_pressure(scalar_t saturation) { return GAMMA_WATER_AIR/std::sqrt(3.52e-11/0.371)*leverett_function(saturation); } scalar_t small_bead_cap_pressure(scalar_t saturation) { return GAMMA_WATER_AIR/std::sqrt(8.41e-12/0.387)*leverett_function(saturation); } scalar_t vapor_pressure(scalar_t pc) { return 3e3*std::exp(-M_v * pc / (rho_l_si * (8.314*(25+273.15)))); } scalar_t leverett_function(scalar_t s_eff) { return 0.325*std::pow((1.0/s_eff - 1), 0.217); } class Printer { public: Printer(UnsaturatedVariables* vars, std::size_t reserve_size); void register_timestep(scalar_t time, solver::VariablesBasePtr base_vars); void print(const std::string& name); private: mesh::Mesh1DPtr m_mesh; std::vector> m_pressure; std::vector> m_saturation; std::vector m_timestep; }; Printer::Printer(UnsaturatedVariables *vars, std::size_t reserve_size): m_mesh(vars->get_mesh()), m_pressure(m_mesh->nb_nodes()), m_saturation(m_mesh->nb_nodes()) { m_timestep.reserve(reserve_size); for (auto node: m_mesh->range_nodes()) { m_pressure[node].reserve(reserve_size); m_saturation[node].reserve(reserve_size); } } void Printer::register_timestep(scalar_t time, solver::VariablesBasePtr base_vars) { UnsaturatedVariables* vars = static_cast(base_vars.get()); m_timestep.push_back(time); MainVariable& saturation = vars->get_liquid_saturation(); MainVariable& pressure = vars->get_pressure_main_variables(0); for (auto node: m_mesh->range_nodes()) { m_pressure[node].push_back(pressure(node)); m_saturation[node].push_back(saturation(node)); } } void Printer::print(const std::string& name) { io::CSVFile pressure_file(name+"_pressure.dat"); io::CSVFile saturation_file(name+"_saturation.dat"); pressure_file << "Node"; saturation_file << "Node"; for (auto& time: m_timestep) { pressure_file.separator(); pressure_file << time; saturation_file.separator(); saturation_file << time; } pressure_file.eol(); saturation_file.eol(); for (auto node: m_mesh->range_nodes()) { pressure_file << m_mesh->get_position(node); saturation_file << m_mesh->get_position(node); for (std::size_t ind=0; ind has_gas = {true, false, false}; std::vector is_big_bead(the_mesh->nb_nodes(), true); //for (int node=25; node( the_mesh, raw_data, has_gas, units::LengthUnit::meter); TransportConstraints constraints; constraints.add_fixed_node(0); constraints.add_gas_node(0); // variables initialisation MainVariable& saturation = vars->get_liquid_saturation(); MainVariable& vapor_pressure = vars->get_pressure_main_variables(0); SecondaryTransientVariable& water_aqueous_concentration = vars->get_water_aqueous_concentration(); water_aqueous_concentration.predictor = water_aqueous_concentration.variable; SecondaryVariable& rel_gas_d = vars->get_relative_gas_diffusivity(); rel_gas_d(0) = 1.0; vapor_pressure(0) = 100; for (index_t node = 1; node < the_mesh->nb_nodes(); ++node) { saturation(node) = 0.9; } water_aqueous_concentration.set_constant(cw_tilde_si); std::shared_ptr upscaling_stagger = std::make_shared(is_big_bead); upscaling_stagger->initialize(vars.get()); std::shared_ptr drying_stagger = std::make_shared(); // init vapor pressure drying_stagger->initialize_timestep(1.0, vars.get()); drying_stagger->restart_timestep(vars.get()); std::shared_ptr transport_stagger = std::make_shared(vars, constraints); solver::ReactiveTransportSolver react_solver(transport_stagger, drying_stagger, upscaling_stagger); solver::ReactiveTransportOptions& opts = react_solver.get_options(); opts.residuals_tolerance = 1e-2; opts.good_enough_tolerance = 0.99; vapor_pressure.chemistry_rate.setZero(); //for (auto it=0; it<100; ++it) //{ // auto retcode = react_solver.solve_timestep(0.1, vars); // std::cout << (int) retcode << std::endl; //} //std::cout << saturation.variable << std::endl; //std::cout << vapor_pressure.variable << std::endl; //std::cout << vars->get_gas_diffusivity().variable << std::endl; //std::cout << vars->get_relative_gas_diffusivity().variable << std::endl; int nb_hours = 9; Printer printer(vars.get(), 4*nb_hours); solver::SimulationInformation simul_info("drying", 900); solver::ReactiveTransportRunner runner(react_solver, 0.01, 10, simul_info); solver::output_f out_func = std::bind(&Printer::register_timestep, &printer, std::placeholders::_1, std::placeholders::_2); runner.set_output_policy(out_func); runner.run_until(nb_hours*3600, vars); printer.print("out_drying"); std::cout << saturation.variable << std::endl; std::cout << vapor_pressure.variable << std::endl; } diff --git a/examples/specmicp/adimensional/carbofe.cpp b/examples/specmicp/adimensional/carbofe.cpp index 56b6bff..21ba400 100644 --- a/examples/specmicp/adimensional/carbofe.cpp +++ b/examples/specmicp/adimensional/carbofe.cpp @@ -1,190 +1,223 @@ +/* ============================================================================= + + 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 "specmicp.hpp" #include "utils/timer.hpp" #include class AutomaticReactionPath: public specmicp::EquilibriumCurve { public: AutomaticReactionPath() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, {"Fe[2+]", "Fe(OH)4[-]"}, }); thedatabase.swap_components(swapping); thedatabase.remove_half_cell_reactions(std::vector({"SO4[2-]"})); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); set_database(raw_data); specmicp::Formulation formulation; specmicp::scalar_t mult = 6e3; specmicp::scalar_t m_c3s = mult*0.6; specmicp::scalar_t m_c2s = mult*0.2; specmicp::scalar_t m_c3a = mult*0.10; specmicp::scalar_t m_c4af = mult*0.05; specmicp::scalar_t m_gypsum = mult*0.05; specmicp::scalar_t wc = 0.8; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_c4af*(4*56.08+101.96+159.07) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"C4AF", m_c4af}, {"Gypsum", m_gypsum} }; formulation.extra_components_to_keep = {"HCO3[-]", }; formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "C3AH6", "C4AH13", "C2AH8", "CAH10", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", //"Straetlingite", "Gypsum", "Ettringite", "Thaumasite", "C3FH6", "C4FH13", "C2FH8", "Fe(OH)3(mic)", "Fe-Ettringite", "Fe-Monosulfate", "Fe-Monocarbonate", "Fe-Hemicarbonate" }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); id_h2o = thedatabase.component_label_to_id("H2O"); id_ho = thedatabase.component_label_to_id("HO[-]"); id_hco3 = thedatabase.component_label_to_id("HCO3[-]"); id_co2g = thedatabase.gas_label_to_id("CO2(g)"); id_ca = thedatabase.component_label_to_id("Ca[2+]"); constraints() = specmicp::AdimensionalSystemConstraints(total_concentrations); constraints().charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions& options = solver_options(); options.solver_options.maxstep = 50.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.non_monotone_linesearch = true; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 300; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-10; options.solver_options.steptol = 1e-16; options.system_options.non_ideality_tolerance = 1e-14; options.system_options.scaling_electron = 1e10; specmicp::Vector x; specmicp::AdimensionalSystemSolver solver(raw_data, constraints(), solver_options()); solver.initialise_variables(x, 0.5, { {"Ca[2+]", -2.0}, {"HO[-]", -1.4}, {"Al(OH)4[-]", -4}, {"Fe(OH)4[-]", -4}, {"SiO(OH)3[-]", -6.0}, {"SO4[2-]", -6.2} }); specmicp::micpsolver::MiCPPerformance perf = solver.solve(x); if (perf.return_code <= specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet) { error_handling("Failed to solve first problem, return code : " + std::to_string((int) perf.return_code) + "."); } solution_vector() = x; initialize_solution(solver.get_raw_solution(x)); // std::cout << x << std::endl; // std::cout << current_solution().secondary_molalities << std::endl; std::cout << "Buffering \t" << "porosity \t pH \t Eh"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->minerals.get_label(mineral); } std::cout << std::endl; output(); } void output() { specmicp::AdimensionalSystemSolutionExtractor sol(current_solution(), database(), solver_options().units_set); std::cout << constraints().total_concentrations(id_hco3)/constraints().total_concentrations(id_ca) << "\t" << sol.porosity() << "\t" << sol.pH() << "\t" << sol.Eh(); for (specmicp::index_t mineral: database()->range_mineral()) { std::cout << "\t" << sol.volume_fraction_mineral(mineral); } std::cout << std::endl; } void update_problem() { constraints().total_concentrations(id_hco3) += 100; constraints().total_concentrations(id_ho) -= 100; constraints().total_concentrations(id_h2o) += 100; } private: specmicp::index_t id_h2o; specmicp::index_t id_ho; specmicp::index_t id_hco3; specmicp::index_t id_co2g; specmicp::index_t id_ca; }; int main() { specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; specmicp::Timer timer; AutomaticReactionPath test_automatic; for (int i=0; i<180; ++i) { test_automatic.run_step(); } timer.stop(); std::cout << "Execution time : " << timer.elapsed_time() << "s" << std::endl; return EXIT_SUCCESS; } diff --git a/examples/specmicp/adimensional/equilibrium_curve.cpp b/examples/specmicp/adimensional/equilibrium_curve.cpp index 440bb00..092b433 100644 --- a/examples/specmicp/adimensional/equilibrium_curve.cpp +++ b/examples/specmicp/adimensional/equilibrium_curve.cpp @@ -1,141 +1,174 @@ +/* ============================================================================= + + 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 #include "utils/log.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "database/database.hpp" class LeachingEquilibriumCurve: public specmicp::EquilibriumCurve { public: specmicp::scalar_t step = 25; LeachingEquilibriumCurve() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, }); thedatabase.swap_components(swapping); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); set_database(raw_data); specmicp::Formulation formulation; specmicp::scalar_t mult = 7e3; specmicp::scalar_t m_c3s = mult*0.7; specmicp::scalar_t m_c2s = mult*0.3; specmicp::scalar_t wc = 0.5; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); id_h2o = thedatabase.component_label_to_id("H2O"); id_ho = thedatabase.component_label_to_id("HO[-]"); id_ca = thedatabase.component_label_to_id("Ca[2+]"); constraints() = specmicp::AdimensionalSystemConstraints(total_concentrations); constraints().charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions& options = solver_options(); options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-6; options.solver_options.steptol = 1e-14; options.system_options.non_ideality_tolerance = 1e-10; solve_first_problem(); std::cout << "total concentration \t TOTaq \t TOTs \t S^t_m \t pH"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->get_label_mineral(mineral); } std::cout << std::endl; specmicp::AdimensionalSystemSolutionExtractor sol(current_solution(), database(), solver_options().units_set); specmicp::scalar_t tot_conc_ca = constraints().total_concentrations(id_ca); total_steps = std::ceil(tot_conc_ca / step) + 1; cnt = 0; solution = specmicp::Matrix::Zero(total_steps, 2); output(); } void output() { specmicp::AdimensionalSystemSolutionExtractor sol(current_solution(), database(), solver_options().units_set); std::cout << constraints().total_concentrations(id_ca) << "\t" << sol.total_aqueous_concentration(id_ca) << "\t" << sol.total_solid_concentration(id_ca) << "\t" << sol.total_saturation_minerals() << "\t" << sol.pH(); for (specmicp::index_t mineral: database()->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; solution(cnt, 0) = sol.total_solid_concentration(id_ca); solution(cnt, 1) = sol.total_aqueous_concentration(id_ca); ++cnt; } specmicp::index_t nb_steps() const { return total_steps; } void update_problem() { constraints().total_concentrations(id_ca) -= step; constraints().total_concentrations(id_ho) += 2*step; } specmicp::Matrix& equilibrium_curve() {return solution;} private: mutable specmicp::index_t cnt; specmicp::index_t total_steps; mutable specmicp::Matrix solution; specmicp::index_t id_h2o; specmicp::index_t id_ho; specmicp::index_t id_ca; }; int main() { LeachingEquilibriumCurve solver; for (int i=1; i 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 #include "utils/log.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional_kinetics/kinetic_variables.hpp" #include "specmicp/adimensional_kinetics/kinetic_model.hpp" #include "specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp" #include "specmicp/adimensional_kinetics/kinetic_system_solver.hpp" #include "database/database.hpp" #include "database/aqueous_selector.hpp" specmicp::RawDatabasePtr get_momas_db() { specmicp::database::Database thedatabase("../data/momas_benchmark.yaml"); thedatabase.remove_components({"X5",}); specmicp::database::AqueousSelector selector(thedatabase.get_database()); selector.remove_aqueous({selector.aqueous_label_to_id("C6"), selector.aqueous_label_to_id("C7")}); thedatabase.save("out_momas.db"); return thedatabase.get_database(); } class AutomaticReactionPath: public specmicp::EquilibriumCurve { public: AutomaticReactionPath() { specmicp::RawDatabasePtr raw_data = get_momas_db(); set_database(raw_data); specmicp::Vector total_concentrations(raw_data->nb_component()); total_concentrations << 1, 0.0, -3.0, 0.0, 1.0; constraints() = specmicp::AdimensionalSystemConstraints(total_concentrations); constraints().disable_conservation_water(); constraints().surface_model.model_type = specmicp::SurfaceEquationType::Equilibrium; constraints().surface_model.concentration = 1.0; specmicp::AdimensionalSystemSolverOptions& options = solver_options(); options.solver_options.maxstep = 1.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.non_monotone_linesearch = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-6; options.solver_options.steptol = 1e-14; options.system_options.non_ideality_tolerance = 1e-8; options.system_options.non_ideality = false; options.use_pcfm = true; //solve_first_problem(); specmicp::Vector variables; specmicp::AdimensionalSystemSolver solver(raw_data, constraints(), solver_options()); solver.initialise_variables(variables, 0.8, {{"X2", -3}, {"X4", -11}}, {}, 0.5 ); solver.run_pcfm(variables); specmicp::micpsolver::MiCPPerformance current_perf = solver.solve(variables, false); std::cout << (int) current_perf.return_code << std::endl; solution_vector() = variables; initialize_solution(solver.get_raw_solution(variables)); std::cout << variables << std::endl; std::cout << "Buffering \t"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->get_label_mineral(mineral); } std::cout << "\t S"; for (specmicp::index_t sorbed: raw_data->range_sorbed()) { std::cout << "\t" << raw_data->get_label_sorbed(sorbed); } std::cout << std::endl; output(); } void output() { specmicp::AdimensionalSystemSolutionExtractor sol(current_solution(), database(), solver_options().units_set); std::cout << constraints().total_concentrations(1); for (specmicp::index_t mineral: database()->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << "\t" << sol.free_surface_concentration(); for (specmicp::index_t sorbed: database()->range_sorbed()) { std::cout << "\t" << sol.molality_sorbed_species(sorbed); } std::cout << std::endl; } void update_problem() { constraints().total_concentrations(1) += 0.1; constraints().total_concentrations(2) += 0.1; constraints().total_concentrations(3) += 0.1; } private: specmicp::index_t id_h2o; specmicp::index_t id_ho; specmicp::index_t id_hco3; specmicp::index_t id_co2g; specmicp::index_t id_ca; }; class MomasKinetics: public specmicp::kinetics::AdimKineticModel { public: MomasKinetics(): specmicp::kinetics::AdimKineticModel({0}), m_id_cc(0), m_id_c3(2), m_id_x4(4) {} //! \brief Compute the kinetic rates and store them in dydt void compute_rate( specmicp::scalar_t t, const specmicp::Vector& y, specmicp::kinetics::AdimKineticVariables& variables, specmicp::Vector& dydt ) { dydt.resizeLike(y); specmicp::AdimensionalSystemSolution& solution = variables.equilibrium_solution(); specmicp::scalar_t factor = std::pow(1e3*0.5*solution.secondary_molalities(m_id_c3),3)/ std::pow(1e3*0.5*pow10(solution.main_variables(m_id_x4)), 2); factor = 0.2*factor-1.0; specmicp::scalar_t k_constant = 10.0; if (factor >= 0) k_constant = 1e-2; dydt(0) = k_constant*factor; } private: specmicp::index_t m_id_cc; specmicp::index_t m_id_c3; specmicp::index_t m_id_x4; }; void solve_kinetics_problem() { specmicp::RawDatabasePtr raw_data = get_momas_db(); specmicp::Vector total_concentrations(6); total_concentrations << 1, 0.6, -2.4, 0.6, 1.0, 1.0; specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.disable_conservation_water(); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.non_monotone_linesearch = true; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 50; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-8; options.solver_options.steptol = 1e-10; options.system_options.non_ideality_tolerance = 1e-10; options.system_options.non_ideality = false; specmicp::Vector equil_variables; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(equil_variables, 0.8, -3); specmicp::micpsolver::MiCPPerformance current_perf = solver.solve(equil_variables, false); std::cout << (int) current_perf.return_code << std::endl; specmicp::AdimensionalSystemSolution equil_solution = solver.get_raw_solution(equil_variables); std::shared_ptr model = std::make_shared(); specmicp::Vector mineral_concentrations(1); mineral_concentrations << 5.0; specmicp::kinetics::AdimKineticSystemEulerSolver kinetic_solver( //specmicp::kinetics::AdimKineticSystemSolver kinetic_solver( model, total_concentrations, mineral_concentrations, constraints, equil_solution, raw_data); options.solver_options.use_scaling = false; kinetic_solver.get_options().speciation_options = options; kinetic_solver.solve(0.005, 1.0); std::cout << "Final amount : " << kinetic_solver.variables().concentration_mineral(0) << std::endl; } int main() { specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Debug; // solve_kinetics_problem(); AutomaticReactionPath test_automatic; for (int i=0; i<20; ++i) { test_automatic.run_step(); } return EXIT_SUCCESS; } diff --git a/examples/specmicp/adimensional/thermocarbo.cpp b/examples/specmicp/adimensional/thermocarbo.cpp index e828b73..c2f744f 100644 --- a/examples/specmicp/adimensional/thermocarbo.cpp +++ b/examples/specmicp/adimensional/thermocarbo.cpp @@ -1,437 +1,470 @@ +/* ============================================================================= + + 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 #include "utils/log.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "database/database.hpp" void fixed_fugacity_thermocarbo() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, }); thedatabase.swap_components(swapping); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); specmicp::Formulation formulation; specmicp::scalar_t mult = 5e3; specmicp::scalar_t m_c3s = mult*0.6; specmicp::scalar_t m_c2s = mult*0.2; specmicp::scalar_t m_c3a = mult*0.10; specmicp::scalar_t m_gypsum = mult*0.10; specmicp::scalar_t wc = 0.8; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; formulation.extra_components_to_keep = {"HCO3[-]", }; formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", "Straetlingite", "Gypsum", "Ettringite", "Thaumasite" }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); //specmicp::index_t id_h2o = thedatabase.component_label_to_id("H2O"); specmicp::index_t id_ho = thedatabase.component_label_to_id("HO[-]"); specmicp::index_t id_hco3 = thedatabase.component_label_to_id("HCO3[-]"); specmicp::index_t id_co2g = thedatabase.gas_label_to_id("CO2(g)"); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = id_ho; constraints.add_fixed_fugacity_gas(id_co2g, id_hco3, -14); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 50.0; options.solver_options.max_iter = 50; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-6; options.solver_options.fvectol = 1e-8; options.solver_options.steptol = 1e-10; options.solver_options.non_monotone_linesearch = false; options.system_options.non_ideality_tolerance = 1e-14; specmicp::Vector x(raw_data->nb_component()+raw_data->nb_mineral()); x.setZero(); x(0) = 0.5; x.segment(2, raw_data->nb_component()).setConstant(-6.0); for (specmicp::index_t i: raw_data->range_component()) { std::cout << raw_data->components.get_label(i) << std::endl; } specmicp::uindex_t tot_iter = 0; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet); //std::cout << perf.nb_iterations << std::endl; tot_iter += perf.nb_iterations; std::cout << "log fugacity" << "\t" << "pH"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->minerals.get_label(mineral); } std::cout << std::endl; specmicp::AdimensionalSystemSolution solution = solver.get_raw_solution(x); specmicp::AdimensionalSystemSolutionExtractor sol(solution, raw_data, options.units_set); std::cout << -14 << "\t" << sol.pH(); for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; for (double logf=-13.9; logf<-4.1; logf+=0.05) { constraints.fixed_fugacity_cs[0].log_value = logf; solver = specmicp::AdimensionalSystemSolver (raw_data, constraints, solution, options); //std::cout << solver.get_options().solver_options.factor_descent_condition << std::endl; specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet); std::cout << perf.nb_iterations << std::endl; tot_iter += perf.nb_iterations; solution = solver.get_raw_solution(x); specmicp::AdimensionalSystemSolutionExtractor sol(solution, raw_data, options.units_set); std::cout << logf << "\t" << sol.pH(); for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; //specmicp::AdimensionalSystemSolution solution = solver.get_raw_solution(x); //std::cout << solution.main_variables(0) << std::endl; //std::cout << 14+solution.main_variables(1) << std::endl; } std::cout << tot_iter << std::endl; } void reaction_path_thermocarbo() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, }); thedatabase.swap_components(swapping); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); specmicp::Formulation formulation; specmicp::scalar_t mult = 5e3; specmicp::scalar_t m_c3s = mult*0.6; specmicp::scalar_t m_c2s = mult*0.2; specmicp::scalar_t m_c3a = mult*0.10; specmicp::scalar_t m_gypsum = mult*0.10; specmicp::scalar_t wc = 0.8; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; formulation.extra_components_to_keep = {"HCO3[-]", }; formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", "Straetlingite", "Gypsum", "Ettringite", "Thaumasite" }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::index_t id_h2o = thedatabase.component_label_to_id("H2O"); specmicp::index_t id_ho = thedatabase.component_label_to_id("HO[-]"); specmicp::index_t id_hco3 = thedatabase.component_label_to_id("HCO3[-]"); //specmicp::index_t id_co2g = thedatabase.gas_label_to_id("CO2(g)"); specmicp::index_t id_ca = thedatabase.component_label_to_id("Ca[2+]"); std::cout << total_concentrations << std::endl; specmicp::AdimensionalSystemConstraints constraints(total_concentrations); //constraints.charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-6; options.solver_options.steptol = 1e-14; options.system_options.non_ideality_tolerance = 1e-10; specmicp::Vector x(raw_data->nb_component()+raw_data->nb_mineral()); x.setZero(); x(0) = 0.8; x.segment(2, raw_data->nb_component()).setConstant(-6.0); for (specmicp::index_t i: raw_data->range_component()) { std::cout << raw_data->components.get_label(i) << std::endl; } specmicp::uindex_t tot_iter = 0; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet); //std::cout << perf.nb_iterations << std::endl; tot_iter += perf.nb_iterations; std::cout << "Buffering \t" << "pH"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->minerals.get_label(mineral); } std::cout << std::endl; specmicp::AdimensionalSystemSolution solution = solver.get_raw_solution(x); specmicp::AdimensionalSystemSolutionExtractor sol(solution, raw_data, options.units_set); std::cout << 0 << "\t" << sol.pH(); for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; for (double c_hco3=100; c_hco3<=constraints.total_concentrations(id_ca); c_hco3+=100) { constraints.total_concentrations(id_hco3) = c_hco3; constraints.total_concentrations(id_ho) -= 100; constraints.total_concentrations(id_h2o) += 100; solver = specmicp::AdimensionalSystemSolver (raw_data, constraints, solution, options); //std::cout << solver.get_options().solver_options.factor_descent_condition << std::endl; specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet); //std::cout << perf.nb_iterations << std::endl; tot_iter += perf.nb_iterations; solution = solver.get_raw_solution(x); specmicp::AdimensionalSystemSolutionExtractor sol(solution, raw_data, options.units_set); std::cout << c_hco3/constraints.total_concentrations(id_ca) << "\t" << sol.pH(); for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; //specmicp::AdimensionalSystemSolution solution = solver.get_raw_solution(x); //std::cout << solution.main_variables(0) << std::endl; //std::cout << 14+solution.main_variables(1) << std::endl; } std::cout << tot_iter << std::endl; } class AutomaticReactionPath: public specmicp::EquilibriumCurve { public: AutomaticReactionPath() { specmicp::database::Database thedatabase("../data/cemdata.yaml"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, }); thedatabase.swap_components(swapping); thedatabase.remove_gas_phases(); specmicp::RawDatabasePtr raw_data = thedatabase.get_database(); set_database(raw_data); specmicp::Formulation formulation; specmicp::scalar_t mult = 5e3; specmicp::scalar_t m_c3s = mult*0.6; specmicp::scalar_t m_c2s = mult*0.2; specmicp::scalar_t m_c3a = mult*0.10; specmicp::scalar_t m_gypsum = mult*0.10; specmicp::scalar_t wc = 0.8; specmicp::scalar_t m_water = wc*1e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; formulation.extra_components_to_keep = {"HCO3[-]", }; formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2(am)", "Calcite", "Al(OH)3(mic)", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", "Straetlingite", "Gypsum", "Ettringite", "Thaumasite" }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); id_h2o = thedatabase.component_label_to_id("H2O"); id_ho = thedatabase.component_label_to_id("HO[-]"); id_hco3 = thedatabase.component_label_to_id("HCO3[-]"); id_co2g = thedatabase.gas_label_to_id("CO2(g)"); id_ca = thedatabase.component_label_to_id("Ca[2+]"); constraints() = specmicp::AdimensionalSystemConstraints(total_concentrations); //constraints().charge_keeper = id_ho; specmicp::AdimensionalSystemSolverOptions& options = solver_options(); options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = false; options.solver_options.non_monotone_linesearch = false; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-8; options.solver_options.steptol = 1e-10; options.system_options.non_ideality_tolerance = 1e-10; solve_first_problem(); std::cout << "Buffering \t" << "pH"; for (specmicp::index_t mineral: raw_data->range_mineral()) { std::cout << "\t" << raw_data->minerals.get_label(mineral); } std::cout << std::endl; output(); } void output() { specmicp::AdimensionalSystemSolutionExtractor sol(current_solution(), database(), solver_options().units_set); std::cout << constraints().total_concentrations(id_hco3)/constraints().total_concentrations(id_ca) << "\t" << sol.pH(); for (specmicp::index_t mineral: database()->range_mineral()) { std::cout << "\t" << sol.mole_concentration_mineral(mineral); } std::cout << std::endl; } void update_problem() { constraints().total_concentrations(id_hco3) += 100; constraints().total_concentrations(id_ho) -= 100; constraints().total_concentrations(id_h2o) += 100; } private: specmicp::index_t id_h2o; specmicp::index_t id_ho; specmicp::index_t id_hco3; specmicp::index_t id_co2g; specmicp::index_t id_ca; }; int main() { specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; //fixed_fugacity_thermocarbo(); //reaction_path_thermocarbo(); AutomaticReactionPath test_automatic; for (int i=0; i<130; ++i) { test_automatic.run_step(); } return EXIT_SUCCESS; } diff --git a/src/bin/specmicp/specmicp.cpp b/src/bin/specmicp/specmicp.cpp index 97204b7..dc3aee2 100644 --- a/src/bin/specmicp/specmicp.cpp +++ b/src/bin/specmicp/specmicp.cpp @@ -1,219 +1,221 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "utils/io/yaml.hpp" #include "database.hpp" #include "database/database.hpp" #include "database/io/configuration.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/adimensional/adimensional_system_solution_saver.hpp" #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "specmicp/adimensional/adimensional_system_structs.hpp" #include "specmicp/io/configuration.hpp" #include "specmicp/io/print.hpp" #include "utils/log.hpp" #include #define SECTION_MAIN "__main__" #define SECTION_SPECIATION "speciation" #define SECTION_FORMULATION "formulation" #define SECTION_CONSTRAINTS "constraints" #define ATTRIBUTE_NAME "name" #define ATTRIBUTE_OUTPUT "output" #define ATTRIBUTE_OUTPUT_DB "output_db" namespace specmicp { void check_db(const std::string& filepath); void run_specmicp(const YAML::Node& configuration); void run_formulation( const YAML::Node& conf_formulation, const RawDatabasePtr& the_database, const AdimensionalSystemSolverOptions& the_options ); } const static char* header = "SpecMiCP: Speciation solver based on the complementarity condition\n" "(c) Copyright 2014-2015 fabien Georget \n"; const static char* description = R"plop( Usage: specmicp specmicp -C/--check-db Options : the configuration file -c , --check-db check that the database can be parsed without error -h, --help produce this help )plop"; const static char* error_print_help = "Use -h to print help"; int main( int argc, const char* argv[]) { specmicp::init_logger(&std::cerr, specmicp::logger::Warning); if (argc < 2) { std::cerr << "Error: expecting one argument. "; std::cerr << error_print_help << std::endl; return EXIT_FAILURE; } std::cout << header << std::endl; const std::string first_arg = argv[1]; if (first_arg[0] == '-') { if (first_arg == "-h" or first_arg == "--help") { std::cout << description << std::endl; return EXIT_SUCCESS; } else if (first_arg == "-C" or first_arg == "--check-db") { if (argc < 3) { std::cerr << "Error : " << first_arg << " option requires an extra argument" << std::endl; return EXIT_FAILURE; } else { specmicp::check_db(argv[2]); return EXIT_SUCCESS; } } } const std::string conf_file = first_arg; YAML::Node configurations = specmicp::io::parse_yaml_file(conf_file); specmicp::run_specmicp(configurations); return EXIT_SUCCESS; } namespace specmicp { void run_specmicp(const YAML::Node& configuration) { RawDatabasePtr the_database = io::configure_database(configuration); AdimensionalSystemSolverOptions the_options; io::configure_specmicp_options(the_options, configuration); io::check_mandatory_yaml_node(configuration, SECTION_SPECIATION, SECTION_MAIN); const YAML::Node& conf_formulation = configuration[SECTION_SPECIATION]; if (conf_formulation.IsSequence()) { for (auto node: conf_formulation) { run_formulation(node, the_database, the_options); } } else { run_formulation(conf_formulation, the_database, the_options); } } void run_formulation( const YAML::Node& conf_formulation, const RawDatabasePtr& the_database, const AdimensionalSystemSolverOptions& the_options ) { const std::string name = io::get_yaml_mandatory(conf_formulation, ATTRIBUTE_NAME, SECTION_MAIN); Formulation formulation; io::check_mandatory_yaml_node(conf_formulation, SECTION_FORMULATION, name); io::configure_specmicp_formulation(formulation, conf_formulation[SECTION_FORMULATION], the_database, the_options.units_set); AdimensionalSystemConstraints constraints; io::check_mandatory_yaml_node(conf_formulation, SECTION_CONSTRAINTS, name); io::configure_specmicp_constraints(constraints, conf_formulation[SECTION_CONSTRAINTS], the_database); if (constraints.charge_keeper != no_species) formulation.extra_components_to_keep.push_back( the_database->get_label_component(constraints.charge_keeper)); for (auto it: constraints.fixed_activity_cs) formulation.extra_components_to_keep.push_back(the_database->get_label_component(it.id_component)); for (auto it: constraints.fixed_molality_cs) formulation.extra_components_to_keep.push_back(the_database->get_label_component(it.id_component)); for (auto it: constraints.fixed_fugacity_cs) formulation.extra_components_to_keep.push_back(the_database->get_label_component(it.id_component)); constraints = AdimensionalSystemConstraints(); constraints.total_concentrations = Dissolver(the_database).dissolve(formulation, true); io::configure_specmicp_constraints(constraints, conf_formulation[SECTION_CONSTRAINTS], the_database); if (conf_formulation[ATTRIBUTE_OUTPUT_DB]) { database::Database(the_database).save(conf_formulation[ATTRIBUTE_OUTPUT_DB].as()); } AdimensionalSystemSolution solution = solve_equilibrium(the_database, constraints, the_options); if (conf_formulation[ATTRIBUTE_OUTPUT]) { AdimensionalSystemSolutionSaver(the_database).save_solution( conf_formulation[ATTRIBUTE_OUTPUT].as(), solution); } } void check_db(const std::string& filepath) { std::cout << "Checking database : " << filepath << "\n ------ \n"; database::Database the_database(filepath); if (not the_database.is_valid()) { throw std::invalid_argument("The database is not valid !"); } std::cout << "Database is valid !" << std::endl; } } //end namespace specmicp diff --git a/src/database.hpp b/src/database.hpp index 11ba0dd..a7d6dff 100644 --- a/src/database.hpp +++ b/src/database.hpp @@ -1,48 +1,50 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_HPP #define SPECMICP_DATABASE_HPP //! \file src/database.hpp //! \brief Define the type of the database container #ifndef SPECMICP_DATABASE_DATACONTAINER_HPP #include "database/data_container.hpp" #endif namespace specmicp { using RawDatabasePtr = database::RawDatabasePtr; } #endif // SPECMICP_DATABASE_HPP diff --git a/src/database/appender.cpp b/src/database/appender.cpp index 3672a00..f1f7b9c 100644 --- a/src/database/appender.cpp +++ b/src/database/appender.cpp @@ -1,116 +1,118 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "appender.hpp" #include "yaml_reader.hpp" #include "../utils/io/yaml.hpp" #include #include namespace specmicp { namespace database { void DataAppender::add_gas(const std::string& yaml_input, bool check_compo) { std::istringstream input(yaml_input); add_gas(input, check_compo); } void DataAppender::add_gas(std::istream& yaml_input, bool check_compo) { DataReaderYaml reader(data, check_compo); YAML::Node root = io::parse_yaml(yaml_input); GasList gas; reader.parse_gas(root, gas); gas.append_to(data->gas); } void DataAppender::add_minerals(const std::string& yaml_input, bool check_compo) { std::istringstream input(yaml_input); add_minerals(input, check_compo); } void DataAppender::add_minerals(std::istream& yaml_input, bool check_compo) { DataReaderYaml reader(data, check_compo); YAML::Node root = io::parse_yaml(yaml_input); MineralList minerals; MineralList minerals_kinetic; reader.parse_minerals(root, minerals, minerals_kinetic); minerals.append_to(data->minerals); minerals_kinetic.append_to(data->minerals_kinetic); } void DataAppender::add_sorbed(const std::string& yaml_input, bool check_compo) { std::istringstream input(yaml_input); add_sorbed(input, check_compo); } void DataAppender::add_sorbed(std::istream& yaml_input, bool check_compo) { DataReaderYaml reader(data, check_compo); YAML::Node root = io::parse_yaml(yaml_input); SorbedList sorbed; reader.parse_sorbed(root, sorbed); sorbed.append_to(data->sorbed); } void DataAppender::add_compounds(const std::string& yaml_input, bool check_compo) { std::istringstream input(yaml_input); add_compounds(input, check_compo); } void DataAppender::add_compounds(std::istream& yaml_input, bool check_compo) { DataReaderYaml reader(data, check_compo); YAML::Node root = io::parse_yaml(yaml_input); CompoundList compounds; reader.parse_compounds(root, compounds); compounds.append_to(data->compounds); } } // end namespace database } // end namespace specmicp diff --git a/src/database/appender.hpp b/src/database/appender.hpp index 8e3374d..3869dcd 100644 --- a/src/database/appender.hpp +++ b/src/database/appender.hpp @@ -1,79 +1,81 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_APPENDER_HPP #define SPECMICP_DATABASE_APPENDER_HPP //! \file appender.hpp //! \brief Add species to a list #include "module.hpp" namespace specmicp { namespace database { class DataAppender: public DatabaseModule { public: DataAppender(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Add gases to the database void add_gas(const std::string& yaml_input, bool check_compo=true); //! \brief Add gases to the database void add_gas(std::istream& yaml_input, bool check_compo=true); //! \brief Add solid phases to the database void add_minerals(const std::string& yaml_input, bool check_compo=true); //! \brief Add solid phases to the database void add_minerals(std::istream& yaml_input, bool check_compo=true); //! \brief Add sorbed species to the database void add_sorbed(const std::string& yaml_input, bool check_compo=true); //! \brief Add sorbed species to the database void add_sorbed(std::istream& yaml_input, bool check_compo=true); //! \brief Add compounds species to the database void add_compounds(const std::string& yaml_input, bool check_compo=true); //! \brief Add sorbed species to the database void add_compounds(std::istream& yaml_input, bool check_compo=true); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP diff --git a/src/database/aqueous_selector.cpp b/src/database/aqueous_selector.cpp index 90c14b1..1bf7dc3 100644 --- a/src/database/aqueous_selector.cpp +++ b/src/database/aqueous_selector.cpp @@ -1,64 +1,66 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "aqueous_selector.hpp" namespace specmicp { namespace database { //! \brief Remove some specific aqueous species void AqueousSelector::remove_aqueous(const std::vector& id_aqueous) { const index_t new_nb_aqueous = data->nb_aqueous() - id_aqueous.size(); index_t new_id = 0; for (index_t aqueous: data->range_aqueous()) { auto it = std::find(id_aqueous.cbegin(), id_aqueous.cend(), aqueous); if (it == id_aqueous.end()) // if we need to keep the species { if (*it == aqueous) { ++new_id; continue; // nothing to change } data->aqueous.move_erase(aqueous, new_id); ++new_id; } } specmicp_assert(new_id == new_nb_aqueous); data->aqueous.resize(new_nb_aqueous); data->aqueous.set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/aqueous_selector.hpp b/src/database/aqueous_selector.hpp index ae69ba0..563f689 100644 --- a/src/database/aqueous_selector.hpp +++ b/src/database/aqueous_selector.hpp @@ -1,67 +1,69 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP #define SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP //! \file aqueous_selector.hpp //! \brief Select aqueous in the database #include "module.hpp" namespace specmicp { namespace database { //! \class AqueousSelector //! \brief Select aqueous in the database //! //! Remove aqueous species from the database. //! This should not be used normally but may be necessary in //! artificial problem. (e.g. the MoMas benchmark) class SPECMICP_DLL_PUBLIC AqueousSelector: public DatabaseModule { public: AqueousSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Remove some specific aqueous species //! //! \param id_aqueous vector containing the if of the species to remove void remove_aqueous(const std::vector& id_aqueous); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP diff --git a/src/database/config_database.hpp b/src/database/config_database.hpp index 06a3516..95a3ac2 100644 --- a/src/database/config_database.hpp +++ b/src/database/config_database.hpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_CONFIG_DATABASE_HPP #define SPECMICP_DATABASE_CONFIG_DATABASE_HPP // This file is used at compilation time to configure basic features of the database // It should not be included in header files // they are advanced usage, and not offered as an option through CMAKE // This is precision used to test if two charges are the same when reading the database #ifndef EPS_TEST_CHARGE #define EPS_TEST_CHARGE 1e-5 #endif // EPS_TEST_CHARGE // This is the precision used to test if two compositions are the same when reading the database #ifndef EPS_TEST_COMPOSITION #define EPS_TEST_COMPOSITION EPS_TEST_CHARGE #endif // EPS_TEST_COMPOSITION // This is the label of water #ifndef LABEL_WATER #define LABEL_WATER "H2O" #endif // LABEL_WATER // This is the label of the electron #ifndef LABEL_ELECTRON #define LABEL_ELECTRON "E[-]" #endif // LABEL_ELECTRON #endif // SPECMICP_DATABASE_CONFIG_DATABASE_HPP diff --git a/src/database/data_container.cpp b/src/database/data_container.cpp index fb4871a..771ec9d 100644 --- a/src/database/data_container.cpp +++ b/src/database/data_container.cpp @@ -1,211 +1,213 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "data_container.hpp" #include "errors.hpp" #include "config_database.hpp" namespace std { template <> struct hash { size_t operator() (const specmicp::database::Metadata& meta_data) const { auto hasher = hash(); return hasher(meta_data.path)+hasher(meta_data.name)+hasher(meta_data.version); } }; } namespace specmicp { namespace database { const std::string water_label{LABEL_WATER}; //!< The water label in the database const std::string electron_label{LABEL_ELECTRON}; //!< The electron label in the database // Conversion factor // // conversion from g/mol to (mass_unit)/mol scalar_t SPECMICP_CONST_F scaling_factor_molar_mass(units::MassUnit mass_unit) { scalar_t factor = 1.0; if (mass_unit == units::MassUnit::kilogram) factor = 1e-3; return factor; } scalar_t DataContainer::molar_volume_mineral(index_t m, units::LengthUnit length_unit) const { const auto& molar_volume = minerals.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals.get_label(m)); } return scaling_molar_volume(length_unit)*molar_volume; } scalar_t DataContainer::molar_volume_mineral_kinetic(index_t m, units::LengthUnit length_unit) const { const auto& molar_volume = minerals_kinetic.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals_kinetic.get_label(m)); } return scaling_molar_volume(length_unit)*molar_volume; } scalar_t DataContainer::scaling_molar_volume(units::LengthUnit length_unit) const { scalar_t scaling = 1.0; if (length_unit == units::LengthUnit::meter) scaling = 1e-6; else if (length_unit == units::LengthUnit::decimeter) scaling = 1e-3; return scaling; } //! \brief Return the molar volume (m^3/mol) of a mineral scalar_t DataContainer::molar_volume_mineral(index_t m) const { const auto& molar_volume = minerals.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals.get_label(m)); } return 1e-6*molar_volume; } //! \brief Return the molar volume (m^3/mol) of a mineral governed by kinetic scalar_t DataContainer::molar_volume_mineral_kinetic(index_t m) const { const auto& molar_volume = minerals_kinetic.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals_kinetic.get_label(m)); } return 1e-6*molar_volume; } //! Return the molar mass of 'component' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_basis(index_t component, units::MassUnit mass_unit) const NOEXCEPT { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return components.molar_mass(component)*scaling; } //! \brief Return the molar mass (kg/mol) of a mineral scalar_t DataContainer::molar_mass_mineral(index_t mineral) const { return 1e-3*components.molar_mass_compounds(minerals.get_nu_row(mineral)); } //! \brief Return the molar mass (kg/mol) of a mineral governed by kinetic scalar_t DataContainer::molar_mass_mineral_kinetic(index_t mineral) const { return 1e-3*components.molar_mass_compounds(minerals_kinetic.get_nu_row(mineral)); } //! Return the molar mass of 'mineral' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_mineral(index_t mineral, units::MassUnit mass_unit) const { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return scaling*components.molar_mass_compounds(minerals.get_nu_row(mineral)); } //! Return the molar mass of 'mineral_kinetic' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_mineral_kinetic(index_t mineral_kinetic, units::MassUnit mass_unit) const { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return scaling*components.molar_mass_compounds(minerals_kinetic.get_nu_row(mineral_kinetic)); } //! Return the molar mass (kg/mol) of a compound scalar_t DataContainer::molar_mass_compound(index_t j) const { return 1e-3*components.molar_mass_compounds(compounds.get_nu_row(j)); } //! Return the molar mass of a compound scalar_t DataContainer::molar_mass_compound(index_t j, units::MassUnit mass_unit) const { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return scaling*components.molar_mass_compounds(compounds.get_nu_row(j)); } //! Return the molar mass (kg/mol) of an aqueous species scalar_t DataContainer::molar_mass_aqueous(index_t j) const { return 1e-3*components.molar_mass_compounds(aqueous.get_nu_row(j)); } //! Return the molar mass of an aqueous species scalar_t DataContainer::molar_mass_aqueous(index_t j, units::MassUnit mass_unit) const { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return scaling*components.molar_mass_compounds(aqueous.get_nu_row(j)); } //! Return the molar mass (kg/mol) of a sorbed species scalar_t DataContainer::molar_mass_sorbed(index_t j) const { return 1e-3*components.molar_mass_compounds(sorbed.get_nu_row(j)); } //! Return the molar mass of a sorbed species scalar_t DataContainer::molar_mass_sorbed(index_t j, units::MassUnit mass_unit) const { scalar_t scaling = scaling_factor_molar_mass(mass_unit); return scaling*components.molar_mass_compounds(sorbed.get_nu_row(j)); } bool DataContainer::is_valid() const { bool is_valid = (components.is_valid() and aqueous.is_valid() and minerals.is_valid() and minerals_kinetic.is_valid() and gas.is_valid() and sorbed.is_valid() and compounds.is_valid() and elements.size() == nb_component() ); if (m_fixed_hash > 0) is_valid = is_valid and (get_hash() == m_fixed_hash); return is_valid; } size_t DataContainer::get_hash() const { size_t hash_db = std::hash()(metadata); // the factors 2 are to distinguish cases were species are simply moved to another list hash_db += ( components.get_hash() + 2*aqueous.get_hash() + minerals.get_hash() + 2*minerals_kinetic.get_hash() + gas.get_hash() + sorbed.get_hash() + compounds.get_hash() ); return hash_db; } } // end namespace database } // end namespace specmicp diff --git a/src/database/data_container.hpp b/src/database/data_container.hpp index b3eb847..fbcbdf2 100644 --- a/src/database/data_container.hpp +++ b/src/database/data_container.hpp @@ -1,474 +1,476 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_DATACONTAINER_HPP #define SPECMICP_DATABASE_DATACONTAINER_HPP //! \file data_container.hpp //! \brief Storage class for the thermodynamics database #include "../types.hpp" #include "../physics/units.hpp" #include "species/element_list.hpp" #include "species/component_list.hpp" #include "species/aqueous_list.hpp" #include "species/mineral_list.hpp" #include "species/gas_list.hpp" #include "species/sorbed_list.hpp" #include "species/compounds_list.hpp" namespace specmicp { namespace database { extern const std::string water_label; //!< The water label in the database constexpr index_t water_id{0}; //!< Index of water in the database extern const std::string electron_label; //!< The electron label in the database constexpr index_t electron_id{1}; //!< Index of the electron in the database //! \brief Information used to trace the database struct SPECMICP_DLL_PUBLIC Metadata { std::string path; //!< path to the database std::string name; //!< name of the database std::string version; //!< version of the database }; //! \brief Storage class - Contains the database //! //! The database is shared by (almost) everything else using a shared_ptr. //! This class is only a container. It should not be modified by hand but //! using the algorithms provided by specimicp::database::Database. //! //! \sa specimicp::database::Database struct SPECMICP_DLL_PUBLIC DataContainer { DataContainer() {} Metadata metadata; //!< Metada, name path and version of the database //! \name Element //! \brief The element list // ======================== //! @{ ElementList elements; //!< The elements //! \brief Return the id of a component given the element index_t get_id_component_from_element(const std::string& element) const { return elements.get_id_component(element); } //! \brief Return the label of a component given the element std::string get_label_component_from_element(const std::string& element) const { return get_label_component(get_id_component_from_element(element)); } //! @} //! \name Basis //! \brief The basis contains the components // ========================================== //! @{ ComponentList components; //!< The basis //! \brief Return the number of components in the basis index_t nb_component() const {return components.size();} //! \brief Return the number of all aqueous components, not including water and electron index_t nb_aqueous_components() const noexcept {return nb_component()-2;} //! \brief Return the id of component 'label' //! //! Return no_species if the component does not exist index_t get_id_component(const std::string& label) const { return components.get_id(label); } //! \brief Return the id of component 'label' std::string get_label_component(index_t id) const{ return components.get_label(id); } //! \brief Return the molar mass of 'component' in kg/mol scalar_t molar_mass_basis(index_t component) const NOEXCEPT {return 1e-3*components.molar_mass(component);} //! \brief Return the molar mass of 'component' in 'mass_unit'/mol scalar_t molar_mass_basis(index_t component, units::MassUnit mass_unit) const NOEXCEPT; //! \brief Return the charge of a component const scalar_t& charge_component(index_t i) const NOEXCEPT {return components.charge(i);} //! \brief Return the 'a_i' Debye-Huckel parameter for a component const scalar_t& a_debye_component(index_t i) const NOEXCEPT {return components.a_debye(i);} //! \brief Return the 'b_i' extended Debye-Huckel parameter for a component const scalar_t& b_debye_component(index_t i) const NOEXCEPT {return components.b_debye(i);} //! \brief Return the index of the water in the basis constexpr static index_t water_index() noexcept { return water_id; } //! \brief return the index of the electron in the basis constexpr static index_t electron_index() noexcept { return electron_id; } //! \brief Range over the components range_t range_component() const { return components.range();} //! \brief Range over the aqueous components range_t range_aqueous_component() const { return range_t(2, nb_component()); } //! @} //! \name Secondary aqueous species //! \brief The secondary aqueous species // ========================================= //! @{ AqueousList aqueous; //!< The list of aqueous species //! \brief Return the number of aqueous species in the system (not counting components) index_t nb_aqueous() const {return aqueous.size();} //! \brief Return the stoichiometric coefficient of 'i' in the dissociation reaction of species 'j' const scalar_t& nu_aqueous(index_t j, index_t i) const {return aqueous.nu_ji(j, i);} //! \brief Return the logk of dissociation reaction of species 'j' const scalar_t& logk_aqueous(index_t j) const {return aqueous.logk(j);} //! \brief Return the id of aqueous species 'label' //! //! Return no_species if the aqueous species does not exist index_t get_id_aqueous(const std::string& label) const{ return aqueous.get_id(label); } //! \brief Return the id of aqueous species 'label' std::string get_label_aqueous(index_t id) const { return aqueous.get_label(id); } //! \brief Return the charge of a secondary aqueous species const scalar_t& charge_aqueous(index_t j) const NOEXCEPT {return aqueous.charge(j);} //! \brief Return the 'a_i' Debye-Huckel parameter for a secondary aqueous species const scalar_t& a_debye_aqueous(index_t j) const NOEXCEPT {return aqueous.a_debye(j);} //! \brief Return the 'b_i' extended Debye-Huckel parameter for a secondary aqueous species const scalar_t& b_debye_aqueous(index_t j) const NOEXCEPT {return aqueous.b_debye(j);} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_half_cell_reaction(index_t aqueous_species) const NOEXCEPT { return (nu_aqueous(aqueous_species, electron_index()) != 0.0); } //! \brief Range over the secondary aqueous species range_t range_aqueous() const { return aqueous.range();} //! Return the molar mass (kg/mol) of an aqueous species scalar_t molar_mass_aqueous(index_t j) const; //! Return the molar mass of an aqueous species scalar_t molar_mass_aqueous(index_t j, units::MassUnit mass_unit) const; //! @} //! \name Compounds species //! \brief The 'compounds' species : strong electrolytes //! ==================================================== //! @{ CompoundList compounds; //!< List of compounds //! \brief return the number of compounds index_t nb_compounds() const {return compounds.size();} //! \brief Return the stoichiometric coefficient of 'i' in the dissociation reaction of species 'j' const scalar_t& nu_compound(index_t j, index_t i) const {return compounds.nu_ji(j, i);} //! \brief Return the id of compounds 'label' //! //! Return 'no_species' if the compound does not exist index_t get_id_compound(const std::string& label) const { return compounds.get_id(label); } //! \brief Return the id of compound 'label' std::string get_label_compound(index_t id) const { return compounds.get_label(id); } //! \brief Range over the sorbed species range_t range_compounds() const { return compounds.range();} //! Return the molar mass (kg/mol) of a compound scalar_t molar_mass_compound(index_t j) const; //! Return the molar mass of a compound scalar_t molar_mass_compound(index_t j, units::MassUnit mass_unit) const; //! @} //! \name Sorbed species //! \brief The adsorbed species // ========================================= //! @{ SorbedList sorbed; //!< The list of sorbed species //! \brief Return the number of sorbed species index_t nb_sorbed() const {return sorbed.size();} //! \brief Return the stoichiometric coefficient of 'i' in the dissociation reaction of species 'j' const scalar_t& nu_sorbed(index_t j, index_t i) const {return sorbed.nu_ji(j, i);} //! \brief Return the logk of dissociation reaction of species 'j' const scalar_t& logk_sorbed(index_t j) const {return sorbed.logk(j);} //! \brief Return the number of sorption sites occupied by a sorbed species const scalar_t& nb_sorption_sites(index_t sorbed_species) const { return sorbed.nb_sorption_site_occupied(sorbed_species); } //! \brief Return the id of sorbed species 'label' //! //! Return no_species if the sorbed species does not exist index_t get_id_sorbed(const std::string& label) const { return sorbed.get_id(label); } //! \brief Return the id of sorbed species 'label' std::string get_label_sorbed(index_t id) const { return sorbed.get_label(id); } //! \brief Range over the sorbed species range_t range_sorbed() const { return sorbed.range();} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_sorbed_half_cell_reaction(index_t sorbed_species) const { return (nu_sorbed(sorbed_species, electron_index()) != 0.0); } //! Return the molar mass (kg/mol) of a sorbed species scalar_t molar_mass_sorbed(index_t j) const; //! Return the molar mass of a sorbed species scalar_t molar_mass_sorbed(index_t j, units::MassUnit mass_unit) const; //! @} //! \name Minerals //! \brief The solid phases // ========================================= //! @{ MineralList minerals; //!< The list of solid phases at equilibrium MineralList minerals_kinetic; //!< The list of solid phases governed by kinetic laws //! \brief Returns the number of solid phases at equilibrium index_t nb_mineral() {return minerals.size();} //! \brief Returns the number of solid phases governed by kinetic laws index_t nb_mineral_kinetic() {return minerals_kinetic.size();} //! \brief Return the stoichiometric coefficient for 'component' in the dissolution reaction of 'mineral' const scalar_t& nu_mineral(index_t mineral, index_t component) const { return minerals.nu_ji(mineral, component); } //! \brief Return the stoichiometric coefficient for 'component' in the dissolution reaction of 'mineral' const scalar_t& nu_mineral_kinetic(index_t mineral, index_t component) const { return minerals_kinetic.nu_ji(mineral, component); } //! \brief Return the logk for the dissolution reaction of 'mineral' const scalar_t& logk_mineral(index_t mineral) const { return minerals.logk(mineral); } //! \brief Return the logk for dissolution reaction of 'mineral' const scalar_t& logk_mineral_kinetic(index_t mineral) const { return minerals_kinetic.logk(mineral); } //! \brief Return true if the corresponding equation is a half-cell reaction bool is_mineral_half_cell_reaction(index_t mineral_species) const { return (nu_mineral(mineral_species, electron_index()) != 0.0); } //! \brief Return true if the corresponding equation is a half-cell reaction bool is_mineral_kinetic_half_cell_reaction(index_t mineral_species) const { return (nu_mineral_kinetic(mineral_species, electron_index()) != 0.0); } //! \brief Return the id of solid phase 'label' //! //! Return no_species if the solid phase does not exist index_t get_id_mineral(const std::string& label) const { return minerals.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_mineral(index_t id) const { return minerals.get_label(id); } //! \brief Return the id of solid phase 'label' //! //! Return no_species if the solid phase does not exist index_t get_id_mineral_kinetic(const std::string& label) const { return minerals_kinetic.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_mineral_kinetic(index_t id) const { return minerals_kinetic.get_label(id); } //! \brief Range over the solid phases (at equilibrium) range_t range_mineral() const { return minerals.range();} //! \brief Range over the solid phases governed by equilibrium range_t range_mineral_kinetic() const { return minerals_kinetic.range();} //! \brief Return the molar mass (kg/mol) of a mineral scalar_t molar_mass_mineral(index_t mineral) const; //! \brief Return the molar mass (kg/mol) of a mineral governed by kinetic scalar_t molar_mass_mineral_kinetic(index_t mineral) const; //! \brief Return the molar mass of 'mineral' in 'mass_uinit'/mol scalar_t molar_mass_mineral(index_t mineral, units::MassUnit mass_unit) const; //! \brief Return the molar mass of 'mineral_kinetic' in 'mass_uinit'/mol scalar_t molar_mass_mineral_kinetic(index_t mineral_kinetic, units::MassUnit mass_unit) const; //! \brief Return the scaling factor for the molar volume scalar_t scaling_molar_volume(units::LengthUnit length_unit) const; //! \brief Return the molar volume whatever it is scalar_t unsafe_molar_volume_mineral(index_t m) const { return minerals.molar_volume(m); } //! \brief Return the molar volume whatever it is scalar_t unsafe_molar_volume_mineral_kinetic(index_t m) const { return minerals_kinetic.molar_volume(m); } //! \brief Return the molar volume (m^3/mol) of a solid phase scalar_t molar_volume_mineral(index_t m) const; //! \brief Return the molar volume (m^3/mol) of a solid phase governed by kinetic scalar_t molar_volume_mineral_kinetic(index_t m) const; //! \brief Return the molar volume of a solid phase in mol/(length_unit)^3 scalar_t molar_volume_mineral(index_t m, units::LengthUnit length_unit) const; //! \brief Return the molar volume of a solid_phase governed by kinetics in mol/(length_unit)^3 scalar_t molar_volume_mineral_kinetic(index_t m, units::LengthUnit length_unit) const; //! @} //! \name Gas //! \brief The gas present in the system // ========================================= //! @{ GasList gas; //!< The list of gas //! \brief Return the number of gas in the system index_t nb_gas() const {return gas.size();} //! \brief Return the stoichiometric coefficient of 'component' in the dissolution reaction of 'gas_id' const scalar_t& nu_gas(index_t gas_id, index_t component) const {return gas.nu_ji(gas_id, component);} //! \brief Return the logk of he dissolution reaction of 'gas_id' const scalar_t& logk_gas(index_t gas_id) const {return gas.logk(gas_id);} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_gas_half_cell_reaction(index_t gas_species) const { return (nu_gas(gas_species, electron_index()) != 0.0); } //! \brief Return the id of gas 'label' //! //! Return no_species if the gas does not exist index_t get_id_gas(const std::string& label) const { return gas.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_gas(index_t id) const { return gas.get_label(id); } //! \brief Range over the gas phases range_t range_gas() const { return gas.range();} //! @} //! \brief Return true if the database is equal to 'other' //! This is just a test on the names in the database not all the values bool operator ==(const DataContainer& other) { return (get_hash() == other.get_hash()); } // Status // ------ //! \brief Return true if the database is valid; bool is_valid() const; //! \brief Freeze the database void freeze_db() {m_fixed_hash = get_hash();} //! \brief Return a hash of the database //! This only take into account the labels, not the values size_t get_hash() const; private: size_t m_fixed_hash {0}; }; } // end namespace database } // end namespace specmicp #include namespace specmicp { namespace database { //! \brief Pointer to a database //! //! This is a smart pointer so we don't have to worry about memory leaks. //! It is intented to be shared between all the modules that needs it. using RawDatabasePtr = std::shared_ptr; } // end namespace database } // end namespace specmicp //! \name dbBoundsAssert //! \brief assert macros to check the bounds of species // ==================================================== //! @{ //! \def specmicp_assert_component_bounds //! Check the bounds of a compoenent //! //! \param component index of a component //! \param raw_database a valid database #define specmicp_assert_component_bounds(component, raw_database) \ specmicp_assert(component >= 0 and component < raw_database->nb_component()) //! \def specmicp_assert_aqueous_bounds //! Check the bounds of a secondary aqueous species //! //! \param aqueous index of an aqueous species //! \param raw_database a valid database #define specmicp_assert_aqueous_bounds(aqueous, raw_database) \ specmicp_assert(aqueous >= 0 and aqueous < raw_database->nb_aqueous()) //! \def specmicp_assert_compound_bounds //! Check the bounds of a compound //! //! \param compound index of a compound //! \param raw_database a valid database #define specmicp_assert_compound_bounds(compound, raw_database) \ specmicp_assert(compound >= 0 and compound < raw_database->nb_compounds()) //! \def specmicp_assert_mineral_bounds //! Check the bounds of a solid phase with respect to raw_database //! //! \param mineral index of a solid phase //! \param raw_database a valid database #define specmicp_assert_mineral_bounds(mineral, raw_database) \ specmicp_assert(mineral >= 0 and mineral < raw_database->nb_mineral()) //! \def specmicp_assert_mineral_kinetic_bounds //! Check the bounds of a solid phase with respect to raw_database //! //! \param mineral index of a solid phase governed by kinetics //! \param raw_database a valid database #define specmicp_assert_mineral_kinetic_bounds(mineral, raw_database) \ specmicp_assert(mineral >= 0 and mineral < raw_database->nb_mineral_kinetic()) //! \def specmicp_assert_gas_bounds //! Check the bounds of a gas with respect to raw_database //! //! \param gas index of a gas //! \param raw_database a valid database #define specmicp_assert_gas_bounds(gas, raw_database) \ specmicp_assert(gas >= 0 and gas < raw_database->nb_gas()) //! @} #endif // SPECMICP_DATABASE_DATACONTAINER_HPP diff --git a/src/database/database.cpp b/src/database/database.cpp index 55cc3ed..3d20830 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -1,176 +1,178 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +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 "yaml_reader.hpp" #include "oxydo_selector.hpp" #include "appender.hpp" #include "yaml_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, bool check_compo) { DataReaderYaml reader(filepath, check_compo); set_database(reader.get_database()); } void Database::parse_database(std::istream& input, bool check_compo) { DataReaderYaml reader(input, check_compo); 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, bool check_compo) { DataAppender(data).add_gas(gas_input, check_compo); } void Database::remove_solid_phases() { MineralSelector(data).remove_all_minerals(); } void Database::add_solid_phases(const std::string &solid_phases_input, bool check_compo) { DataAppender(data).add_minerals(solid_phases_input, check_compo); } void Database::remove_sorbed_species() { DatabaseSelector(data).remove_all_sorbed(); } void Database::add_sorbed_species(const std::string& sorbed_input, bool check_compo) { DataAppender(data).add_sorbed(sorbed_input, check_compo); } void Database::remove_compounds() { DatabaseSelector(data).remove_all_compounds(); } void Database::add_compounds(const std::string& compounds_input, bool check_compo) { DataAppender(data).add_compounds(compounds_input, check_compo); } void Database::remove_half_cell_reactions() { OxydoSelector(data).remove_half_cells(); } 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) { DatabaseWriterYaml(data).write(filename); } } // end namespace database } // end namespace specmicp diff --git a/src/database/database.hpp b/src/database/database.hpp index 01944b7..76b9ffd 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -1,183 +1,185 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_DATABASE_HPP #define SPECMICP_DATABASE_DATABASE_HPP //! \file src/database/database.hpp //! \brief Database management #include "module.hpp" #include namespace specmicp { //! \namespace specmicp::database //! \brief Database management namespace database { //! \brief Prepare the database for the simulation. //! //! This is the class that should be used to handle the database. //! It does not contain the data, only the algorithms. //! //! \ingroup specmicp_api class SPECMICP_DLL_PUBLIC Database: public DatabaseModule { public: //! \brief Default constructor //! //! the method parse_database must be called to parse the json database Database() {} //! \brief Initialise the database py parsing 'filepath' Database(std::string filepath, bool check_compo=true) { parse_database(filepath, check_compo); } //! \brief initialise the database with the raw database Database(std::shared_ptr raw_data): DatabaseModule(raw_data) {} //! \brief Parse the database 'filepath' void parse_database(std::string filepath, bool check_compo=true); //! \brief Parse the database from a stream void parse_database(std::istream& input, bool check_compo=true); //! \brief Return the database //! //! Return a smart pointer of a DataCotnainer instance //! Note : this is a read write access, be careful std::shared_ptr get_database() {return data;} //! \brief Change the basis //! //! @param new_basis list of id of the new basis //! //! The new basis is a list of id, id = id_component for no swapping //! or id = id_aqueous + nb_component for swapping a secondary species void switch_basis(std::vector& new_basis); //! \brief Swap some component in the basis //! \param swap_to_make a map where the keys are the current //! component and the values are the new component void swap_components(const std::map& swap_to_make); //! \brief Remove components not present in the system //! //! "H2O" and "E[-]" cannot be removed from the database. //! //! \param labels_components_to_remove list of labels of the component to remove from the basis void remove_components(const std::vector& labels_components_to_remove); //! \brief Remove components not present in the system //! //! "H2O" and "E[-]" cannot be removed from the database. //! //! \param id_components_to_remove list of id of the component to remove from the basis void remove_components(const std::vector& id_components_to_remove); //! \brief Keep only components in the id_components_to_keep list //! //! "H2O" and "E[-]" will always be kept in the database. //! //! \param id_components_to_keep list of id of the component to keep in the basis void keep_only_components(const std::vector& id_components_to_keep); //! \brief Keep only components in the labels_components_to_keep list //! //! "H2O" and "E[-]" will always be kept in the database. //! //! \param labels_components_to_keep list of labels of the component to keep in the basis void keep_only_components(const std::vector& labels_components_to_keep); //! \brief Keep only some minerals at equilibrium //! //! The effect is to flag all the other minerals as "kinetic" void minerals_keep_only(const std::vector& minerals_to_keep); //! \brief Keep only some minerals at equilibrium //! //! The effect is to flag all the other minerals as "kinetic" void minerals_keep_only(const std::vector& minerals_to_keep); //! \brief Remove all gas species void remove_gas_phases(); //! \brief Add gas phases into the database //! //! The input is a JSON list of gas (formated like the database) void add_gas_phases(const std::string& gas_input, bool check_compo=true); //! \brief Remove all solid phases void remove_solid_phases(); //! \brief Add some solid phases into the database //! //! The input is a JSON list of minerals (formated like the database) void add_solid_phases(const std::string& solid_phases_input, bool check_compo=true); //! \brief Remove all sorbed species void remove_sorbed_species(); //! \brief Add sorbed species into the database //! //! The input is a JSON list of sorbed species (formated like the database) void add_sorbed_species(const std::string& sorbed_species_input, bool check_compo=true); //! \brief Remove the compounds void remove_compounds(); //! \brief Add some compounds into the database //! //! The input is a JSON list of compounds (formated like the database) void add_compounds(const std::string& solid_phases_input, bool check_compo=true); //! \brief Remove all the half-cells reactions void remove_half_cell_reactions(); //! \brief Remove the half-cells reactions for components in 'list_components' void remove_half_cell_reactions(const std::vector& list_components); //! \brief Remove the half-cells reactions for components in 'list_id_components' void remove_half_cell_reactions(const std::vector& list_id_components); //! \brief Freeze the database void freeze() {data->freeze_db();} //! \brief Save the database on disk void save(const std::string& filename); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_DATABASE_HPP diff --git a/src/database/database_fwd.hpp b/src/database/database_fwd.hpp index eec8199..0eb4c90 100644 --- a/src/database/database_fwd.hpp +++ b/src/database/database_fwd.hpp @@ -1,51 +1,53 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_DATABASEFWD_HPP #define SPECMICP_DATABASE_DATABASEFWD_HPP #include namespace specmicp { namespace database { struct DataContainer; class Database; using RawDatabasePtr = std::shared_ptr; } //end namespace database using RawDatabasePtr = database::RawDatabasePtr; } //end namespace specmicp #endif // SPECMICP_DATABASE_DATABASEFWD_HPP diff --git a/src/database/database_holder.hpp b/src/database/database_holder.hpp index 522e305..198cd16 100644 --- a/src/database/database_holder.hpp +++ b/src/database/database_holder.hpp @@ -1,70 +1,72 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_DATABASEHOLDER_HPP #define SPECMICP_DATABASE_DATABASEHOLDER_HPP //! \file database_holder.hpp //! \brief Base class for a class using the database #include "data_container.hpp" namespace specmicp { namespace database { //! \brief Base class for a class using a database class DatabaseHolder { public: DatabaseHolder(const RawDatabasePtr& the_database): m_data(the_database) {} DatabaseHolder(RawDatabasePtr& the_database): m_data(the_database) {} //! \brief return the database RawDatabasePtr& get_database() {return m_data;} const RawDatabasePtr& get_database() const {return m_data;} protected: RawDatabasePtr m_data; }; } //end namespace database } //end namespace specmicp #endif // SPECMICP_DATABASE_DATABASEHOLDER_HPP diff --git a/src/database/errors.hpp b/src/database/errors.hpp index d361b09..5a853f7 100644 --- a/src/database/errors.hpp +++ b/src/database/errors.hpp @@ -1,200 +1,202 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_ERRORS_HPP #define SPECMICP_DATABASE_ERRORS_HPP #include #include #include #include "../types.hpp" //! \file errors.hpp database errors definitions namespace specmicp { namespace database { // Error used when parsing and handling the database // ------------------------------------------------- //! \brief This error is thrown when a label does not exist class db_invalid_label: public std::invalid_argument { public: db_invalid_label(const std::string &msg): std::invalid_argument("Unknown label : " + msg) {} }; //! \brief This error is thrown when a bad syntax is detected in the database class db_invalid_syntax : public std::invalid_argument { public: db_invalid_syntax (const std::string &msg): std::invalid_argument("Invalid syntax : " + msg) {} }; //! \brief This error is thrown when a bad syntax is detected in the database class db_invalid_data : public std::invalid_argument { public: db_invalid_data (const std::string &msg): std::invalid_argument("Invalid syntax : " + msg) {} }; //! \brief This error is thrown when the database is not as expected class invalid_database : public std::invalid_argument { public: invalid_database (const std::string &msg): std::invalid_argument("Invalid Database : " + msg) {} }; //! \brief This error is thrown when a non initialised value is wanted class db_noninitialized_value : public std::runtime_error { public: db_noninitialized_value (const std::string &value, const std::string &species): std::runtime_error("Value was not initialized : " + value +", for species : "+species+".") {} }; //! \brief This error is raised when the species already exist class db_species_already_exist: public std::invalid_argument { public: db_species_already_exist(std::string species, std::string destination): std::invalid_argument("The species '" + species + "' already exist in " + destination + ".") {} }; //! \brief Error be raised when a given species is invalid class SPECMICP_DLL_PUBLIC InvalidSpecies: public std::invalid_argument { public: InvalidSpecies(const std::string& label, const std::string& msg): std::invalid_argument("Invalid species '"+label+"' : " +msg) {} }; //! \brief Error be raised when a species is not a valid component class SPECMICP_DLL_PUBLIC InvalidComponent: public InvalidSpecies { public: InvalidComponent(const std::string& label): InvalidSpecies(label, "is not a component.") {} }; //! \brief Error be raised when a species is not a valid aqueous species class SPECMICP_DLL_PUBLIC InvalidAqueous: public InvalidSpecies { public: InvalidAqueous(const std::string& label): InvalidSpecies(label, "is not a secondary aqueous species.") {} }; //! \brief Error be raised when a species is not a valid aqueous species class SPECMICP_DLL_PUBLIC InvalidGenericAqueousSpecies: public InvalidSpecies { public: InvalidGenericAqueousSpecies(const std::string& label): InvalidSpecies(label, "is not a generic aqueous species.") {} }; //! \brief Error be raised when a species is not a valid compound class SPECMICP_DLL_PUBLIC InvalidCompound: public InvalidSpecies { public: InvalidCompound(const std::string& label): InvalidSpecies(label, "is not a compound.") {} }; //! \brief Error be raised when a species is not a valid solid phase class SPECMICP_DLL_PUBLIC InvalidSolidPhase: public InvalidSpecies { public: InvalidSolidPhase(const std::string& label): InvalidSpecies(label, "is not a valid solid phase.") {} }; //! \brief Error be raised when a species is not a valid mineral (at equilibrium) class SPECMICP_DLL_PUBLIC InvalidMineral: public InvalidSpecies { public: InvalidMineral(const std::string& label): InvalidSpecies(label, "is not a valid a mineral at equilibrium.") {} }; //! \brief Error be raised when a species is not a valid mineral governed by kinetics class SPECMICP_DLL_PUBLIC InvalidMineralKinetics: public InvalidSpecies { public: InvalidMineralKinetics(const std::string& label): InvalidSpecies(label, "is not a valid a mineral governed by kinetics.") {} }; //! \brief Error raised when a species is not a valid gas class SPECMICP_DLL_PUBLIC InvalidGas: public InvalidSpecies { public: InvalidGas(const std::string& label): InvalidSpecies(label, "is not a valid gas") {} }; //! \brief Error raised when a species is not a valid sorbed species class SPECMICP_DLL_PUBLIC InvalidSorbed: public InvalidSpecies { public: InvalidSorbed(const std::string& label): InvalidSpecies(label, "is not a sorbed species") {} }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_ERRORS_HPP diff --git a/src/database/io/configuration.cpp b/src/database/io/configuration.cpp index 0b8f52d..1297fe4 100644 --- a/src/database/io/configuration.cpp +++ b/src/database/io/configuration.cpp @@ -1,143 +1,145 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "configuration.hpp" #include "../../utils/io/yaml.hpp" #include "../database.hpp" #define S_DATABASE "database" #define S_DATABASE_A_PATH "path" #define S_DATABASE_A_SWAP "swap_components" #define S_DATABASE_A_SWAP_K_IN "in" #define S_DATABASE_A_SWAP_K_OUT "out" #define S_DATABASE_A_REMOVE_GAS "remove_gas" #define S_DATABASE_A_REMOVE_SOLIDS "remove_solids" #define S_DATABASE_A_REMOVE_SORBED "remove_sorbeds" #define S_DATABASE_A_EXTRA_GAS "extra_gas" #define S_DATABASE_A_EXTRA_SOLIDS "extra_solids" #define S_DATABASE_A_EXTRA_SORBED "extra_sorbeds" #define S_DATABASE_A_REMOVE_HALF_CELLS "remove_half_cells" #define S_DATABASE_A_LIST_SOLIDS_TOKEEP "list_solids_to_keep" namespace specmicp { namespace io { void swap_components(const YAML::Node& db_conf, database::Database& db_manager); void keep_only_minerals(const YAML::Node& db_conf, database::Database& db_manager); void phases_conf(const YAML::Node& db_conf, database::Database& db_manager); RawDatabasePtr configure_database(const YAML::Node& conf) { check_mandatory_yaml_node(conf, S_DATABASE, "__main__"); const YAML::Node& db_conf = conf[S_DATABASE]; const std::string path = get_yaml_mandatory(db_conf, S_DATABASE_A_PATH, S_DATABASE); database::Database db_manager(path); if (db_conf[S_DATABASE_A_SWAP]) swap_components(db_conf, db_manager); phases_conf(db_conf, db_manager); if (db_conf[S_DATABASE_A_REMOVE_HALF_CELLS]) { if (db_conf[S_DATABASE_A_REMOVE_HALF_CELLS].IsSequence()) { std::vector comp_to_remove; for (auto node: db_conf[S_DATABASE_A_REMOVE_HALF_CELLS]) comp_to_remove.push_back(node.as()); db_manager.remove_half_cell_reactions(comp_to_remove); } else if (db_conf[S_DATABASE_A_REMOVE_HALF_CELLS].as()) { db_manager.remove_half_cell_reactions(); } } return db_manager.get_database(); } void swap_components(const YAML::Node &db_conf, database::Database &db_manager) { const YAML::Node& swapper = db_conf[S_DATABASE_A_SWAP]; std::map switch_map; for (auto it: swapper) { switch_map[it[S_DATABASE_A_SWAP_K_OUT].as()] = it[S_DATABASE_A_SWAP_K_IN].as(); } db_manager.swap_components(switch_map); } void phases_conf(const YAML::Node& db_conf, database::Database& db_manager) { if (db_conf[S_DATABASE_A_REMOVE_GAS] and db_conf[S_DATABASE_A_REMOVE_GAS].as()) db_manager.remove_gas_phases(); if (db_conf[S_DATABASE_A_EXTRA_GAS]) db_manager.add_gas_phases(db_conf[S_DATABASE_A_EXTRA_GAS].as()); if (db_conf[S_DATABASE_A_LIST_SOLIDS_TOKEEP]) { std::vector list; list.reserve(db_conf[S_DATABASE_A_LIST_SOLIDS_TOKEEP].size()); for (auto it: db_conf[S_DATABASE_A_LIST_SOLIDS_TOKEEP]) { list.push_back(it.as()); } db_manager.minerals_keep_only(list); } if (db_conf[S_DATABASE_A_REMOVE_SOLIDS] and db_conf[S_DATABASE_A_REMOVE_SOLIDS].as()) db_manager.remove_solid_phases(); if (db_conf[S_DATABASE_A_EXTRA_SOLIDS]) db_manager.add_solid_phases(db_conf[S_DATABASE_A_EXTRA_SOLIDS].as()); if (db_conf[S_DATABASE_A_REMOVE_SORBED] and db_conf[S_DATABASE_A_REMOVE_SORBED].as()) db_manager.remove_gas_phases(); if (db_conf[S_DATABASE_A_EXTRA_SORBED]) db_manager.add_sorbed_species(db_conf[S_DATABASE_A_EXTRA_SORBED].as()); } } //end namespace io } //end namespace specmicp diff --git a/src/database/io/configuration.hpp b/src/database/io/configuration.hpp index 1625623..7d9fccc 100644 --- a/src/database/io/configuration.hpp +++ b/src/database/io/configuration.hpp @@ -1,54 +1,56 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_CONFIGURATION_HPP #define SPECMICP_IO_CONFIGURATION_HPP #include "../../types.hpp" #include "../../database.hpp" namespace YAML { class Node; } //end namespace YAML namespace specmicp { namespace io { RawDatabasePtr SPECMICP_DLL_PUBLIC configure_database(const YAML::Node& conf); } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_CONFIGURATION_HPP diff --git a/src/database/io/hdf5_database.cpp b/src/database/io/hdf5_database.cpp index 1f43b99..d782212 100644 --- a/src/database/io/hdf5_database.cpp +++ b/src/database/io/hdf5_database.cpp @@ -1,221 +1,223 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "hdf5_database.hpp" #include "../data_container.hpp" #include "../../utils/io/specmicp_hdf5.hpp" #include namespace specmicp { namespace io { namespace internal { //! \brief Implementation of the database saver class SPECMICP_DLL_LOCAL DatabaseHDF5Saver { public: DatabaseHDF5Saver(database::RawDatabasePtr raw_data): m_data(raw_data) {} //! //! \brief Save the labels of a database //! \param file HDF5 file //! \param name Name of the group to be created //! \param section Name of the group where the new group willbe created //! void save_labels(HDF5File& file, const std::string& name, const std::string& section ); private: //! \brief Save the component labels void save_components_labels(HDF5File& file, const std::string& section); //! \brief Save the aqueous labels void save_aqueous_labels( HDF5File& file, const std::string& section); //! \brief Save the gas labels void save_gas_labels( HDF5File& file, const std::string& section); //! \brief Save the minerals labels void save_minerals_labels( HDF5File& file, const std::string& section); //! \brief Generic function to save a group of labels //! //! \param file HDF5 file //! \param section Group und //! \param name //! \param nb_species //! \param get_label //! static void save_generic_labels( HDF5File& file, const std::string& name, const std::string& section, index_t nb_species, std::function get_label ); database::RawDatabasePtr m_data; }; } //end namespace internal void save_database_labels( HDF5File& file, const std::string& name, const std::string& section, database::RawDatabasePtr raw_data ) { internal::DatabaseHDF5Saver saver(raw_data); saver.save_labels(file, name, section); } // Implementation // ============== namespace internal { void DatabaseHDF5Saver::save_labels( HDF5File& file, const std::string& name, const std::string& section ) { auto group_name = file.complete_name(name, section); auto group = file.create_group(group_name); save_components_labels(file, group_name); save_aqueous_labels(file, group_name); save_gas_labels(file, group_name); save_minerals_labels(file, group_name); } void DatabaseHDF5Saver::save_components_labels( HDF5File& file, const std::string& section ) { return save_generic_labels( file, "components", section, m_data->nb_component(), [this](index_t id) -> std::string { return this->m_data->get_label_component(id); } ); } void DatabaseHDF5Saver::save_aqueous_labels( HDF5File& file, const std::string& section ) { return save_generic_labels( file, "aqueous", section, m_data->nb_aqueous(), [this](index_t id) -> std::string { return this->m_data->get_label_aqueous(id); } ); } void DatabaseHDF5Saver::save_gas_labels( HDF5File& file, const std::string& section ) { return save_generic_labels( file, "gas", section, m_data->nb_gas(), [this](index_t id) -> std::string { return this->m_data->get_label_gas(id); } ); } void DatabaseHDF5Saver::save_minerals_labels( HDF5File& file, const std::string& section ) { return save_generic_labels( file, "minerals", section, m_data->nb_mineral(), [this](index_t id) -> std::string { return this->m_data->get_label_mineral(id); } ); } void DatabaseHDF5Saver::save_generic_labels( HDF5File& file, const std::string& name, const std::string& section, index_t nb_species, std::function get_label ) { // /!\ we need to create a vector of char* to pass to hdf5 // danger => explicit use of new[] and delete[] std::vector labels(nb_species); for (index_t id=0; id(nb_species)}; auto fspace = H5::DataSpace(1, dims); // write to file auto dataset = file.create_dataset(name, section, type, fspace, plist); dataset->write(labels.data(), type); // free memory for (index_t id=0; id Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_HDF5_DATABASE_HPP #define SPECMICP_IO_HDF5_DATABASE_HPP //! \file hdf5_database.hpp //! \brief Format the database to hdf5 #include "../../types.hpp" #include namespace specmicp { namespace database { struct DataContainer; using RawDatabasePtr = std::shared_ptr; } //end namespace Database namespace io { class HDF5File; //! \brief Save the database labels in a HDF5 file //! //! \param file HDF5 file //! \param name A new group 'name' will be created to save the database //! \param section The group will be created in the group 'section' //! \param raw_data The database to save //! void save_database_labels( HDF5File& file, const std::string& name, const std::string& section, database::RawDatabasePtr raw_data ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_HDF5_DATABASE_HPP diff --git a/src/database/mineral_selector.cpp b/src/database/mineral_selector.cpp index 5a19951..d970829 100644 --- a/src/database/mineral_selector.cpp +++ b/src/database/mineral_selector.cpp @@ -1,96 +1,98 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "mineral_selector.hpp" namespace specmicp { namespace database { void MineralSelector::keep_only(const std::vector& minerals_to_keep) { // First we compute the new sizes const uindex_t nb_to_keep = minerals_to_keep.size(); const uindex_t nb_to_remove = data->nb_mineral() - nb_to_keep; const uindex_t nb_new_min_kin = data->nb_mineral_kinetic() + nb_to_remove; uindex_t new_id = 0; uindex_t new_id_kin = data->nb_mineral_kinetic(); // Then we assure that there is place for moving data data->minerals_kinetic.resize(nb_new_min_kin); // Then we move data for (index_t id: data->range_mineral()) { auto search = std::find(minerals_to_keep.begin(), minerals_to_keep.end(), id); if (search == minerals_to_keep.end() ) // to move to kinetic { data->minerals.move_erase_to(id, data->minerals_kinetic, new_id_kin); ++new_id_kin; } else { data->minerals.move_erase(id, new_id); ++new_id; } } specmicp_assert(new_id == nb_to_keep); // simple test to assure that everything is ok specmicp_assert(new_id_kin == nb_new_min_kin); // Finally we shrink the containers for the mineral at equilibrium data->minerals.resize(nb_to_keep); data->minerals.set_valid(); data->minerals_kinetic.set_valid(); } void MineralSelector::keep_only(const std::vector& minerals_to_keep) { std::vector ids(minerals_to_keep.size()); for (uindex_t min=0; minminerals = MineralList(0, data->nb_component()); data->minerals_kinetic = MineralList(0, data->nb_component()); data->minerals.set_valid(); data->minerals_kinetic.set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/mineral_selector.hpp b/src/database/mineral_selector.hpp index 84d47c6..f581f95 100644 --- a/src/database/mineral_selector.hpp +++ b/src/database/mineral_selector.hpp @@ -1,68 +1,70 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_MINERALSELECTOR_HPP #define SPECMICP_DATABASE_MINERALSELECTOR_HPP //! \file mineral_selector.hpp select minerals in the database #include "module.hpp" namespace specmicp { namespace database { //! \brief Select equilibrum minerals in the database //! //! Keep only the solid phases that the user wants class MineralSelector: public DatabaseModule { public: MineralSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Keep only minerals with id in "minerals to keep" void keep_only(const std::vector& minerals_to_keep); //! \brief Keep only minerals in "minerals_to_keep" void keep_only(const std::vector& minerals_to_keep); //! \brief Remove all minerals from the databse void remove_all_minerals(); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MINERALSELECTOR_HPP diff --git a/src/database/module.cpp b/src/database/module.cpp index 7e0e46f..7301f99 100644 --- a/src/database/module.cpp +++ b/src/database/module.cpp @@ -1,99 +1,101 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "module.hpp" namespace specmicp { namespace database { index_t DatabaseModule::safe_component_label_to_id(const std::string& label) { auto id = component_label_to_id(label); if (id == no_species) { throw InvalidComponent(label); } return id; } index_t DatabaseModule::safe_aqueous_label_to_id(const std::string& label) { auto id = aqueous_label_to_id(label); if (id == no_species) { throw InvalidAqueous(label); } return id; } index_t DatabaseModule::safe_mineral_label_to_id(const std::string& label) { auto id = mineral_label_to_id(label); if (id == no_species) { throw InvalidMineral(label); } return id; } index_t DatabaseModule::safe_mineral_kinetic_label_to_id(const std::string& label) { auto id = mineral_kinetic_label_to_id(label); if (id == no_species) { throw InvalidMineralKinetics(label); } return id; } index_t DatabaseModule::safe_gas_label_to_id(const std::string& label) { auto id = gas_label_to_id(label); if (id == no_species) { throw InvalidGas(label); } return id; } index_t DatabaseModule::safe_sorbed_label_to_id(const std::string& label) { auto id = sorbed_label_to_id(label); if (id == no_species) { throw InvalidSorbed(label); } return id; } } //end namespace database } //end namespace specmicp diff --git a/src/database/module.hpp b/src/database/module.hpp index 5497f21..ac99102 100644 --- a/src/database/module.hpp +++ b/src/database/module.hpp @@ -1,176 +1,178 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATAABASE_MODULE_HPP #define SPECMICP_DATAABASE_MODULE_HPP //! \file module.hpp base class for a database module #include "data_container.hpp" #include "errors.hpp" namespace specmicp { namespace database { //! \brief Base class for a database module class SPECMICP_DLL_PUBLIC DatabaseModule { public: //! \brief Create a blank database DatabaseModule() { reset_database(); } //! \brief Use the raw database thedata DatabaseModule(RawDatabasePtr& thedata): data(thedata) {} //! \brief set the database void set_database(RawDatabasePtr& thedata) {data = thedata;} //! \brief set the database void set_database(RawDatabasePtr&& thedata) {data = thedata;} //! \brief (Re)set the database - create a blank database void reset_database() {data = std::make_shared();} //! \brief Return true if the database is valid bool is_valid() {return data->is_valid();} //! \brief Return the label for the component 'id' std::string component_id_to_label(index_t id) { return data->components.get_label(id); } //! \brief Return the id of the component "label" //! //! Return no_species if "label" is not a component index_t component_label_to_id(const std::string& label) { return data->components.get_id(label); } //! \brief Safe version of 'component_label_to_id //! throw an error if the compounds cannot be found index_t safe_component_label_to_id(const std::string& label); //! \brief Return the label for the aqueous species 'id' std::string aqueous_id_to_label(index_t id) { return data->aqueous.get_label(id); } //! \brief Return the id of the secondary aqueous species "label" //! //! Return no_species if "label" is not an aqueous species. //! A component (of the basis) is not considered as a secondary aqueous species. index_t aqueous_label_to_id(const std::string& label) { return data->aqueous.get_id(label); } //! \brief Safe version of 'aqueous_label_to_id //! throw an error if the compounds cannot be found index_t safe_aqueous_label_to_id(const std::string& label); //! \brief Return the label for the solid phase 'id' std::string mineral_id_to_label(index_t id) { return data->minerals.get_label(id); } //! \brief Return the id of the mineral "label" //! //! Return no_species if label is not a mineral (at equilibrium) index_t mineral_label_to_id(const std::string& label) { return data->minerals.get_id(label); } //! \brief Safe version of mineral_label_to_id //! throw an error if the compounds cannot be found index_t safe_mineral_label_to_id(const std::string& label); //! \brief Return the label for the kinetic solid phase 'id' std::string mineral_kinetic_id_to_label(index_t id) { return data->minerals_kinetic.get_label(id); } //! \brief Return the id of the mineral "label" //! //! Return no_species if label is not a mineral (at equilibrium) index_t mineral_kinetic_label_to_id(const std::string& label) { return data->minerals_kinetic.get_id(label); } //! \brief Safe version of mineral_kinetic_label_to_id //! throw an error if the compounds cannot be found index_t safe_mineral_kinetic_label_to_id(const std::string& label); //! \brief Return the label for the gas 'id' std::string gas_id_to_label(index_t id) { return data->gas.get_label(id); } //! \brief Return the id of the gas "label" //! //! Return no_species if "label" is not a gas index_t gas_label_to_id(const std::string& label) { return data->gas.get_id(label); } //! \brief Safe version of 'gas_label_to_id //! throw an error if the compounds cannot be found index_t safe_gas_label_to_id(const std::string& label); //! \brief Return the label for the sorbed species 'id' std::string sorbed_id_to_label(index_t id) { return data->sorbed.get_label(id); } //! \brief Return the id of the gas "label" //! //! Return no_species if "label" is not a gas index_t sorbed_label_to_id(const std::string& label) { return data->sorbed.get_id(label); } //! \brief Safe version of 'sorbed_label_to_id //! throw an error if the compounds cannot be found index_t safe_sorbed_label_to_id(const std::string& label); protected: RawDatabasePtr data; //! The database }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MODULE_HPP diff --git a/src/database/oxydo_selector.cpp b/src/database/oxydo_selector.cpp index f26b0da..a41e6f8 100644 --- a/src/database/oxydo_selector.cpp +++ b/src/database/oxydo_selector.cpp @@ -1,136 +1,138 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "oxydo_selector.hpp" namespace specmicp { namespace database { //! \brief Remove the half-cells reaction in 'slist' void remove_half_cells_secondary( ReactiveSpeciesList* slist ); //! \brief Remove the half-cells reaction corresponding to list_components in 'slist' void remove_half_cells_secondary( ReactiveSpeciesList* slist, const std::vector& list_components ); void OxydoSelector::remove_half_cells(const std::vector& list_components) { std::vector list_id_components(list_components.size()); for (std::size_t i=0; i& list_components) { remove_half_cells_secondary(&(data->aqueous), list_components); remove_half_cells_secondary(&(data->sorbed), list_components); remove_half_cells_secondary(&(data->gas), list_components); remove_half_cells_secondary(&(data->minerals), list_components); remove_half_cells_secondary(&(data->minerals_kinetic), list_components); } void OxydoSelector::remove_half_cells() { remove_half_cells_secondary(&(data->aqueous)); remove_half_cells_secondary(&(data->sorbed)); remove_half_cells_secondary(&(data->gas)); remove_half_cells_secondary(&(data->minerals)); remove_half_cells_secondary(&(data->minerals_kinetic)); } //! \brief Remove the half-cells reaction for the aqueous species void remove_half_cells_secondary( ReactiveSpeciesList* slist, const std::vector& list_components ) { // first we select the species to remove std::vector to_remove(slist->size(), false); for (auto id: slist->range()) { if (slist->nu_ji(id, DataContainer::electron_index()) == 0.0) continue; for (const auto& component: list_components) { if (slist->nu_ji(id, component) != 0.0) to_remove[id] = true; } } // then we remove them, in two steps auto new_j = 0; // 1) first we copy data in the beginning of the arrays for (index_t j: slist->range()) { if (to_remove[j]) continue; slist->move_erase(j, new_j); ++new_j; } // 2) then we resize the arrays slist->resize(new_j); slist->set_valid(); } //! \brief Remove the half-cells reaction for the aqueous species void remove_half_cells_secondary( ReactiveSpeciesList* slist ) { // first we select the species to remove std::vector to_remove(slist->size(), false); for (auto id: slist->range()) { if (slist->nu_ji(id, DataContainer::electron_index()) != 0.0) to_remove[id] = true; } auto new_j = 0; // 1) first we copy data in the beginning of the arrays for (index_t j: slist->range()) { if (to_remove[j]) continue; slist->move_erase(j, new_j); ++new_j; } // 2) then we resize the arrays slist->resize(new_j); slist->set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/oxydo_selector.hpp b/src/database/oxydo_selector.hpp index b66e4d5..42c2a5a 100644 --- a/src/database/oxydo_selector.hpp +++ b/src/database/oxydo_selector.hpp @@ -1,66 +1,68 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_OXYDOSELECTOR_HPP #define SPECMICP_DATABASE_OXYDOSELECTOR_HPP //! \file oxydo_selector.hpp //! \brief Remove half-cells reactions #include "module.hpp" namespace specmicp { namespace database { //! \class OxydoSelector //! \brief Remove half cells reaction for for given components //! class OxydoSelector: public DatabaseModule { public: OxydoSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Remove all half-cells reaction void remove_half_cells(); //! \brief Remove the halfs-cells reaction for components in 'list_components' void remove_half_cells(const std::vector& list_components); //! \brief Remove the halfs-cells reaction for components in 'list_components' void remove_half_cells(const std::vector& list_components); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MINERALSELECTOR_HPP diff --git a/src/database/reader_common.cpp b/src/database/reader_common.cpp index 8983d69..ebbb713 100644 --- a/src/database/reader_common.cpp +++ b/src/database/reader_common.cpp @@ -1,342 +1,344 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +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 #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; } // find the next element std::string::size_type find_element(const std::string& label, std::string::size_type pos, element_map& element_coeff); // insert label in elem_map if it doesn't exist else add coeff to the value void insert_or_add(element_map& elem_map, const std::string& label, scalar_t coeff); // find the position of the matching parenthesis std::string::size_type find_matching_parenthesis(const std::string& label, std::string::size_type init_pos); // find a number, return 1 if it's not there std::string::size_type find_number(const std::string& label, std::string::size_type init_pos, scalar_t& number); // return true of the bit in paremnthesis is a phase qualifier (aq, g, s, am, mic) bool is_phase_qualifier(const std::string& bit_in_parenthesis); // return true if it is an expected special character (not a number or a parenthesis) bool is_special(std::string::size_type charac); void element_composition_from_label(std::string label, element_map& compo) { boost::trim_all(label); compo.clear(); std::string::size_type pos = 0; while (pos < label.size()) { if (label[pos] == '(') // ex Al(OH)4 { ++pos; // go into the parenthesis // find composition in parenthesis element_map subcompo; std::string::size_type final_pos = find_matching_parenthesis(label, pos); const std::string sublabel = label.substr(pos, final_pos-pos); if (is_phase_qualifier(sublabel)) { // skip that pos = final_pos; break; } element_composition_from_label(sublabel, subcompo); // find coefficient of parenthesis scalar_t coeff; final_pos = find_number(label, final_pos+1, coeff); // add the compo of parenthesis to the total compo add_to_element_map(compo, subcompo, coeff); pos = final_pos; } else if (label[pos] == ':') // ex CaSO3:0.5H2O { ++pos; // skip the semi-colon // find coefficient scalar_t coeff; std::string::size_type final_pos = find_number(label, pos, coeff); // find element element_map subcompo; element_composition_from_label(label.substr(final_pos, label.size()-final_pos), subcompo); // add compo to total compo add_to_element_map(compo, subcompo, coeff); pos = label.size(); } else if (label[pos] == '[') // charge AlO(OH)3[-] { // it's finished break; } else { pos = find_element(label, pos, compo); } } } bool is_special(std::string::size_type charac) { return (charac == '(' or charac == ':' or charac == ')' or charac == '[' or charac == ']'); } std::string::size_type find_matching_parenthesis(const std::string& label, std::string::size_type init_pos) { for (std::string::size_type ind=init_pos; indsecond += coeff; } else { elem_map.insert(element_map::value_type(label, coeff)); } } std::string::size_type find_element(const std::string& label, std::string::size_type pos, element_map& compo) { if (not std::isupper(label[pos])) throw std::invalid_argument("Invalid formula : "+label+" (Error detected at position "+std::to_string(pos)+" )."); std::string::size_type current_pos = pos +1; std::string::size_type start_number_pos = std::string::npos; while (true) { if (current_pos == label.size() or is_special(label[current_pos]) or std::isupper(label[current_pos]) ) { if (start_number_pos == std::string::npos) { insert_or_add(compo, label.substr(pos, current_pos-pos), 1.0); } else { const std::string coeff_str = label.substr(start_number_pos, current_pos-start_number_pos); insert_or_add(compo, label.substr(pos, start_number_pos-pos), std::stod(coeff_str)); } break; } else if (std::isdigit(label[current_pos]) or label[current_pos] == '.') { if (start_number_pos == std::string::npos) start_number_pos = current_pos; } ++current_pos; } return current_pos; } bool is_phase_qualifier(const std::string& bit_in_parenthesis) { if (bit_in_parenthesis == "aq" or bit_in_parenthesis == "g" or bit_in_parenthesis == "s" or bit_in_parenthesis == "am" or bit_in_parenthesis == "mic" ) { return true; } else { return false; } } void add_to_element_map(element_map& to_update, const element_map& to_add, const scalar_t coeff) { for (auto& it:to_add) { insert_or_add(to_update, it.first, coeff*it.second); } } } //end namespace database } //end namespace specmicp diff --git a/src/database/reader_common.hpp b/src/database/reader_common.hpp index 01a124d..a62a827 100644 --- a/src/database/reader_common.hpp +++ b/src/database/reader_common.hpp @@ -1,76 +1,78 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_READERCOMMON_HPP #define SPECMICP_DATABASE_READERCOMMON_HPP //! \file reader_common.hpp //! \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 : label -> charge //! - neutral -> 0 //! - neutral[] -> 0 //! - charge[+] -> +1 //! - charge[-1] -> -1 //! - charge[+2] -> +2 //! - charge[2-] -> -2 scalar_t charge_from_label(const std::string& label); //! \brief A map giving the stoichiometric coefficient of each element in a compound using element_map = std::map; //! \brief Find the composition (in element) from a label void element_composition_from_label(std::string label, element_map& compo); //! \brief Add an element map to another //! //! \brief to_update the map that is being updated //! \brief to_add the map used to update to_update //! \brief coeff the stoichiometric coefficient void add_to_element_map(element_map& to_update, const element_map& to_add, const scalar_t coeff); } //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 8e38ac5..ebf9c6d 100644 --- a/src/database/section_name.hpp +++ b/src/database/section_name.hpp @@ -1,38 +1,71 @@ +/* ============================================================================= + + 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. * + +============================================================================= */ #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_ATTRIBUTE_FORMULA "formula" #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_CHECKCOMPO "check_composition" #define INDB_ATTRIBUTE_ELEMENT "element" #define INDB_ATTRIBUTE_COMPONENT "component" #define INDB_MAIN "__main__" #define INDB_ELECTRON "E[-]" diff --git a/src/database/selector.cpp b/src/database/selector.cpp index 1568029..c1c2835 100644 --- a/src/database/selector.cpp +++ b/src/database/selector.cpp @@ -1,209 +1,211 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "selector.hpp" #include "aqueous_selector.hpp" namespace specmicp { namespace database { void DatabaseSelector::remove_component(const std::vector& id_component_to_remove) { // Find which components are to be removed analyse_component(id_component_to_remove); // Select the ... // Aqueous secondary species select_aqueous(id_component_to_remove); // Minerals select_minerals(id_component_to_remove); select_minerals_kinetic(id_component_to_remove); // Gas if (data->nb_gas() > 0) select_gas(id_component_to_remove); // Sorbed species if (data->nb_sorbed() > 0) select_sorbed(id_component_to_remove); // Compounds ! if (data->nb_compounds() > 0) select_compounds(id_component_to_remove); // Elements data->elements.remove_components(m_is_component_to_remove); // and finally the components select_components(); } void DatabaseSelector::analyse_component(const std::vector& id_component_to_remove) { for (auto it: id_component_to_remove) { if (it == DataContainer::water_index()) { throw std::invalid_argument("Water cannot be removed from the database"); } else if (it == DataContainer::electron_index()) { throw std::invalid_argument("The electron cannot be removed from the database"); } m_is_component_to_remove[it] = no_species; } auto new_ind = 0; for (auto component: data->range_component()) { if (m_is_component_to_remove[component] != no_species) { m_is_component_to_remove[component] = new_ind; ++new_ind; } } m_nb_component_to_keep = new_ind; specmicp_assert( static_cast(data->nb_component()) - id_component_to_remove.size() == new_ind); } // This is the main algorithm to remove secondary species void DatabaseSelector::select_secondary( ReactiveSpeciesList* toselect, const std::vector& id_component_to_remove ) { // first we select which aqueous species we should remove std::vector to_remove(toselect->size(), false); for (index_t j: toselect->range()) { for (const auto& it: id_component_to_remove) { if (toselect->nu_ji(j, it) != 0.0) { to_remove[j] = true; break; } } } // then we remove them, in two steps const auto nb_to_keep = std::count(to_remove.cbegin(), to_remove.cend(), false); auto new_j = 0; // 1) first we copy data in the beginning of the arrays for (index_t j: toselect->range()) { if (to_remove[j]) continue; toselect->move_erase(j, new_j, m_is_component_to_remove); ++new_j; } specmicp_assert(new_j == nb_to_keep); // 2) then we resize the arrays toselect->resize(nb_to_keep, nb_component_to_keep()); toselect->set_valid(); // By doing in this order, we avoid bulk copy of arrays } void DatabaseSelector::select_aqueous(const std::vector& id_component_to_remove) { select_secondary(&(data->aqueous), id_component_to_remove); } void DatabaseSelector::select_minerals(const std::vector& id_component_to_remove) { select_secondary(&(data->minerals), id_component_to_remove); } void DatabaseSelector::select_minerals_kinetic(const std::vector& id_component_to_remove) { select_secondary(&(data->minerals_kinetic), id_component_to_remove); } void DatabaseSelector::select_gas(const std::vector& id_component_to_remove) { select_secondary(&(data->gas), id_component_to_remove); } void DatabaseSelector::select_sorbed(const std::vector& id_component_to_remove) { select_secondary(&(data->sorbed), id_component_to_remove); } void DatabaseSelector::select_compounds(const std::vector& id_component_to_remove) { select_secondary(&(data->compounds), id_component_to_remove); } void DatabaseSelector::select_components() { for (index_t i: data->range_component()) { index_t new_index = m_is_component_to_remove[i]; if (new_index == no_species) continue; data->components.move_erase(i, new_index); } data->components.resize(nb_component_to_keep()); data->components.set_valid(); } void DatabaseSelector::keep_only_component(const std::vector& id_to_keep) { // First build the list of components to remove std::vector id_to_remove; id_to_remove.reserve(data->nb_component() - id_to_keep.size()); for (index_t id: data->range_aqueous_component()) // avoid removing H2O and E[-] { auto search = std::find(id_to_keep.cbegin(), id_to_keep.cend(), id); if (search == id_to_keep.end()) id_to_remove.push_back(id); } // Then remove them remove_component(id_to_remove); } void DatabaseSelector::remove_all_gas() { data->gas = GasList(0, data->nb_component()); data->gas.set_valid(); } void DatabaseSelector::remove_all_sorbed() { data->sorbed = SorbedList(0, data->nb_component()); data->sorbed.set_valid(); } void DatabaseSelector::remove_all_compounds() { data->compounds = CompoundList(0, data->nb_component()); data->compounds.set_valid(); } //! \brief Remove some specific aqueous species void DatabaseSelector::remove_aqueous(const std::vector& id_aqueous) { AqueousSelector(data).remove_aqueous(id_aqueous); } } // end namespace database } // end namespace specmicp diff --git a/src/database/selector.hpp b/src/database/selector.hpp index 18e1ab4..9b5588a 100644 --- a/src/database/selector.hpp +++ b/src/database/selector.hpp @@ -1,121 +1,123 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SELECTOR_HPP #define SPECMICP_DATABASE_SELECTOR_HPP //! \file selector.hpp Select components in the database #include #include "module.hpp" namespace specmicp { namespace database { //! \brief Select components in the database //! //! This class reduce the database by removing some components //! and all the species associated with these components. class DatabaseSelector: public DatabaseModule { public: DatabaseSelector(RawDatabasePtr thedata): DatabaseModule(thedata), m_is_component_to_remove(thedata->nb_component(), 0) {} //! \brief Remove compoment in the list "id_component_to_remove" //! //! \param id_component_to_remove list of id of the components to remove void remove_component(const std::vector& id_component_to_remove); //! \brief keep only components in the "id_to_keep" list //! //! \param id_to_keep list of id of the components to keep in the database void keep_only_component(const std::vector& id_to_keep); //! \brief Remove all gas phase void remove_all_gas(); //! \brief Remove all sorbed species void remove_all_sorbed(); //! \brief Remove all compounds void remove_all_compounds(); //! \brief Remove some specific aqueous species //! //! This method should not be used in normal usage. //! Removing the aqueous species will break the consistency of the database //! //! \param id_aqueous list of id of the aqueous to remove void remove_aqueous(const std::vector& id_aqueous); private: //! \brief Analyse wich component should be removed void analyse_component(const std::vector& id_component_to_remove); void select_secondary( ReactiveSpeciesList* toselect, const std::vector& id_component_to_remove ); //! \brief Select the correct aqueous species void select_aqueous(const std::vector& id_component_to_remove); //! \brief Select the correct minerals void select_minerals(const std::vector& id_component_to_remove); //! \brief Select the correct minerals governed by kinetics void select_minerals_kinetic(const std::vector& id_component_to_remove); //! \brief Select the gas phases void select_gas(const std::vector& id_component_to_remove); //! \brief Select the sorbed species void select_sorbed(const std::vector& id_component_to_remove); //! \brief Select the compounds void select_compounds(const std::vector& id_component_to_remove); //! \brief Select components //! //! This should be the last operation void select_components(); //! \brief Return the number of component to keep in the db uindex_t nb_component_to_keep() const {return m_nb_component_to_keep;} std::vector m_is_component_to_remove; // -1 if component will be removed, else new index uindex_t m_nb_component_to_keep; // total number of component after the purging is done }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SELECTOR_HPP diff --git a/src/database/species/aqueous_list.hpp b/src/database/species/aqueous_list.hpp index 0ac20a6..51e764d 100644 --- a/src/database/species/aqueous_list.hpp +++ b/src/database/species/aqueous_list.hpp @@ -1,173 +1,175 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_AQUEOUSLIST_HPP #define SPECMICP_DATABASE_AQUEOUSLIST_HPP #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #include "ionic_parameters.hpp" #endif //! \file aqueous_list.hpp //! \brief The list of aqueous species namespace specmicp { namespace database { //! \struct AqueousValues //! \brief Struct to initialize an aqueous species in the aqueous species list //! //! \ingroup database_species struct AqueousValues { std::string label; scalar_t logk; IonicModelValues ionic_values; }; //! \class AqueousList //! \brief The aqueous species //! //! This is the list of aqueous species in the system //! //! \ingroup database_species class AqueousList: public ReactiveSpeciesList { public: //! Initialize an empty list AqueousList() {} //! Initialize a list of 'siz' aqueous species with 'nb_components' components AqueousList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components), m_ionic_param(size) {} //! \name Size //! \brief Manage the size of the list // -------- //! @{ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_ionic_param.resize(size); } //! \brief Resize the list, adjust the number of components void resize(index_t size, index_t nb_components) override { ReactiveSpeciesList::resize(size, nb_components); m_ionic_param.resize(size); } //! @} //! \name Getter //! \brief Return values // ---------------------- //! @{ //! \brief Return the ionic size of component 'k' const scalar_t& a_debye(index_t k) const { return m_ionic_param.a_debye(k); } //! \brief Return the 'b-dot' parameter of component 'k' const scalar_t& b_debye(index_t k) const { return m_ionic_param.b_debye(k); } //! \brief Return the charge of component 'k' const scalar_t& charge(index_t k) const { return m_ionic_param.charge(k); } //! \brief Return the ionic model values of component 'k' IonicModelValues ionic_values(index_t k) const { return m_ionic_param.get_values(k); } //! @} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the ionic model parameters void set_ionic_values(index_t k, const IonicModelValues& values) { m_ionic_param.set_values(k, values); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const AqueousValues& values) { set_label(k, values.label); set_logk(k, values.logk); m_ionic_param.set_values(k, values.ionic_values); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, AqueousValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); m_ionic_param.set_values(k, std::move(values.ionic_values)); } //! @} //! \name Move //! \brief Move species inside the list or to other lists // ------------ //! @{ //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_ionic_param.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind); } //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) override { m_ionic_param.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize(index_t k, index_t other_species, scalar_t coeff) { add_species_to(k, other_species, coeff); } private: IonicModelParameters m_ionic_param; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_AQUEOUSLIST_HPP diff --git a/src/database/species/base_wrapper.cpp b/src/database/species/base_wrapper.cpp index 7640f45..a688e03 100644 --- a/src/database/species/base_wrapper.cpp +++ b/src/database/species/base_wrapper.cpp @@ -1,52 +1,54 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "base_wrapper.hpp" namespace specmicp { namespace database { //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void MatrixSpeciesWrapper::move_erase(index_t old_ind, index_t new_ind, const std::vector& is_col_to_remove) { specmicp_assert(static_cast(is_col_to_remove.size()) == m_matrix.cols()); for (index_t col=0; col Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_BASEWRAPPER_HPP #define SPECMICP_DATABASE_BASEWRAPPER_HPP #include "../../types.hpp" //! \file base_wrapper.hpp //! //! \brief Base wrapper around vectors and matrices //! //! These classes encapsulate an Eigen Matrix (or vector) //! //! \defgroup database_species namespace specmicp { namespace database { //! \class MatrixSpeciesWrapper //! \brief A wrapper around a matrix, to be used by a SpeciesList (or a derived class) instance //! //! \ingroup database_species Describing the species in the database class SPECMICP_DLL_PUBLIC MatrixSpeciesWrapper { public: //! \brief Default constructor MatrixSpeciesWrapper() {} //! \brief Constructor initializing the matrix MatrixSpeciesWrapper(index_t size, index_t nb_cols): m_matrix(Matrix::Zero(size, nb_cols)) {} //! \name Size // ============ //! \brief Return and set the size of the matrix //! @{ //! \brief Return the number of rows in the matrix index_t size() const {return m_matrix.rows();} //! \brief Return the number of columnns in the matrix index_t cols() const {return m_matrix.cols();} //! \brief Resize the matrix //! This is a resize only for the number of rows void resize(index_t size) { m_matrix.conservativeResize(size, Eigen::NoChange); } //! \brief Resize the matrix (both rows and colums) void resize(index_t rows, index_t cols) { m_matrix.conservativeResize(rows, cols); } // @} //! \name Getter // ============= //! \brief Return the values //! @{ //! \brief Return the element ['row', ['col'] const scalar_t& operator()(index_t row, index_t col) const { return m_matrix(row, col); } //! \brief Return a const reference to the matrix const Matrix& get_matrix() const { return m_matrix; } //! \brief Return the row of a matrix Eigen::MatrixBase::ConstRowXpr get_row(index_t k) const { return m_matrix.row(k); } //! \brief Return the element ['row','col'] const scalar_t& get_value(index_t row, index_t col) const { return m_matrix(row, col); } //! @} //! \name Setter // ============= //! \brief Set the values //! @{ //! \brief Add 'other' to row 'k' template void SPECMICP_DLL_LOCAL add_to_row(index_t k, const Eigen::MatrixBase& other) { m_matrix.row(k) += other; } //! \brief Multiply row 'k' by 'multiplier' template void SPECMICP_DLL_LOCAL multiply_by(const Eigen::MatrixBase& multiplier) { m_matrix = m_matrix*multiplier; } //! \brief Set the value of the matrix by copying 'init_matrix' template void SPECMICP_DLL_LOCAL set_matrix(const Eigen::MatrixBase& init_matrix) { m_matrix = init_matrix; } //! \brief Set the element ['row','col'] to 'value' void SPECMICP_DLL_LOCAL set_value(index_t row, index_t col, scalar_t value) { m_matrix(row, col) = value; } //! \brief Reset row 'k' void SPECMICP_DLL_LOCAL reset_row(index_t k) { m_matrix.row(k).setZero(); } //! @} //! \name Move // =========== //! \brief Move values inside, and outside, of the matrix //! @{ //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void move_erase(index_t old_ind, index_t new_ind) { m_matrix.row(new_ind) = m_matrix.row(old_ind); } //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_col_to_remove); //! \brief Move the row to another matrix void move_erase_to(index_t ind, MatrixSpeciesWrapper& other, index_t other_ind) { other.m_matrix.row(other_ind) = m_matrix.row(ind); m_matrix.row(ind).setZero(); } //! \brief Swap two rows void swap(index_t ind, MatrixSpeciesWrapper& other, index_t other_ind) { m_matrix.row(ind).swap(other.m_matrix.row(other_ind)); } //! @} private: Matrix m_matrix; }; //! \class VectorSpeciesWrapper //! \brief A wrapper around a vector //! //! \ingroup database_species class SPECMICP_DLL_PUBLIC VectorSpeciesWrapper { public: //! \brief Default constructor VectorSpeciesWrapper() {} //! \brief Initialise the vector //! \param size initial size of the vector VectorSpeciesWrapper(index_t size): m_vector(Vector::Zero(size)) {} //! \name Size // ============ //! \brief Return and set the size of the vector //! @{ //! \brief Return the size of the vector index_t size() const {return m_vector.rows();} //! \brief Resize the vector void resize(index_t size) { m_vector.conservativeResize(size); } //! @} //! \name Getter // ============= //! \brief Return the values //! @{ //! \brief return the value of index k const scalar_t& operator()(index_t k) const { return m_vector(k); } //! \brief Return the inner product of the vector and 'other' template scalar_t dot(const Eigen::MatrixBase& other) const { return m_vector.dot(other); } //! \brief Return the value of index k const scalar_t& get_value(index_t k) const { return m_vector(k); } //! \brief Return the vector const Vector& get_vector() const { return m_vector; } //! @} //! \name Setter // ============= //! \brief Set the values //! @{ //! \brief add 'vector' template void SPECMICP_DLL_LOCAL add(const Eigen::MatrixBase& vector) { m_vector += vector; } //! \brief Multiply the vector by 'multiplier' template void SPECMICP_DLL_LOCAL multiply_by(const Eigen::MatrixBase& multiplier) { m_vector = m_vector*multiplier; } //! \brief Set the value at index k void SPECMICP_DLL_LOCAL set_value(index_t k, scalar_t value) { m_vector(k) = value; } //! \brief Copy 'vector' to the vector template void SPECMICP_DLL_LOCAL set_vector(const Eigen::MatrixBase& vector) { m_vector = vector; } //! \brief Apply a linear transformation to the vector template void transform(const Eigen::MatrixBase& transform_matrix) { specmicp_assert(transform_matrix.rows() == transform_matrix.cols()); m_vector = transform_matrix*m_vector; } //! @} //! \name Move // =========== //! \brief Move values inside, and outside, of the matrix //! @{ //! \brief Move value of old_ind at new_ind void move_erase(index_t old_ind, index_t new_ind) { m_vector(new_ind) = m_vector(old_ind); } //! \brief Move row 'ind' to 'other' at row 'other_ind' void move_erase_to(index_t ind, VectorSpeciesWrapper& other, index_t other_ind) { other.m_vector(other_ind) = m_vector(ind); m_vector(ind) = 0; } //! @} private: Vector m_vector; }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_BASEWRAPPER_HPP diff --git a/src/database/species/component_list.hpp b/src/database/species/component_list.hpp index 1566ff1..4898e0d 100644 --- a/src/database/species/component_list.hpp +++ b/src/database/species/component_list.hpp @@ -1,163 +1,165 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_COMPONENTLIST_HPP #define SPECMICP_DATABASE_COMPONENTLIST_HPP #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #include "ionic_parameters.hpp" #endif //! \file component_list.hpp A list of components, i.e the basis namespace specmicp { namespace database { //! \struct ComponentValues //! \brief Used for the initialization of a component //! //! \ingroup database_species struct ComponentValues { std::string label; scalar_t molar_mass; IonicModelValues ionic_values; }; //! \class ComponentList //! \brief The basis //! //! This is the list of components in the system //! It extends the species list by managing the ionic //! model parameters and the molar masses. //! //! \ingroup database_species class ComponentList: public SpeciesList { public: ComponentList() {} ComponentList(index_t size): SpeciesList(size), m_molar_mass(size), m_ionic_param(size) {} // Resize // ------ //! \brief Resize the basis void resize(index_t size) override { SpeciesList::resize(size); m_molar_mass.resize(size); m_ionic_param.resize(size); } // Getter // ====== //! \brief Return the molar mass of component k const scalar_t& molar_mass(index_t k) const { return m_molar_mass(k); } //! \brief Return the charge of component 'k' const scalar_t& charge(index_t k) const { return m_ionic_param.charge(k); } //! \brief Return the ionic size of component 'k' const scalar_t& a_debye(index_t k) const { return m_ionic_param.a_debye(k); } //! \brief Return the 'b-dot' parameter of component 'k' const scalar_t& b_debye(index_t k) const { return m_ionic_param.b_debye(k); } //! \brief Return the ionic model values of component 'k' IonicModelValues ionic_values(index_t k) const { return m_ionic_param.get_values(k); } // Setter // ------ //! \brief set the values for component 'k' void set_values(index_t k, const ComponentValues& values) { set_label(k, values.label); m_molar_mass.set_value(k, values.molar_mass); m_ionic_param.set_values(k, values.ionic_values); } //! \brief set the values for component 'k' void set_values(index_t k, ComponentValues&& values) { set_label(k, std::move(values.label)); m_molar_mass.set_value(k, values.molar_mass); m_ionic_param.set_values(k, values.ionic_values); } void set_ionic_values(index_t k, const IonicModelValues& values) { m_ionic_param.set_values(k, values); } //! \brief Return the molar mass of a compounts //! \param stoech a vector containing the stoichiometric coefficients template scalar_t molar_mass_compounds(const Eigen::MatrixBase& stoech) const { return m_molar_mass.dot(stoech); } //! \brief Transform the molar mass of the basis //! \param transform_matrix the linear operator to apply template void molar_mass_transform(const Eigen::MatrixBase& transform_matrix) { m_molar_mass.transform(transform_matrix); } // Move // ----- //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_molar_mass.move_erase(old_ind, new_ind); m_ionic_param.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } private: VectorSpeciesWrapper m_molar_mass; IonicModelParameters m_ionic_param; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_COMPONENTLIST_HPP diff --git a/src/database/species/compounds_list.cpp b/src/database/species/compounds_list.cpp index 3ec6966..f9e93cd 100644 --- a/src/database/species/compounds_list.cpp +++ b/src/database/species/compounds_list.cpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "compounds_list.hpp" #include "../errors.hpp" namespace specmicp { namespace database { void CompoundList::append_to(CompoundList &other) { if (nb_components() != other.nb_components()) { throw db_invalid_data("The two list of sorbed species are not compatible."); } const auto o_size = other.size(); const auto t_size = size(); const auto new_size = o_size+t_size; other.resize(new_size); for (auto i=0; i Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SPECIES_COMPOUNDS_LIST_HPP #define SPECMICP_DATABASE_SPECIES_COMPOUNDS_LIST_HPP //! \file compounds_list.hpp //! \brief List of compounds #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #include "ionic_parameters.hpp" #endif #include "aqueous_list.hpp" namespace specmicp { namespace database { //! \class CompoundList //! \brief The compound species //! //! A compound is an aqueous species that will dissociate immediately //! in the system. They are use to initialize the system but are not included //! in the equilibrium computation //! //! \ingroup database_species class CompoundList: public ReactiveSpeciesList { public: //! Initialize an empty list CompoundList() {} //! Initialize a list of 'siz' aqueous species with 'nb_components' components CompoundList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components) {} //! \name Size //! \brief Manage the size of the list // -------- //! @{ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); } //! \brief Resize the list, adjust the number of components void resize(index_t size, index_t nb_components) override { ReactiveSpeciesList::resize(size, nb_components); } //! @} //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const std::string& label) { set_label(k, label); set_logk(k, -1e99); } //! @} //! \name Move //! \brief Move species inside the list or to other lists // ------------ //! @{ //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { ReactiveSpeciesList::move_erase(old_ind, new_ind); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } //! \brief Append the species in this list to the other list void append_to(CompoundList& other); }; } //end namespace database } //end namespace specmicp #endif // SPECMICP_DATABASE_SPECIES_COMPOUNDS_LIST_HPP diff --git a/src/database/species/element_list.cpp b/src/database/species/element_list.cpp index 01b719f..05a6937 100644 --- a/src/database/species/element_list.cpp +++ b/src/database/species/element_list.cpp @@ -1,138 +1,140 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "element_list.hpp" //#include #include #include "../../utils/compat.hpp" namespace specmicp { namespace database { class ElementList::Impl { public: Impl() {} //! \brief Add element 'label_element' that corresponds to component void add_element(const std::string& label_element, index_t component){ m_map[label_element] = component; } //! \brief Return the id of component corresponding to element 'label' index_t get_id_component(const std::string& label) const { auto it = m_map.find(label); if (it != m_map.end()) return it->second; else return no_species; } //! \brief return the size of the map (should be equal to the number of components) index_t size() const {return m_map.size();} //! \brief return the element corresponding to the component std::string get_element_from_component(index_t component); void remove_components(const std::vector& is_component_to_remove); private: std::map m_map; }; std::string ElementList::Impl::get_element_from_component(index_t component) { // non-optimized, use boost::bimap ? (maybe todo) for (auto it: m_map) { if (it.second == component) { return it.first; } } throw std::invalid_argument("'"+std::to_string(component)+"' is not a valid index for a component"); } void ElementList::Impl::remove_components(const std::vector& is_component_to_remove) { std::vector to_erase; // Check if the component still exist // if it does copy its new location for (auto it=m_map.begin(); it!=m_map.end(); ++it) { const index_t new_value = is_component_to_remove[static_cast(it->second)]; if (new_value == no_species) to_erase.push_back(it->first); else it->second = new_value; } // Remove the element that does not exist anymore for (auto it: to_erase) { m_map.erase(it); } } void ElementList::remove_components(const std::vector &is_component_to_remove) { m_impl->remove_components(is_component_to_remove); } void ElementList::add_element(const std::string& label_element, index_t component) { m_impl->add_element(label_element, component); } index_t ElementList::get_id_component(const std::string& label) const { return m_impl->get_id_component(label); } index_t ElementList::size() const { return m_impl->size(); } ElementList::ElementList(): m_impl(make_unique()) {} std::string ElementList::get_label_element(index_t id_component) { return m_impl->get_element_from_component(id_component); } // syntax hilighter does not like that byt this is correct // see pg 53 of Effective modern C++ by Scott Meyer ElementList::~ElementList() = default; ElementList::ElementList(ElementList&& other) = default; ElementList& ElementList::operator=(ElementList&& other) = default; } //end namespace data } //end namespace specmicp diff --git a/src/database/species/element_list.hpp b/src/database/species/element_list.hpp index f7165fd..af2ac69 100644 --- a/src/database/species/element_list.hpp +++ b/src/database/species/element_list.hpp @@ -1,71 +1,73 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SPECIES_ELEMENTLIST_HPP #define SPECMICP_DATABASE_SPECIES_ELEMENTLIST_HPP //! \file element_list.hpp //! \brief List of elements #include "../../types.hpp" #include namespace specmicp { namespace database { //! \brief List of Element class SPECMICP_DLL_PUBLIC ElementList { public: ElementList(); ~ElementList(); ElementList(ElementList&& other); ElementList& operator=(ElementList&& other); //! \brief Add element 'label_element' that corresponds to component void add_element(const std::string& label_element, index_t component); //! \brief Return the id of component corresponding to element 'label' index_t get_id_component(const std::string& label) const; //! \brief return the size of the map (should be equal to the number of components) index_t size() const; //! \brief Remove components void remove_components(const std::vector& is_component_to_remove); //! \brief Return the label of an element given a component index std::string get_label_element(index_t id_component); private: class Impl; std::unique_ptr m_impl; }; } //end namespace database } //end namespace specmicp #endif // SPECMICP_DATABASE_SPECIES_ELEMENTLIST_HPP diff --git a/src/database/species/gas_list.cpp b/src/database/species/gas_list.cpp index 2c22026..4d8f224 100644 --- a/src/database/species/gas_list.cpp +++ b/src/database/species/gas_list.cpp @@ -1,62 +1,64 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "gas_list.hpp" #include "../errors.hpp" namespace specmicp { namespace database { //! \brief Append the phases in this list to the other list void GasList::append_to(GasList& other) { if (nb_components() != other.nb_components()) { throw db_invalid_data("The two list of gas phases are not compatible."); } const auto o_size = other.size(); const auto t_size = size(); const auto new_size = o_size+t_size; other.resize(new_size); for (auto i=0; i Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_GASLIST_HPP #define SPECMICP_DATABASE_GASLIST_HPP #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #include "aqueous_list.hpp" //! \file gas_list.hpp //! \brief The list of gas phases in the database. namespace specmicp { namespace database { //! \struct GasValues //! \brief Struct to initialize a gas in the gas list //! //! \ingroup database_species struct GasValues { std::string label; //!< Label of the gas scalar_t logk; //!< Log_10 of the equilibrium constant }; //! \class GasList //! \brief The gas list //! //! This is the list of gas in the system //! //! \ingroup database_species class GasList: public ReactiveSpeciesList { public: //! Initialize an empty list GasList() {} //! Initialize a list of 'siz' aqueous species with 'nb_components' components GasList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components) {} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const GasValues& values) { set_label(k, values.label); set_logk(k, values.logk); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, GasValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } //! \brief Append the phases in this list to the other list void append_to(GasList& other); }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_GASLIST_HPP diff --git a/src/database/species/ionic_parameters.hpp b/src/database/species/ionic_parameters.hpp index 244c877..a85b73d 100644 --- a/src/database/species/ionic_parameters.hpp +++ b/src/database/species/ionic_parameters.hpp @@ -1,112 +1,114 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #define SPECMICP_DATABASE_IONICPARAMETERS_HPP #ifndef SPECMICP_DATABASE_BASEWRAPPER_HPP #include "base_wrapper.hpp" #endif //! \file ionic_parameters.hpp //! \brief The ionic model parameters //! //! These parameters are needed for all (primary and secondary) //! aqueous species. namespace specmicp { namespace database { //! \struct IonicModelValues //! The set of main values for the ionic model //! This is used for the initialisation of an aqueous species. //! //! \ingroup database_species struct IonicModelValues { scalar_t charge {0.0}; scalar_t a_debye {0.0}; scalar_t b_debye {0.0}; IonicModelValues() {} IonicModelValues(scalar_t acharge, scalar_t adebye, scalar_t bdebye): charge(acharge), a_debye(adebye), b_debye(bdebye) {} }; //! \class IonicModelParameters //! \brief Class that contains the ionic model parameters //! //! This class is used for all (primary and secondary) aqueous species. //! //! \ingroup database_species class IonicModelParameters: public MatrixSpeciesWrapper { public: static constexpr index_t charge_ind = 0; //!< Column index of the charge static constexpr index_t adebye_ind = 1; //!< Column index of the ionic size parameter static constexpr index_t bdebye_ind = 2; //!< Column index of the b-dot parameter IonicModelParameters() {} IonicModelParameters(index_t size): MatrixSpeciesWrapper(size, 3) {} void resize_columns(index_t colums) = delete; //!< The number of columns is fixed void resize_matrix(index_t rows, index_t cols) = delete; //!< The number of columns is fixed //! \brief Return the charge const scalar_t& charge(index_t ind) const {return get_value(ind, charge_ind);} //! \brief Return the ionic size parameter const scalar_t& a_debye(index_t ind) const {return get_value(ind, adebye_ind);} //! \brief Return the b-dot parameter const scalar_t& b_debye(index_t ind) const {return get_value(ind, bdebye_ind);} //! \brief Set the values void set_values(index_t ind, const IonicModelValues& values) { set_value(ind, charge_ind, values.charge); set_value(ind, adebye_ind, values.a_debye); set_value(ind, bdebye_ind, values.b_debye); } //! \brief Return the ionic value IonicModelValues get_values(index_t ind) const { return IonicModelValues(charge(ind), a_debye(ind), b_debye(ind)); } }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_IONICPARAMETERS_HPP diff --git a/src/database/species/mineral_list.cpp b/src/database/species/mineral_list.cpp index 68af2fb..d29d31f 100644 --- a/src/database/species/mineral_list.cpp +++ b/src/database/species/mineral_list.cpp @@ -1,70 +1,72 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "mineral_list.hpp" #include "../errors.hpp" namespace specmicp { namespace database { void MineralList::move_erase_to( index_t ind, MineralList& other, index_t other_ind ) { ReactiveSpeciesList::move_erase_to(ind, other, other_ind); m_molar_volume.move_erase_to(ind, other.m_molar_volume, other_ind); } void MineralList::append_to(MineralList &other) { if (nb_components() != other.nb_components()) { throw db_invalid_data("The two list of solid are not compatible."); } const auto o_size = other.size(); const auto t_size = size(); const auto new_size = o_size+t_size; other.resize(new_size); for (auto i=0; i Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP #define SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_AQUEOUSLIST_HPP #include "aqueous_list.hpp" #endif //! \file mineral_list.hpp //! \brief A list of solid phases namespace specmicp { namespace database { //! \struct MineralValue //! Initializer struct for a solid phase //! //! \ingroup database_species struct MineralValue { std::string label; //!< The label scalar_t logk; //!< log_10 of the equilibrium constant scalar_t molar_volume; //!< The molar volume }; //! \class MineralList //! \brief A list of solid phases //! //! In addition to the basic features of a 'ReactiveSpeciesList' //! this class handles the molar volume of the solid phases. //! //! \ingroup database_species class MineralList: public ReactiveSpeciesList { public: MineralList() {} MineralList(index_t size, index_t nb_component): ReactiveSpeciesList(size, nb_component), m_molar_volume(size) {} // Getter // ------ //! \brief Return the molar volume const scalar_t& molar_volume(index_t k) const { return m_molar_volume(k); } // Setter // ------ //! \brief Initialise the solid phase at index_t k //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const MineralValue& values) { set_label(k, values.label); set_logk(k, values.logk); m_molar_volume.set_value(k, values.molar_volume); } //! \brief Initialise the solid phase at index_t k //! \warning Do no set stoichiometric coefficients void set_values(index_t k, MineralValue&& values) { set_label(k, std::move(values.label)); set_logk(k, std::move(values.logk)); m_molar_volume.set_value(k, std::move(values.molar_volume)); } // Move // ---- //! \brief Move the solid phase at index 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { ReactiveSpeciesList::move_erase(old_ind, new_ind); m_molar_volume.move_erase(old_ind, new_ind); } //! \brief Move the solid phase at index 'old_ind' to 'new_ind' and removes components void move_erase( index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove ) override { ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); m_molar_volume.move_erase(old_ind, new_ind); } //! \brief Move solid phase 'ind' to 'other_ind' in the 'other' list void move_erase_to( index_t ind, MineralList& other, index_t other_ind ); //! \brief Append the phases in this list to the other list void append_to(MineralList& other); // Resize // ------ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_molar_volume.resize(size); } //! \brief Resize the list and the stoichiometric coefficients matrix void resize(index_t size, index_t nb_component) override { ReactiveSpeciesList::resize(size, nb_component); m_molar_volume.resize(size); } // Misc // ---- //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } private: VectorSpeciesWrapper m_molar_volume; }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP diff --git a/src/database/species/sorbed_list.cpp b/src/database/species/sorbed_list.cpp index 30cac56..9d74352 100644 --- a/src/database/species/sorbed_list.cpp +++ b/src/database/species/sorbed_list.cpp @@ -1,66 +1,68 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "sorbed_list.hpp" #include "../errors.hpp" namespace specmicp { namespace database { void SorbedList::move_erase_to(index_t old, SorbedList& other, index_t other_ind) { ReactiveSpeciesList::move_erase_to(old, other, other_ind); m_sorption_site.move_erase_to(old, other.m_sorption_site, other_ind); } void SorbedList::append_to(SorbedList &other) { if (nb_components() != other.nb_components()) { throw db_invalid_data("The two list of sorbed species are not compatible."); } const auto o_size = other.size(); const auto t_size = size(); const auto new_size = o_size+t_size; other.resize(new_size); for (auto i=0; i Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SORBEDLIST_HPP #define SPECMICP_DATABASE_SORBEDLIST_HPP #include "../../types.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #include "aqueous_list.hpp" //! \file aqueous_list.hpp //! \brief The list of sorbed species //! //! This list stores the informations about sorbed species. namespace specmicp { namespace database { //! \struct SorbedValues //! \brief Struct to initialize a sorbed species in the sorbed species list //! //! \ingroup database_species struct SorbedValues { std::string label; scalar_t logk; index_t sorption_site_occupied; }; //! \class SorbedList //! \brief The sorbed species //! //! This is the list of sorbed species in the database //! //! \ingroup database_species class SorbedList: public ReactiveSpeciesList { public: //! Initialize an empty list SorbedList() {} //! Initialize a list of 'size' sorbed species with 'nb_components' components SorbedList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components), m_sorption_site(size) {} //! \name Size //! \brief Manage the size of the list // -------- //! @{ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_sorption_site.resize(size); } //! \brief Resize the list, adjust the number of components void resize(index_t size, index_t nb_components) override { ReactiveSpeciesList::resize(size, nb_components); m_sorption_site.resize(size); } //! @} //! \name Getter //! \brief Return values // ---------------------- //! @{ //! \brief Return the ionic size of component 'k' const scalar_t& nb_sorption_site_occupied(index_t k) const { return m_sorption_site(k); } //! @} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const SorbedValues& values) { set_label(k, values.label); set_logk(k, values.logk); m_sorption_site.set_value(k, values.sorption_site_occupied); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, SorbedValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); m_sorption_site.set_value(k, values.sorption_site_occupied); } //! @} //! \name Move //! \brief Move species inside the list or to other lists // ------------ //! @{ //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_sorption_site.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind); } //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) override { m_sorption_site.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); } //! \brief move the species at index 'old' to 'other_ind' in 'other' void move_erase_to(index_t old, SorbedList& other, index_t other_ind); //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } //! \brief Append the species in this list to the other list void append_to(SorbedList& other); private: VectorSpeciesWrapper m_sorption_site; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_SORBEDLIST_HPP diff --git a/src/database/species/species.cpp b/src/database/species/species.cpp index e8a8700..ba92a60 100644 --- a/src/database/species/species.cpp +++ b/src/database/species/species.cpp @@ -1,80 +1,82 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "species.hpp" #include "database/errors.hpp" namespace specmicp { namespace database { static std::hash hash_fn; //!< The hash function void SpeciesList::set_label(index_t ind, const std::string& label) { m_labels[ind] = label; m_hashes[ind] = hash_fn(label); } void SpeciesList::set_label(index_t ind, std::string&& label) { m_labels.emplace(m_labels.begin()+ind, std::move(label)); m_hashes[ind] = hash_fn(m_labels[ind]); } index_t SpeciesList::get_id(const std::string& label) const { if (label == "") return no_species; auto hash = hash_fn(label); auto searchit = std::find(m_hashes.cbegin(), m_hashes.cend(), hash); if (searchit == m_hashes.cend()) return no_species; // the species does not exist in the list return static_cast(searchit - m_hashes.cbegin()); } size_t SpeciesList::get_hash() const { return std::accumulate(m_hashes.cbegin(), m_hashes.cend(), 0); } //! \brief Move species 'ind' to the list 'other' at 'other_ind' void ReactiveSpeciesList::move_erase_to(index_t ind, ReactiveSpeciesList& other, index_t other_ind) { if (other.get_id(get_label(ind)) != no_species) { throw db_species_already_exist(get_label(ind), "the destination"); } SpeciesList::move_erase_to(ind, other, other_ind); m_nu_coeffs.move_erase_to(ind, other.m_nu_coeffs, other_ind); m_log_k.move_erase_to(ind, other.m_log_k, other_ind); } } // end namespace database } // end namespace specmicp diff --git a/src/database/species/species.hpp b/src/database/species/species.hpp index 59103d6..3889801 100644 --- a/src/database/species/species.hpp +++ b/src/database/species/species.hpp @@ -1,396 +1,398 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SPECIES_HPP #define SPECMICP_DATABASE_SPECIES_HPP #include "../../types.hpp" #include "base_wrapper.hpp" //! \file species.hpp //! //! \brief The base wrappers describing a species list //! //! The two classes of this file are the basis for any list of species //! and are at the cores of the database and its algorithm. //! namespace specmicp { namespace database { //! \class SpeciesList //! \brief Base class for a species list //! //! Manage the labels, id and the size of a species list. //! //! \ingroup database_species class SPECMICP_DLL_PUBLIC SpeciesList { public: //! \brief An empty list SpeciesList(): m_is_valid(false) {} //! \brief Initalise a list with 'size' species SpeciesList(index_t size): m_is_valid(false), m_size(size), m_labels(size), m_hashes(size) {} virtual ~SpeciesList() = default; //! \name Size //! \brief Manage the size of the list // --------------- //! @{ //! \brief Return the number of species in the list index_t size() const {return m_size;} //! \brief Reset the number of species in the list virtual void resize(index_t size) { m_size = size; m_labels.resize(size); m_hashes.resize(size); set_nonvalid(); } //! @} //! \name Getter //! \brief Return values // ------- //! @{ //! \brief Return the label of species const std::string& get_label(index_t ind) const { specmicp_assert(ind < m_size); return m_labels[ind]; } //! \brief Return the index of a species from the label //! \return the index of the species or -1 if the species does not exist index_t get_id(const std::string& label) const; //! \brief to iterate over the elements range_t range() const { return range_t(m_size); } //! \brief Return true if the list is valid //! //! The validity flag is automatically turned off when rsize, move_erase or move_erase_to is use. //! The user must turn it on again by using the set_valid member //! //! \sa set_valid //! \sa set_nonvalid bool is_valid() const noexcept { return m_is_valid; } //! \brief Return a hash of the list size_t get_hash() const; //! @} //! \name Setter //! \brief Set values // ------ //! @{ //! \brief Set the label of species 'ind' void set_label(index_t ind, const std::string& label); //! \brief Set the label of species 'ind' void set_label(index_t ind, std::string&& label); //! \brief Set the list to be nonvalid //! \sa is_valid //! \sa set_valid void set_nonvalid() noexcept {m_is_valid = false;} //! \brief Set the list to be valid //! \sa is_valid //! \sa set_nonvalid SPECMICP_DLL_LOCAL void set_valid() {m_is_valid = true;} //! \brief Erase values at 'ind' void reset(index_t ind) { m_labels[ind] = ""; m_hashes[ind] = 0; } //! @} //! \name Move species //! \brief Move species in the list or to another list // ------------- //! @{ //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' virtual void move_erase(index_t old_ind, index_t new_ind) { set_nonvalid(); m_labels[new_ind] = m_labels[old_ind]; m_hashes[new_ind] = m_hashes[old_ind]; } //! \brief move 'ind' to 'other' at 'other_ind' void move_erase_to(index_t ind, SpeciesList& other, index_t other_ind) { set_nonvalid(); other.set_nonvalid(); other.set_label(other_ind, std::move(get_label(ind))); reset(ind); } //! @} private: using hash_result_type = std::hash::result_type; //!< Result of the hash function bool m_is_valid; index_t m_size; //!< Size of the list std::vector m_labels; //!< Labels std::vector m_hashes; //!< List of hashes }; //! \class ReactiveSpeciesList //! \brief A list of reactive species //! //! This list extends 'SpeciesList' and add the managements of //! stoichiometric coefficients and equilibrium constant. //! \ingroup database_species class SPECMICP_DLL_PUBLIC ReactiveSpeciesList: public SpeciesList { public: //! \brief Initialize an empty list ReactiveSpeciesList() {} //! \brief Initialize a list of size 'size' with 'nb_components' components ReactiveSpeciesList(index_t size, index_t nb_components): SpeciesList(size), m_nu_coeffs(size, nb_components), m_log_k(size) {} virtual ~ReactiveSpeciesList() = default; //! \name Size //! \brief Manage the size of the list // ----------- //! @{ //! \brief Resize void resize(index_t size) override { m_nu_coeffs.resize(size); m_log_k.resize(size); SpeciesList::resize(size); } //! \brief Resize the list and the number of components virtual void resize(index_t size, index_t nb_components) { m_nu_coeffs.resize(size, nb_components); m_log_k.resize(size); SpeciesList::resize(size); } //! \brief Return the number of components index_t nb_components() { return m_nu_coeffs.cols(); } //! @} //! \name Getter //! \brief Return values // ------ //! @{ //! \brief Return a const reference to the logk vector const Vector& get_logk_vector() const { return m_log_k.get_vector(); } //! \brief Return a const reference to the stoichiometric matrix const Matrix& get_nu_matrix() const { return m_nu_coeffs.get_matrix(); } //! \brief Return a const reference to a row of the stoichiometric coefficient matrix Eigen::MatrixBase::ConstRowXpr get_nu_row(index_t k) const { return m_nu_coeffs.get_row(k); } //! \brief Return the logK of species 'j' const scalar_t& logk(index_t j) const { return m_log_k(j); } //! \brief Return the stoichiometric coefficient of species j and component i const scalar_t& nu_ji(index_t j, index_t i) const { return m_nu_coeffs(j, i); } //! @} //! \name Setter //! \brief Set the values of the parameters // ---------- //! @{ //! \brief set a logk void set_logk(index_t j, scalar_t value) { m_log_k.set_value(j, value); } //! \brief Set the logk vector template void set_logk_vector(const Eigen::MatrixBase& vector) { specmicp_assert(vector.rows() == m_log_k.size()); m_log_k.set_vector(vector); } //! \brief Set the stoehiometric coefficient of species 'j' and component 'i' to 'value' void set_nu_ji(index_t j, index_t i, scalar_t value) { m_nu_coeffs.set_value(j, i, value); } //! \brief Set the stoichiometric coefficient template void set_nu_matrix(const Eigen::MatrixBase& matrix) { specmicp_assert(matrix.rows() == size()); m_nu_coeffs.set_matrix(matrix); } //! \brief Switch the basis //! //! Reference : Bethke2008 template void SPECMICP_DLL_LOCAL switch_basis( const Eigen::MatrixBase& transform, const Eigen::MatrixBase& kswap) { m_nu_coeffs.multiply_by(transform); m_log_k.add(-get_nu_matrix()*kswap); } //! \brief Reset a row of the stoichiometric coefficient matrix void reset_nu_row(index_t k) { m_nu_coeffs.reset_row(k); } //! @} //! \name Adding species //! \brief 'Add' one species to the other //! Replace an aqueous species by its decomposition into components. //! This is typically use during the canonicalization of the database // -------------- //! @{ //! \brief Add the species 'species_to_add' to 'k' void add_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { add_nu_species_to(k, species_to_add, coeff); add_logk_species_to(k, species_to_add, coeff); } //! \brief Add the species 'species_to_add' from 'other' to 'k' void add_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { add_nu_alien_species_to(k, other, species_to_add, coeff); add_logk_alien_species_to(k, other, species_to_add, coeff); } //! @} //! \name Move operations //! \brief Move species in the list or to other list // ----- //! @{ //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_nu_coeffs.move_erase(old_ind, new_ind); m_log_k.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' //! //! This is the method that need to be used to remove components in the database. virtual void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) { m_nu_coeffs.move_erase(old_ind, new_ind, is_reactants_to_remove); m_log_k.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } //! \brief Move species 'ind' to the list 'other' at 'other_ind' void move_erase_to(index_t ind, ReactiveSpeciesList& other, index_t other_ind); //! @} private: // methods //! \brief Add the logk of 'species_to_add' in 'other' at species 'k' void SPECMICP_DLL_LOCAL add_logk_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { auto tmp = m_log_k(k) + coeff*other.m_log_k(species_to_add); m_log_k.set_value(k, tmp); } //! \brief Add the logk of species_to_add at species 'k' void SPECMICP_DLL_LOCAL add_logk_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { auto tmp = m_log_k(k) + coeff*m_log_k(species_to_add); m_log_k.set_value(k, tmp); } //! \brief Add the stoichiometric coefficient of species_to_add at species 'k' void SPECMICP_DLL_LOCAL add_nu_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { m_nu_coeffs.add_to_row(k, coeff*other.m_nu_coeffs.get_row(species_to_add)); } //! \brief Add the stoichiometric coefficient of species_to_add at species 'k' void SPECMICP_DLL_LOCAL add_nu_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { m_nu_coeffs.add_to_row(k, coeff*m_nu_coeffs.get_row(species_to_add)); } private: // attributes MatrixSpeciesWrapper m_nu_coeffs; //!< The stoichiometric coefficients VectorSpeciesWrapper m_log_k; //!< The logk values }; } // end namespace database } // end namespace specmicp namespace std { template <> struct hash { size_t operator ()(const specmicp::database::SpeciesList& alist) {return alist.get_hash();} }; } //end namespace std #endif // SPECMICP_DATABASE_SPECIES_HPP diff --git a/src/database/switch_basis.cpp b/src/database/switch_basis.cpp index 4314add..b8f7d5f 100644 --- a/src/database/switch_basis.cpp +++ b/src/database/switch_basis.cpp @@ -1,145 +1,147 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "switch_basis.hpp" #include #include namespace specmicp { namespace database { index_t BasisSwitcher::get_true_aqueous_index(index_t ind) { return ind - data->nb_component(); } void BasisSwitcher::swap_components(const std::map& swap_to_make) { std::vector id_swap; id_swap.reserve(data->nb_component()); for (index_t i: data->range_component()) { id_swap.push_back(i); } for (const auto& it: swap_to_make) { if (it.first == water_label) { throw std::invalid_argument("Basis switch : water cannot be swapped from basis"); } if (it.first == electron_label) { throw std::invalid_argument("Basis switch : electron cannot be swapped from basis"); } const index_t idc = safe_component_label_to_id(it.first); const index_t idaq = data->nb_component() + safe_aqueous_label_to_id(it.second); id_swap[idc] = idaq; } switch_basis(id_swap); } void BasisSwitcher::switch_basis(std::vector& new_basis) { Eigen::MatrixXd beta = Eigen::MatrixXd::Zero( data->nb_component(), data->nb_component()); Eigen::VectorXd kswap(data->nb_component()); // swap coefficients, build beta matrix and kswap for (index_t i: data->range_component()) { if (new_basis[i] >= data->nb_component()) { index_t j = get_true_aqueous_index(new_basis[i]); beta.row(i).segment(0, data->nb_component()) = data->aqueous.get_nu_row(j); data->aqueous.reset_nu_row(j); data->aqueous.set_nu_ji(j, i, 1.0); kswap(i) = data->logk_aqueous(j); data->aqueous.set_logk(j, 0.0); } else { beta(i, i) = 1.0; kswap(i) = 0.0; } } Matrix betainv = beta.inverse(); data->components.molar_mass_transform(beta); data->aqueous.switch_basis(betainv, kswap); swap_aq_param(new_basis); swap_labels(new_basis); // now do the minerals data->minerals.switch_basis(betainv, kswap); data->minerals_kinetic.switch_basis(betainv, kswap); // and the gases if (data->nb_gas() > 0) { data->gas.switch_basis(betainv, kswap); } // and sorbed species if (data->nb_sorbed() > 0) { data->sorbed.switch_basis(betainv, kswap); } if (data->nb_compounds() > 0) { data->compounds.switch_basis(betainv, kswap); } } void BasisSwitcher::swap_aq_param(std::vector& new_basis) { for (index_t i: data->range_component()) { if(new_basis[i] >= data->nb_component()) { const index_t j = get_true_aqueous_index(new_basis[i]); const auto tmp = data->components.ionic_values(i); data->components.set_ionic_values(i, data->aqueous.ionic_values(j)); data->aqueous.set_ionic_values(j, tmp); } } } void BasisSwitcher::swap_labels(std::vector& new_basis) { for (index_t i: data->range_component()) { if (new_basis[i] >= data->nb_component()) { const index_t j = get_true_aqueous_index(new_basis[i]); const auto tmp = data->components.get_label(i); data->components.set_label(i, data->aqueous.get_label(j)); data->aqueous.set_label(j, tmp); } } } } // end namespace database } // end namespace specmicp diff --git a/src/database/switch_basis.hpp b/src/database/switch_basis.hpp index c99f2f7..074a869 100644 --- a/src/database/switch_basis.hpp +++ b/src/database/switch_basis.hpp @@ -1,82 +1,84 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_SWITCHBASIS_HPP #define SPECMICP_DATABASE_SWITCHBASIS_HPP //! \file switch_basis.hpp //! \brief Switch the basis #include "module.hpp" #include namespace specmicp { namespace database { //! \brief Use this class to switch the basis of the database class BasisSwitcher: public DatabaseModule { public: BasisSwitcher(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Switch the basis //! //! \param new_basis list of id of the new basis //! //! The new basis is a list of id, id = id_component for no swapping //! or id = id_aqueous + nb_component for swapping a secondary species //! //! \sa swap_components void switch_basis(std::vector& new_basis); //! \brief Swap components //! //! \param swap_to_make is a map where the keys are the components to swap and the values the id of the aqueous to put in the database void swap_components(const std::map& swap_to_make); private: //! \brief Return the true aqueous index index_t get_true_aqueous_index(index_t ind); //! \brief Swap aqueous parameters during a basis transformation void swap_aq_param(std::vector& new_basis); //! \brief Swap labels - called during a basis transformation void swap_labels(std::vector& new_basis); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SWITCHBASIS_HPP diff --git a/src/database/unknown_class.cpp b/src/database/unknown_class.cpp index b04684c..8749347 100644 --- a/src/database/unknown_class.cpp +++ b/src/database/unknown_class.cpp @@ -1,170 +1,172 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "unknown_class.hpp" #include "data_container.hpp" #include "errors.hpp" namespace specmicp { namespace database { AqueousSpeciesClass find_aqueous_species_class(const RawDatabasePtr& data, const std::string& label) { if (data->get_id_component(label) != no_species) { return AqueousSpeciesClass::Component; } else if (data->get_id_aqueous(label) != no_species) { return AqueousSpeciesClass::Aqueous; } else if (data->get_id_compound(label) != no_species) { return AqueousSpeciesClass::Compound; } else { return AqueousSpeciesClass::Invalid; } } GenericAqueousSpecies find_aqueous_species(const RawDatabasePtr& data, const std::string& label) { index_t ida = data->get_id_component(label); if (ida != no_species) { return {AqueousSpeciesClass::Component, ida}; } ida = data->get_id_aqueous(label); if (ida != no_species) { return {AqueousSpeciesClass::Aqueous, ida}; } ida = data->get_id_compound(label); if (ida != no_species) { return {AqueousSpeciesClass::Compound, ida}; } return {AqueousSpeciesClass::Invalid, no_species}; } scalar_t molar_mass_aqueous(const RawDatabasePtr& data, const std::string& label) { GenericAqueousSpecies ida = find_aqueous_species(data, label); scalar_t molar_mass {-1}; switch (ida.type) { case AqueousSpeciesClass::Component: molar_mass = data->molar_mass_basis(ida.id); break; case AqueousSpeciesClass::Aqueous: molar_mass = data->molar_mass_aqueous(ida.id); break; case AqueousSpeciesClass::Compound: molar_mass = data->molar_mass_compound(ida.id); break; default: throw InvalidGenericAqueousSpecies(label); } return molar_mass; } SolidPhaseClass find_solid_phase_class(const RawDatabasePtr& data, const std::string& label) { if (data->get_id_mineral(label) != no_species) { return SolidPhaseClass::EquilibriumMineral; } else if (data->get_id_mineral_kinetic(label) != no_species) { return SolidPhaseClass::MineralKinetics; } else return SolidPhaseClass::Invalid; } GenericSolidPhase find_solid_phase(const RawDatabasePtr& data, const std::string& label) { index_t ids = data->get_id_mineral(label); if (ids != no_species) { return {SolidPhaseClass::EquilibriumMineral, ids}; } ids = data->get_id_mineral_kinetic(label); if (ids != no_species) { return {SolidPhaseClass::MineralKinetics, ids}; } else return {SolidPhaseClass::Invalid, no_species}; } scalar_t molar_mass_solid_phase(const RawDatabasePtr& data, const std::string& label) { GenericSolidPhase ids = find_solid_phase(data, label); scalar_t molar_mass = -1; switch (ids.type) { case SolidPhaseClass::EquilibriumMineral: molar_mass = data->molar_mass_mineral(ids.id); break; case SolidPhaseClass::MineralKinetics: molar_mass = data->molar_mass_mineral_kinetic(ids.id); break; default: throw InvalidSolidPhase(label); break; } return molar_mass; } scalar_t molar_volume_solid_phase(const RawDatabasePtr& data, const std::string& label) { GenericSolidPhase ids = find_solid_phase(data, label); scalar_t molar_volume = -1; switch (ids.type) { case SolidPhaseClass::EquilibriumMineral: molar_volume = data->molar_volume_mineral(ids.id); break; case SolidPhaseClass::MineralKinetics: molar_volume = data->molar_volume_mineral_kinetic(ids.id); break; default: throw InvalidSolidPhase(label); break; } return molar_volume; } } //end namespace database } //end namespace specmicp diff --git a/src/database/unknown_class.hpp b/src/database/unknown_class.hpp index b8f79dc..04bb147 100644 --- a/src/database/unknown_class.hpp +++ b/src/database/unknown_class.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_UNKNOWNCLASS_HPP #define SPECMICP_DATABASE_UNKNOWNCLASS_HPP //! \file unknown_class.hpp //! \brief Find properties of species in an unknow class #include "../types.hpp" #include "database_fwd.hpp" namespace specmicp { namespace database { //! \brief Class of an aqueous species enum class AqueousSpeciesClass { Component, //!< The aqeuous species is in the basis Aqueous, //!< The aqueous species is a secondary species Compound, //!< The aqueous is a species is a compound Invalid //!< This is not an aqueous species }; //! \brief Identification of a generic aqueous species struct GenericAqueousSpecies { AqueousSpeciesClass type; //!< The class of the aqueous species index_t id; //!< Its id in the database }; //! \brief Return the class of an aqueous species AqueousSpeciesClass SPECMICP_DLL_PUBLIC find_aqueous_species_class(const RawDatabasePtr& data, const std::string& label); //! \brief Find an aqueous species in the database GenericAqueousSpecies SPECMICP_DLL_PUBLIC find_aqueous_species(const RawDatabasePtr& data, const std::string& label); //! \brief Return the molar class of an aqueous of unknown class scalar_t SPECMICP_DLL_PUBLIC molar_mass_aqueous(const RawDatabasePtr& data, const std::string& label); //! \brief Class of a solid phase enum class SolidPhaseClass { EquilibriumMineral, //!< Solid phase at equilibrium MineralKinetics, //!< Solid phase governed by kinetics Invalid //!< Invalid solid phase }; //! \brief Identification of a generic solid phase struct GenericSolidPhase { SolidPhaseClass type; //!< The class of the solid phase index_t id; //!< Its id in the database }; //! \brief Return the class of an solid phase SolidPhaseClass SPECMICP_DLL_PUBLIC find_solid_phase_class(const RawDatabasePtr& data, const std::string& label); //! \brief Find a solid phase in the database GenericSolidPhase SPECMICP_DLL_PUBLIC find_solid_phase(const RawDatabasePtr& data, const std::string& label); //! \brief Return the molar mass (in SI units) of a solid phase scalar_t SPECMICP_DLL_PUBLIC molar_mass_solid_phase(const RawDatabasePtr& data, const std::string& label); //! \brief Return the molar volume (in SI units) of a solid phase scalar_t SPECMICP_DLL_PUBLIC molar_volume_solid_phase(const RawDatabasePtr& data, const std::string& label); } //end namespace database } //end namespace specmicp #endif // SPECMICP_DATABASE_UNKNOWNCLASS_HPP diff --git a/src/database/yaml_reader.cpp b/src/database/yaml_reader.cpp index d88c204..a9c05bf 100644 --- a/src/database/yaml_reader.cpp +++ b/src/database/yaml_reader.cpp @@ -1,744 +1,746 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "yaml_reader.hpp" #include "reader_common.hpp" #include "section_name.hpp" #include #include "../utils/io/yaml.hpp" #include #include "../utils/log.hpp" #include "../utils/compat.hpp" #include "config_database.hpp" #include namespace specmicp { namespace database { struct DataReaderYaml::DataReaderYamlElementData { bool check_compo {true}; std::vector components; bool is_init {false}; }; DataReaderYaml::DataReaderYaml(): m_elem_data(make_unique()) {} DataReaderYaml::~DataReaderYaml() = default; //! \brief Constructor DataReaderYaml::DataReaderYaml(RawDatabasePtr data, bool check_compo): DatabaseModule(data), m_elem_data(make_unique()) { m_elem_data->check_compo = check_compo; } //! \brief Constructor //! //! @param filepath string containing the path to the database DataReaderYaml::DataReaderYaml(const std::string& filepath, bool check_compo): DatabaseModule(), m_elem_data(make_unique()) { m_elem_data->check_compo = check_compo; parse(filepath); } //! \brief Constructor //! //! @param input input stream that contains the database DataReaderYaml::DataReaderYaml(std::istream& input, bool check_compo): DatabaseModule(), m_elem_data(make_unique()) { m_elem_data->check_compo = check_compo; parse(input); } // safe access to values 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 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 DataReaderYaml::parse(std::istream& input ) { const YAML::Node root = io::parse_yaml(input); const char* indb_main = INDB_MAIN; io::check_mandatory_yaml_node(root, INDB_SECTION_METADATA, indb_main); parse_metadata(root[INDB_SECTION_METADATA]); // 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; parse_elements(root[INDB_SECTION_ELEMENTS], elements); data->elements = std::move(elements); // Aqueous species // --------------- 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 // -------- 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[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[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[INDB_SECTION_COMPOUNDS]) parse_compounds(root[INDB_SECTION_COMPOUNDS], clist); else clist.set_valid(); data->compounds = std::move(clist); } void DataReaderYaml::parse_metadata(const YAML::Node& root) { 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); m_elem_data->check_compo = io::get_yaml_optional(root, INDB_ATTRIBUTE_CHECKCOMPO, INDB_SECTION_METADATA, m_elem_data->check_compo); } void DataReaderYaml::init_elemental_composition() { if (m_elem_data->is_init) return; m_elem_data->components.reserve(data->nb_component()); // Parse label to find elemental composition for (auto id: data->range_component()) { element_map elem_compo; element_composition_from_label(data->get_label_component(id), elem_compo); m_elem_data->components.emplace_back(elem_compo); } m_elem_data->is_init = true; } 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[-]."); } 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[INDB_ATTRIBUTE_ACTIVITY]) { 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); } // molar mass values.molar_mass = io::get_yaml_mandatory( species, INDB_ATTRIBUTE_MOLARMASS, label); data->components.set_values(id_in_db, std::move(values)); } if (m_elem_data->check_compo) init_elemental_composition(); // after this the basis is ready to use data->components.set_valid(); } 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()) { const YAML::Node& species = aqueous[static_cast(id)]; AqueousValues values; values.label = obtain_label(species, INDB_SECTION_AQUEOUS); values.ionic_values.charge = charge_from_label(values.label); if (species[INDB_ATTRIBUTE_ACTIVITY]) { 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.label); alist.set_values(id, values); // equation std::map 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)) > EPS_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); } // check composition if (m_elem_data->check_compo) { if (species[INDB_ATTRIBUTE_FORMULA]) check_composition(species[INDB_ATTRIBUTE_FORMULA].as(), alist, id); else check_composition(alist.get_label(id), alist, id); } } // valid set of aqueous species alist.set_valid(); } 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)]; //check if material is at equilibrium or governed by kinetics MineralValue value; value.label = 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, value); // equation // -------- std::map 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) > EPS_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); } // check composition if (m_elem_data->check_compo) { if (species[INDB_ATTRIBUTE_FORMULA]) check_composition(species[INDB_ATTRIBUTE_FORMULA].as(), mlist, true_id); else check_composition(mlist.get_label(true_id), mlist, true_id); } // 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 DataReaderYaml::parse_gas(const YAML::Node& gas, GasList& glist) { DEBUG << "Parse gas"; glist = GasList(gas.size(), data->nb_component()); for (auto id: glist.range()) { const YAML::Node& species = gas[static_cast(id)]; GasValues values; 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.label); glist.set_values(id, values); // equation std::map 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) > EPS_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); } // check composition if (m_elem_data->check_compo) { if (species[INDB_ATTRIBUTE_FORMULA]) check_composition(species[INDB_ATTRIBUTE_FORMULA].as(), glist, id); else check_composition(glist.get_label(id), glist, id); } } glist.set_valid(); } 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()) { const YAML::Node& species = sorbed[static_cast(id)]; SorbedValues values; 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, 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, values); std::map 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) > EPS_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 DataReaderYaml::parse_compounds(const YAML::Node& compounds, CompoundList &clist) { DEBUG << "Parse compounds"; clist = CompoundList(compounds.size(), data->nb_component()); for (auto id: clist.range()) { const YAML::Node& species = compounds[static_cast(id)]; 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, 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) > EPS_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); } // check composition if (m_elem_data->check_compo) { if (species[INDB_ATTRIBUTE_FORMULA]) check_composition(species[INDB_ATTRIBUTE_FORMULA].as(), clist, id); else check_composition(clist.get_label(id), clist, id); } } clist.set_valid(); } void check_element_map(const element_map& formula, const element_map& composition, const std::string& label); void DataReaderYaml::check_composition(const std::string& formula, ReactiveSpeciesList& rlist, index_t id) { if (not m_elem_data->is_init) init_elemental_composition(); // parse the formula element_map compo_from_label; element_composition_from_label(formula, compo_from_label); // parse the composition element_map compo_from_compo; for (auto idc: data->range_component()) { if (rlist.nu_ji(id, idc) == 0.0) continue; add_to_element_map(compo_from_compo, m_elem_data->components[idc], rlist.nu_ji(id, idc) ); } // clean the composition for (auto it=compo_from_compo.begin(); it!=compo_from_compo.end(); ) { if (it->first == "E" or it->second == 0.0) it = compo_from_compo.erase(it); else ++it; } // check that both map are equal check_element_map(compo_from_label, compo_from_compo, rlist.get_label(id)); } void check_element_map(const element_map& formula, const element_map& composition, const std::string& label) { for (const auto& it1: formula) { const auto it2 = composition.find(it1.first); if (it2 == composition.cend()) { throw db_invalid_data("Species '"+label+"' : element '"+ it1.first+"' is in the formula but not in the composition"); } if (std::abs(it1.second - it2->second) > EPS_TEST_COMPOSITION) { throw db_invalid_data("Species '"+label+"' : element '"+ it1.first+"' has a different stoichiometry in the formula ("+ std::to_string(it1.second)+ ") than in the composition ("+ std::to_string(it2->second)+")."); } } for (const auto& it1: composition) { const auto it2 = formula.find(it1.first); if (it2 == composition.cend()) { throw db_invalid_data("Species '"+label+"' : element '"+ it1.first+"' is in the composition but not in the formula"); } } } void DataReaderYaml::parse_elements(const YAML::Node& elements, ElementList &elist) { if (elements.size() != static_cast(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()) { const YAML::Node& elem = elements[static_cast(id)]; 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); } } std::string obtain_label(const YAML::Node& species, const std::string& section) { return io::get_yaml_mandatory(species, INDB_ATTRIBUTE_LABEL, section); } void obtain_composition(const YAML::Node& species, std::map& compo, const std::string& label) { const std::string compo_string = io::get_yaml_mandatory(species, INDB_ATTRIBUTE_COMPOSITION, label); parse_equation(compo_string, compo); } scalar_t obtain_logk(const YAML::Node& species, const std::string& label) { return io::get_yaml_mandatory(species, INDB_ATTRIBUTE_LOGK, label); } bool is_kinetic(const YAML::Node& species, const std::string& label) { return io::get_yaml_optional(species, INDB_ATTRIBUTE_FLAG_KINETIC, label, false); } } //end namespace database } //end namespace specmicp diff --git a/src/database/yaml_reader.hpp b/src/database/yaml_reader.hpp index 237bf8e..d41f5f5 100644 --- a/src/database/yaml_reader.hpp +++ b/src/database/yaml_reader.hpp @@ -1,132 +1,134 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPEMCICP_DATABASE_YAMLREADER_HPP #define SPEMCICP_DATABASE_YAMLREADER_HPP //! \file database/yaml_reader.hpp //! \brief A reader for a database in yaml format #include "module.hpp" namespace YAML { class Node; } namespace specmicp { namespace database { class SPECMICP_DLL_LOCAL DataReaderYaml: public DatabaseModule { public: //! \brief Empty constructor DataReaderYaml(); ~DataReaderYaml(); //! \brief Constructor DataReaderYaml(RawDatabasePtr data, bool check_compo=true); //! \brief Constructor //! //! @param filepath string containing the path to the database DataReaderYaml(const std::string& filepath, bool check_compo=true); //! \brief Constructor //! //! @param input input stream that contains the database DataReaderYaml(std::istream& input, bool check_compo=true); //! Return the databes RawDatabasePtr get_database() {return data;} //! \brief Parse the basis section //! //! Contains the list of primary species void parse_basis(const YAML::Node& basis_root); //! \brief Parse the aqueous section //! //! Contains the list of secondary species void parse_aqueous(const YAML::Node& aqueous_root, AqueousList& alist); //! \brief Parse the mineral section //! //! Contains the list of minerals void parse_minerals( const YAML::Node& minerals, MineralList &minerals_list, MineralList &minerals_kinetic_list ); //! \brief Parse the gas section void parse_gas(const YAML::Node& gas_root, GasList& glist); //! \brief Parse the sorbed species section void parse_sorbed(const YAML::Node& sorbed_root, SorbedList& slist); //! \brief Parse the compounds void parse_compounds(const YAML::Node& compounds, CompoundList& clist); //! \brief Parse the elements 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(const YAML::Node& root); //! \brief Initialize the data to check the composition void init_elemental_composition(); //! \brief Check initial composition //! //! \throw db_invalid_data if the composition is not consistent with the formula void check_composition(const std::string& formula, ReactiveSpeciesList& rlist, index_t id); DataReaderYaml(const DataReaderYaml&) = delete; DataReaderYaml& operator =(const DataReaderYaml&) = delete; struct DataReaderYamlElementData; std::unique_ptr m_elem_data; }; } //end namespace database } //end namespace specmicp #endif // SPEMCICP_DATABASE_YAMLREADER_HPP diff --git a/src/database/yaml_writer.cpp b/src/database/yaml_writer.cpp index ceee719..bdcee0a 100644 --- a/src/database/yaml_writer.cpp +++ b/src/database/yaml_writer.cpp @@ -1,311 +1,313 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "yaml_writer.hpp" #include #include "../utils/io/yaml.hpp" #include "section_name.hpp" #include "../utils/dateandtime.hpp" #include "../utils/io/format.hpp" #include namespace specmicp { namespace database { std::string format_equation( index_t species, const ReactiveSpeciesList& slist, const ComponentList& basis ); void DatabaseWriterYaml::write(const std::string& filename) { YAML::Emitter root; io::configure_yaml_emitter(root); //auto& format = io::FormatInformation::get_format(); set_yaml_tree(root); io::save_yaml(filename, root); } void DatabaseWriterYaml::set_yaml_tree(YAML::Emitter& root) { root << YAML::Comment("This database was generated automatically by SpecMiCP"); root << YAML::BeginMap; set_metadata(root); set_elements(root); set_basis(root); set_aqueous(root); set_minerals(root); set_gas(root); set_sorbed(root); set_compound(root); root << YAML::EndMap; } void DatabaseWriterYaml::set_metadata(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_METADATA << YAML::Key; root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_NAME << YAML::Value << data->metadata.name; root << YAML::Key << INDB_ATTRIBUTE_VERSION << YAML::Value << dateandtime::now(); root << YAML::Key << INDB_ATTRIBUTE_PATH << YAML::Value << "N/A"; root << YAML::EndMap; } void DatabaseWriterYaml::set_basis(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_BASIS << YAML::Key; root << YAML::BeginSeq; for (auto id: data->range_component()) { set_component(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_component(index_t component, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << data->get_label_component(component); root << YAML::Key << INDB_ATTRIBUTE_MOLARMASS << YAML::Value << data->molar_mass_basis(component, units::MassUnit::gram); if (component >= 2) { root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY << YAML::Value; root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY_A << YAML::Value << data->a_debye_component(component); root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY_B << YAML::Value << data->b_debye_component(component); root << YAML::EndMap; } root << YAML::EndMap; } void DatabaseWriterYaml::set_elements(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_ELEMENTS << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_component()) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_ELEMENT << YAML::Value << YAML::DoubleQuoted << data->elements.get_label_element(id); root << YAML::Key << INDB_ATTRIBUTE_COMPONENT << YAML::Value << data->get_label_component(id); root << YAML::EndMap; } root << YAML::EndSeq; } void DatabaseWriterYaml::set_aqueous(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_AQUEOUS << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_aqueous()) { set_aqueous_species(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_aqueous_species(index_t aqueous, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_aqueous(aqueous); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::Value << YAML::DoubleQuoted << format_equation(aqueous, data->aqueous, data->components); root << YAML::Key << INDB_ATTRIBUTE_LOGK << YAML::Value << data->logk_aqueous(aqueous); root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY << YAML::Value; root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY_A << YAML::Value << data->a_debye_aqueous(aqueous); root << YAML::Key << INDB_ATTRIBUTE_ACTIVITY_B << YAML::Value << data->b_debye_aqueous(aqueous); root << YAML::EndMap; root << YAML::EndMap; } void DatabaseWriterYaml::set_minerals(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_MINERALS << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_mineral()) { set_mineral(id, root); } for (auto id: data->range_mineral_kinetic()) { set_mineral_kinetic(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_mineral(index_t mineral, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_mineral(mineral); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::Value << YAML::DoubleQuoted << format_equation(mineral, data->minerals, data->components) ; root << YAML::Key << INDB_ATTRIBUTE_LOGK << YAML::Value << data->logk_mineral(mineral); if (data->unsafe_molar_volume_mineral(mineral) > 0) { root << YAML::Key << INDB_ATTRIBUTE_MOLARVOLUME << YAML::Value << data->molar_volume_mineral(mineral, units::LengthUnit::centimeter); } root << YAML::EndMap; } void DatabaseWriterYaml::set_mineral_kinetic(index_t mineral, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_mineral_kinetic(mineral); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::Value << YAML::DoubleQuoted << format_equation(mineral, data->minerals_kinetic, data->components) ; root << YAML::Key << INDB_ATTRIBUTE_LOGK << YAML::Value << data->logk_mineral_kinetic(mineral); if (data->unsafe_molar_volume_mineral_kinetic(mineral) > 0) { root << YAML::Key << INDB_ATTRIBUTE_MOLARVOLUME << YAML::Value << data->molar_volume_mineral_kinetic(mineral, units::LengthUnit::centimeter); } root << YAML::Key << INDB_ATTRIBUTE_FLAG_KINETIC << YAML::Value << true; root << YAML::EndMap; } void DatabaseWriterYaml::set_gas(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_GAS << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_gas()) { set_gas_phase(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_gas_phase(index_t gas, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_gas(gas); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::Value << YAML::DoubleQuoted << format_equation(gas, data->gas, data->components); root << YAML::Key << INDB_ATTRIBUTE_LOGK << YAML::Value << data->logk_gas(gas); root << YAML::EndMap; } void DatabaseWriterYaml::set_sorbed(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_SORBED << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_sorbed()) { set_sorbed_species(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_sorbed_species(index_t sorbed, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_sorbed(sorbed); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::DoubleQuoted << YAML::Value << format_equation(sorbed, data->sorbed, data->components); root << YAML::Key << INDB_ATTRIBUTE_NBSITEOCCUPIED << YAML::Value << data->nb_sorption_sites(sorbed); root << YAML::Key << INDB_ATTRIBUTE_LOGK << YAML::Value << data->logk_sorbed(sorbed); root << YAML::EndMap; } void DatabaseWriterYaml::set_compound(YAML::Emitter& root) { root << YAML::Key << INDB_SECTION_COMPOUNDS << YAML::Value; root << YAML::BeginSeq; for (auto id: data->range_compounds()) { set_compound_species(id, root); } root << YAML::EndSeq; } void DatabaseWriterYaml::set_compound_species(index_t compound, YAML::Emitter& root) { root << YAML::BeginMap; root << YAML::Key << INDB_ATTRIBUTE_LABEL << YAML::Value << YAML::DoubleQuoted << data->get_label_compound(compound); root << YAML::Key << INDB_ATTRIBUTE_COMPOSITION << YAML::DoubleQuoted << YAML::Value << format_equation(compound, data->compounds, data->components); root << YAML::EndMap; } std::string format_equation(index_t species, const ReactiveSpeciesList& slist, const ComponentList& basis) { std::ostringstream equation; const io::FormatInformation& formatter = io::FormatInformation::get_format(); for (index_t component: basis.range()) { if (slist.nu_ji(species, component) != 0) { if (slist.nu_ji(species, component) == 1.0) { equation << basis.get_label(component) << ", "; } else if (slist.nu_ji(species, component) == -1.0) { equation << "- " << basis.get_label(component) << ", "; } else { formatter.format_stoichiometric_coefficient(equation, slist.nu_ji(species, component)); equation << " " << basis.get_label(component) << ", "; } } } std::string str_eq = equation.str(); str_eq.erase(str_eq.size()-2, 2); // remove tailing ', ' return str_eq; } } //end namespace database } //end namespace specmicp diff --git a/src/database/yaml_writer.hpp b/src/database/yaml_writer.hpp index 2ec32f1..88c64b4 100644 --- a/src/database/yaml_writer.hpp +++ b/src/database/yaml_writer.hpp @@ -1,92 +1,94 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DATABASE_YAMLWRITER #define SPECMICP_DATABASE_YAMLWRITER //! \file database/yaml_writer.hpp //! \brief Write a database on disk #include "module.hpp" namespace YAML { class Emitter; } //end namespace YAML namespace specmicp { namespace database { //! \brief Write a database in the JSON format //! //! This class can be used to save the database used in a computation. //! It will save the current state of the database class SPECMICP_DLL_LOCAL DatabaseWriterYaml: public DatabaseModule { public: DatabaseWriterYaml(RawDatabasePtr& the_database): DatabaseModule(the_database) {} //! \brief Write the database //! //! \param filepath path to the file where the database will be saved void write(const std::string& filepath); //! \brief Format the database as a YAML::Emitter void set_yaml_tree(YAML::Emitter& root); private: // The following methods set a section of the database void set_metadata(YAML::Emitter& root); void set_basis(YAML::Emitter& root); void set_component(index_t component, YAML::Emitter& root); void set_elements(YAML::Emitter& root); void set_aqueous(YAML::Emitter& root); void set_aqueous_species(index_t aqueous, YAML::Emitter& root); void set_minerals(YAML::Emitter& root); void set_mineral(index_t mineral, YAML::Emitter& root); void set_mineral_kinetic(index_t mineral, YAML::Emitter& root); void set_gas(YAML::Emitter& root); void set_gas_phase(index_t gas, YAML::Emitter& root); void set_sorbed(YAML::Emitter& root); void set_sorbed_species(index_t sorbed, YAML::Emitter& root); void set_compound(YAML::Emitter& root); void set_compound_species(index_t compound, YAML::Emitter& root); }; } //end namespace database } //end namespace specmicp #endif // SPECMICP_DATABASE_YAMLWRITER diff --git a/src/dfpm/1dtransport/diffusion.cpp b/src/dfpm/1dtransport/diffusion.cpp index 844f8ea..f551dcc 100644 --- a/src/dfpm/1dtransport/diffusion.cpp +++ b/src/dfpm/1dtransport/diffusion.cpp @@ -1,226 +1,228 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "diffusion.hpp" #include "diffusion_parameters.hpp" #include "../meshes/mesh1d.hpp" namespace specmicp { namespace dfpm { // SaturatedDiffusion1D:: SaturatedDiffusion1D::SaturatedDiffusion1D( mesh::Mesh1DPtr the_mesh, std::shared_ptr parameters, std::vector list_bcs ): m_tot_ndf(the_mesh->nb_nodes()), m_mesh(the_mesh), m_param(parameters), m_internal_flow(Vector::Zero(m_tot_ndf)), m_external_flow(Vector::Zero(m_tot_ndf)) { number_equations(list_bcs); } void SaturatedDiffusion1D::number_equations(std::vector list_bcs) { m_id_equations = Eigen::VectorXi::Zero(m_tot_ndf); for (auto it=list_bcs.begin(); it!=list_bcs.end(); ++it) { m_id_equations(*it) = no_equation; } index_t neq = 0; for (index_t node: m_mesh->range_nodes()) { if (m_id_equations(node) == no_equation) continue; m_id_equations(node) = neq; ++ neq; } m_neq = neq; } void SaturatedDiffusion1D::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual ) { m_internal_flow.setZero(); residual.resize(get_neq()); residual.setZero(); for (index_t element: m_mesh->range_elements()) { Vector elem_residuals(2); elem_residuals.setZero(); element_residuals(element, displacement, velocity, elem_residuals); for (index_t enode: m_mesh->range_nen()) { if (id_equation(m_mesh->get_node(element, enode)) == no_equation) continue; residual(id_equation(m_mesh->get_node(element, enode))) += elem_residuals(enode); } } } void SaturatedDiffusion1D::element_residuals( index_t element, const Vector& displacement, const Vector& velocity, Vector& elem_residuals ) { Eigen::Matrix jacob; Eigen::Matrix evelocity, edisplacement; scalar_t mass_coeff = -(m_mesh->get_volume_element(element)/2.0); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); //const scalar_t porosity = (m_param->porosity(node_0) + // m_param->porosity(node_1) )/2.0; const scalar_t diff_coeff = 1.0/(0.5/m_param->diffusion_coefficient(node_0) + 0.5/m_param->diffusion_coefficient(node_1)); const index_t dof_0 = node_0; const index_t dof_1 = node_1; scalar_t flux_coeff = -( m_mesh->get_face_area(element) / m_mesh->get_dx(element) // * porosity * diff_coeff ); jacob << 1.0, -1.0, -1.0, 1.0; jacob *= flux_coeff; evelocity << velocity(dof_0)* mass_coeff*m_param->porosity(node_0), velocity(dof_1)* mass_coeff*m_param->porosity(node_1); edisplacement << displacement(dof_0), displacement(dof_1); elem_residuals = jacob*edisplacement; m_internal_flow(dof_0) += elem_residuals(0); m_internal_flow(dof_1) += elem_residuals(1); for (index_t en: m_mesh->range_nen()) { elem_residuals(en) += evelocity(en); elem_residuals(en) += (m_mesh->get_volume_element(element)/2.0 *external_flow(m_mesh->get_node(element, en))); } } void SaturatedDiffusion1D::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { list_triplet_t jacob; const index_t estimation = m_mesh->nb_nodes()*(m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { element_jacobian(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); } void SaturatedDiffusion1D::element_jacobian( index_t element, Vector& displacement, Vector& velocity, list_triplet_t& jacobian, scalar_t alphadt) { Eigen::VectorXd element_residual_orig(Eigen::VectorXd::Zero(2)); element_residuals(element, displacement, velocity, element_residual_orig); for (index_t en: m_mesh->range_nen()) { Eigen::VectorXd element_residual(Eigen::VectorXd::Zero(2)); const index_t node = m_mesh->get_node(element, en); const index_t dof = node; const index_t idc = id_equation(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-4*eps_jacobian) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; element_residuals(element, displacement, velocity, element_residual); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr: m_mesh->range_nen()) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = id_equation(noder); if (idr == no_equation) continue; jacobian.push_back(triplet_t(idr, idc, (element_residual(enr) - element_residual_orig(enr))/h)); } } } void SaturatedDiffusion1D::update_solution(const Vector &update, scalar_t lambda, scalar_t alpha_dt, Vector &predictor, Vector &displacement, Vector &velocity ) { for (index_t node: m_mesh->range_nodes()) { const index_t id = id_equation(node); if (id == no_equation) continue; velocity(node) += lambda*update(id); } displacement = predictor + alpha_dt*velocity; } } // end namespace dfpm } // end namespace specmicp diff --git a/src/dfpm/1dtransport/diffusion.hpp b/src/dfpm/1dtransport/diffusion.hpp index a9106a6..19df098 100644 --- a/src/dfpm/1dtransport/diffusion.hpp +++ b/src/dfpm/1dtransport/diffusion.hpp @@ -1,151 +1,153 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP #define SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP //! \file diffusion.hpp //! \brief A simple diffusion program #include #include "../types.hpp" #include "../types.hpp" #include "../../dfpmsolver/parabolic_program.hpp" #include "../meshes/mesh1dfwd.hpp" namespace specmicp { //! \namespace specmicp::dfpm //! \brief The finite element module namespace dfpm { struct SaturatedDiffusion1DParameters; //! \class SaturatedDiffusion1D //! \brief A saturated diffusion equation //! //! This is an example of a dfpm program //! //! \sa SaturatedDiffusion1DParameters class SPECMICP_DLL_PUBLIC SaturatedDiffusion1D: public dfpmsolver::ParabolicProgram { public: SaturatedDiffusion1D( mesh::Mesh1DPtr the_mesh, std::shared_ptr parameters, std::vector list_bcs ); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return 1;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_id_equations(id_dof);} void element_residuals(index_t element, const Vector& displacement, const Vector& velocity, Vector& element_residual ); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ); //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); void element_jacobian( index_t element, Vector& displacement, Vector& velocity, list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} //! \brief Return the value of the external flow for dof 'id_dof' scalar_t external_flow(index_t id_dof) const {return m_external_flow(id_dof);} //! \brief Return a reference to the value of the external flow for dof 'id_dof' scalar_t& external_flow(index_t id_dof) {return m_external_flow(id_dof);} //! \brief Return a reference to the vector of external flow Vector& external_flow() {return m_external_flow;} private: void SPECMICP_DLL_LOCAL number_equations(std::vector list_bcs); index_t m_tot_ndf; index_t m_neq; Eigen::VectorXi m_id_equations; mesh::Mesh1DPtr m_mesh; std::shared_ptr m_param; Vector m_internal_flow; Vector m_external_flow; }; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP diff --git a/src/dfpm/1dtransport/diffusion_parameters.hpp b/src/dfpm/1dtransport/diffusion_parameters.hpp index cafd7d7..abd68ad 100644 --- a/src/dfpm/1dtransport/diffusion_parameters.hpp +++ b/src/dfpm/1dtransport/diffusion_parameters.hpp @@ -1,60 +1,62 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP #define SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP #include "../../types.hpp" namespace specmicp { namespace dfpm { //! \brief Parameter for the saturated diffusion equation //! //! \sa specmicp::dfpm::SaturatedDiffusion struct SaturatedDiffusion1DParameters { Vector porosity; Vector diffusion_coefficient; SaturatedDiffusion1DParameters(index_t nb_nodes): porosity(nb_nodes), diffusion_coefficient(nb_nodes) {} }; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP diff --git a/src/dfpm/io/configuration.cpp b/src/dfpm/io/configuration.cpp index ef7f533..1853573 100644 --- a/src/dfpm/io/configuration.cpp +++ b/src/dfpm/io/configuration.cpp @@ -1,125 +1,127 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "configuration.hpp" #include "../../utils/io/yaml.hpp" #include "../meshes/generic_mesh1d.hpp" #include "../meshes/axisymmetric_mesh1d.hpp" #include #define S_MESH "mesh" #define S_MESH_A_TYPE "type" #define S_UNIFMESH "uniform_mesh" #define S_UNIFMESH_A_DX "dx" #define S_UNIFMESH_A_NBNODES "nb_nodes" #define S_UNIFMESH_A_SECTION "section" #define S_RAMPMESH "ramp_mesh" #define S_RAMPMESH_A_MIN_DX "min_dx" #define S_RAMPMESH_A_MAX_DX "max_dx" #define S_RAMPMESH_A_RAMP_LENGTH "length_ramp" #define S_RAMPMESH_A_PLATEAU_LENGTH "length_plateau" #define S_RAMPMESH_A_SECTION "section" #define S_UNIFAXISYMESH "uniform_axisymmetric" #define S_UNIFAXISYMESH_A_RADIUS "radius" #define S_UNIFAXISYMESH_A_NBNODES "nb_nodes" #define S_UNIFAXISYMESH_A_HEIGHT "height" #define S_UNIFAXISYMESH_A_DX "dx" namespace specmicp { namespace io { mesh::Mesh1DPtr configure_mesh(const YAML::Node& conf) { check_mandatory_yaml_node(conf, S_MESH, "__main__"); const YAML::Node& subconf = conf[S_MESH]; std::string type = subconf[S_MESH_A_TYPE].as(); if (type == S_UNIFMESH) return configure_uniform_mesh1D(subconf); else if (type == S_RAMPMESH) return configure_ramp_mesh1D(subconf); else if (type == S_UNIFAXISYMESH) return configure_uniform_axisymmetric_mesh1D(subconf); else throw std::invalid_argument("Not a valid type of mesh : '"+type+"'."); } mesh::Mesh1DPtr configure_uniform_mesh1D(const YAML::Node& conf) { check_mandatory_yaml_node(conf, S_UNIFMESH, S_MESH); const YAML::Node& subconf = conf[S_UNIFMESH]; mesh::Uniform1DMeshGeometry geometry; geometry.dx = get_yaml_mandatory(subconf, S_UNIFMESH_A_DX, S_UNIFMESH); geometry.nb_nodes = get_yaml_mandatory(subconf, S_UNIFMESH_A_NBNODES, S_UNIFMESH); geometry.section = get_yaml_mandatory(subconf, S_UNIFMESH_A_SECTION, S_UNIFMESH); return mesh::uniform_mesh1d(geometry); } mesh::Mesh1DPtr configure_ramp_mesh1D(const YAML::Node& conf) { check_mandatory_yaml_node(conf, S_RAMPMESH, S_MESH); const YAML::Node& subconf = conf[S_RAMPMESH]; mesh::Ramp1DMeshGeometry geometry; geometry.dx_min = get_yaml_mandatory(subconf, S_RAMPMESH_A_MIN_DX, S_RAMPMESH); geometry.dx_max = get_yaml_mandatory(subconf, S_RAMPMESH_A_MAX_DX, S_RAMPMESH); geometry.length_ramp = get_yaml_mandatory(subconf, S_RAMPMESH_A_RAMP_LENGTH, S_RAMPMESH); geometry.length_plateau = get_yaml_mandatory(subconf, S_RAMPMESH_A_PLATEAU_LENGTH, S_RAMPMESH); geometry.section = get_yaml_mandatory(subconf, S_RAMPMESH_A_SECTION, S_RAMPMESH); return mesh::ramp_mesh1d(geometry); } mesh::Mesh1DPtr configure_uniform_axisymmetric_mesh1D(const YAML::Node& conf) { const YAML::Node& subconf = conf[S_UNIFAXISYMESH]; mesh::UniformAxisymmetricMesh1DGeometry geometry; geometry.dx = get_yaml_optional(subconf, S_UNIFAXISYMESH_A_DX, S_UNIFAXISYMESH, -1.0); geometry.nb_nodes = get_yaml_optional(subconf, S_UNIFAXISYMESH_A_NBNODES, S_UNIFAXISYMESH, -1); geometry.height = get_yaml_mandatory(subconf, S_UNIFAXISYMESH_A_HEIGHT, S_UNIFAXISYMESH); geometry.radius = get_yaml_mandatory(subconf, S_UNIFAXISYMESH_A_RADIUS, S_UNIFAXISYMESH); return mesh::uniform_axisymmetric_mesh1d(geometry); } } //end namespace io } //end namespace specmicp diff --git a/src/dfpm/io/configuration.hpp b/src/dfpm/io/configuration.hpp index 2a4b4aa..e7e4ea7 100644 --- a/src/dfpm/io/configuration.hpp +++ b/src/dfpm/io/configuration.hpp @@ -1,62 +1,64 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_IO_CONFIGURATION_HPP #define SPECMICP_DFPM_IO_CONFIGURATION_HPP #include "../../macros.hpp" #include "../meshes/mesh1dfwd.hpp" namespace YAML { class Node; } //end namespace YAML namespace specmicp { namespace io { //! \brief Configure the mesh mesh::Mesh1DPtr SPECMICP_DLL_PUBLIC configure_mesh(const YAML::Node& conf); //! \brief Configure an uniform mesh mesh::Mesh1DPtr SPECMICP_DLL_PUBLIC configure_uniform_mesh1D(const YAML::Node& conf); //! \brief Configure a 'ramp' mesh mesh::Mesh1DPtr SPECMICP_DLL_PUBLIC configure_ramp_mesh1D(const YAML::Node& conf); //! \brief Configure an uniform axisymmetric mesh mesh::Mesh1DPtr SPECMICP_DLL_PUBLIC configure_uniform_axisymmetric_mesh1D(const YAML::Node& conf); } //end namespace io } //end namespace specmicp #endif // SPECMICP_DFPM_IO_CONFIGURATION_HPP diff --git a/src/dfpm/io/hdf5_mesh.cpp b/src/dfpm/io/hdf5_mesh.cpp index fb511e2..5c94b57 100644 --- a/src/dfpm/io/hdf5_mesh.cpp +++ b/src/dfpm/io/hdf5_mesh.cpp @@ -1,118 +1,120 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "hdf5_mesh.hpp" #include "../meshes/mesh1d.hpp" #include #include "../../utils/io/specmicp_hdf5.hpp" #include "../../utils/io/hdf5_eigen.hpp" #define COORDINATES_DSET "coordinates" namespace specmicp { namespace io { namespace internal { //! \brief Implementation of mesh saver in HDF5 format //! //! \internal class SPECMICP_DLL_PUBLIC MeshHDF5Saver { public: MeshHDF5Saver(mesh::Mesh1DPtr the_mesh): m_mesh(the_mesh) {} void save_mesh_coordinates( HDF5File& file, const std::string& name, const std::string& section ); private: mesh::Mesh1DPtr m_mesh; }; } //end namespace internal void save_mesh_coordinates( HDF5File& file, const std::string& name, const std::string& section, mesh::Mesh1DPtr the_mesh ) { internal::MeshHDF5Saver saver(the_mesh); saver.save_mesh_coordinates(file, name, section); } // Implementation // ============== namespace internal { void MeshHDF5Saver::save_mesh_coordinates( HDF5File& file, const std::string& name, const std::string& section) { auto group_name = file.complete_name(name, section); auto group = file.create_group(group_name); hsize_t dims[] = {static_cast(m_mesh->nb_nodes())}; auto fspace = H5::DataSpace(1, dims); auto plist = H5::DSetCreatPropList(); auto dataset = file.create_dataset(COORDINATES_DSET, group_name, H5::PredType::NATIVE_DOUBLE, fspace, plist); //! \brief Try without creation of temporary ? std::vector coords(m_mesh->nb_nodes()); for (auto node: m_mesh->range_nodes()) { coords[node] = m_mesh->get_position(node); } dataset->write(coords.data(), H5::PredType::NATIVE_DOUBLE, fspace); } } //end namespace internal } //end namespace io } //end namespace specmicp diff --git a/src/dfpm/io/hdf5_mesh.hpp b/src/dfpm/io/hdf5_mesh.hpp index df95713..554f7b4 100644 --- a/src/dfpm/io/hdf5_mesh.hpp +++ b/src/dfpm/io/hdf5_mesh.hpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_HDF5_MESH_HPP #define SPECMICP_IO_HDF5_MESH_HPP #include "../../types.hpp" #include "../meshes/mesh1dfwd.hpp" namespace specmicp { namespace io { class HDF5File; //! \brief Save the coordinates of a mesh into a HDF5 file //! //! \param file HDF5 file //! \param name Name of the group where the mesh is saved //! \param section Name of the section where the mesh group is //! \param mesh The mesh //! void SPECMICP_DLL_PUBLIC save_mesh_coordinates( HDF5File& file, const std::string& name, const std::string& section, mesh::Mesh1DPtr the_mesh ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_HDF5_MESH_HPP diff --git a/src/dfpm/io/meshes.cpp b/src/dfpm/io/meshes.cpp index ef75400..1ae1b91 100644 --- a/src/dfpm/io/meshes.cpp +++ b/src/dfpm/io/meshes.cpp @@ -1,96 +1,98 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "meshes.hpp" #include #include #include "../meshes/mesh1d.hpp" #include "../../physics/io/units.hpp" #include "../../utils/io/csv_formatter.hpp" namespace specmicp { namespace io { void print_mesh(std::ostream* output, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit) { (*output) << "# dfpm mesh \n"; (*output) << "# units : " << length_unit_to_string(lenght_unit) << "\n"; (*output) << "Node\tDistance\tCell_volume" << std::endl; for (index_t node: the_mesh->range_nodes()) { (*output) << node << "\t" << the_mesh->get_position(node) << "\t" << the_mesh->get_volume_cell(node) << "\n"; } } //! \brief Print 'the_mesh' in the file 'filepath' void print_mesh(std::string filepath, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit) { std::ofstream outfile(filepath); if (not outfile) { throw std::runtime_error("Cannot open file : '"+filepath+"'."); } print_mesh(&outfile, the_mesh, lenght_unit); outfile.close(); } void print_header_for_each_node(CSVFile& output, mesh::Mesh1DPtr the_mesh, const std::string& x_label) { output << x_label; for (index_t node: the_mesh->range_nodes()) { output.separator(); output << the_mesh->get_position(node); } output.eol(); } void print_for_each_node(CSVFile& output, mesh::Mesh1DPtr the_mesh, scalar_t x, to_print_each_node_f& func) { output << x; for (index_t node: the_mesh->range_nodes()) { output.separator(); output << func(node); } output.eol(); } } //end namespace io } //end namespace specmicp diff --git a/src/dfpm/io/meshes.hpp b/src/dfpm/io/meshes.hpp index 5bda2b5..88e98f1 100644 --- a/src/dfpm/io/meshes.hpp +++ b/src/dfpm/io/meshes.hpp @@ -1,79 +1,81 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_IO_MESHES_HPP #define SPECMICP_DFPM_IO_MESHES_HPP //! \file dfpm/io/meshes.hpp //! \brief Print the meshes #include "../../types.hpp" #include "../meshes/mesh1dfwd.hpp" #include "../../physics/units.hpp" #include #include namespace specmicp { namespace io { class CSVFile; //! \brief Print 'the_mesh' informations in 'output' void SPECMICP_DLL_PUBLIC print_mesh(std::ostream* output, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit); //! \brief Print 'the_mesh' in the file 'filepath' void SPECMICP_DLL_PUBLIC print_mesh(std::string filepath, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit); using to_print_each_node_f = std::function; //! \brief The header for the #print_for_each_node function //! //! void SPECMICP_DLL_PUBLIC print_header_for_each_node(CSVFile& output, mesh::Mesh1DPtr the_mesh, const std::string& x_label); //! \brief Output the value of func in a CSV file for every node //! //! A row looks like : x,func(0),func(1),...,func(n) //! void SPECMICP_DLL_PUBLIC print_for_each_node(CSVFile& output, mesh::Mesh1DPtr the_mesh, scalar_t x, to_print_each_node_f& func); } // end namespace io } // end namespace specmicp #endif // SPECMICP_DFPM_IO_MESHES_HPP diff --git a/src/dfpm/mesh.hpp b/src/dfpm/mesh.hpp index aa6989a..00e7b22 100644 --- a/src/dfpm/mesh.hpp +++ b/src/dfpm/mesh.hpp @@ -1,39 +1,41 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file dfpm/mesh.hpp //! \brief End-user include file to make and use meshes #include "meshes/uniform_mesh1d.hpp" #include "meshes/axisymmetric_uniform_mesh1d.hpp" #include "meshes/axisymmetric_mesh1d.hpp" #include "meshes/generic_mesh1d.hpp" diff --git a/src/dfpm/meshes/axisymmetric_mesh1d.cpp b/src/dfpm/meshes/axisymmetric_mesh1d.cpp index 51b2402..095b617 100644 --- a/src/dfpm/meshes/axisymmetric_mesh1d.cpp +++ b/src/dfpm/meshes/axisymmetric_mesh1d.cpp @@ -1,111 +1,113 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "axisymmetric_mesh1d.hpp" namespace specmicp { namespace mesh { AxisymmetricMesh1D::AxisymmetricMesh1D(Vector radius, scalar_t height): Mesh1D(radius.rows()), m_height(height), m_data(radius.rows(), 3), m_face_radius(radius.rows()-1) { // radius m_data.col(0) = radius; // Radius of the faces for (index_t element=0; element( std::make_shared(radius, height)); } Mesh1DPtr uniform_axisymmetric_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height) { Vector radius_s(nb_nodes); for (index_t node=0; node( std::make_shared(radius_s, height)); } Mesh1DPtr SPECMICP_DLL_PUBLIC uniform_axisymmetric_mesh1d(const UniformAxisymmetricMesh1DGeometry& geometry) { scalar_t dx = geometry.dx; index_t nb_nodes = geometry.nb_nodes; if (dx < 0.0) { if (nb_nodes < 0) throw std::invalid_argument("One of 'dx' and 'nb_nodes' is required to build a uniform axisymmetric mesh"); dx = geometry.radius/(nb_nodes - 1); } if (nb_nodes < 0) nb_nodes = geometry.radius / dx + 1; Vector radius_s(nb_nodes); for (index_t node=0; node( std::make_shared(radius_s, geometry.height)); } } //end namespace mesh } //end namespace specmicp diff --git a/src/dfpm/meshes/axisymmetric_mesh1d.hpp b/src/dfpm/meshes/axisymmetric_mesh1d.hpp index 6e316d0..41b2932 100644 --- a/src/dfpm/meshes/axisymmetric_mesh1d.hpp +++ b/src/dfpm/meshes/axisymmetric_mesh1d.hpp @@ -1,125 +1,127 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP #define SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP //! \file axisymmetric_mesh1d.hpp //! \brief An axisymmetric 1D mesh #include "../../types.hpp" #include "mesh1d.hpp" namespace specmicp { namespace mesh { //! \brief A generic Axisymmetric 1D mesh class SPECMICP_DLL_PUBLIC AxisymmetricMesh1D: public Mesh1D { public: const index_t radius = 0; const index_t cell_vol_0 = 1; const index_t cell_vol_1 = 2; //! \brief Build an axisymmetric 1D mesh //! //! \param radius is a vector of the position of the nodes //! \param height is the height of the sample (or depth) AxisymmetricMesh1D(Vector radius, scalar_t height); //! \brief Return the radius of an element scalar_t get_radius(index_t element, index_t enode) { return m_data(get_node(element, enode), radius); } //! \brief Return the radius of the face scalar_t get_radius_face(index_t element) { return m_face_radius(element); } //! \brief Return the position (meaning may vary with the mesh) of the node scalar_t get_position(index_t node) {return m_data(node, radius);} //! \brief Return the length of an element scalar_t get_dx(index_t element) { return get_radius(element, 0) - get_radius(element, 1);} //! \brief Return the area of the face at the middle of an element scalar_t get_face_area(index_t element) { return 2*M_PI*m_face_radius(element)*m_height;} //! \brief Return the volume of an element scalar_t get_volume_element(index_t element) { return (m_data(get_node(element, 0), cell_vol_1) + m_data(get_node(element, 1), cell_vol_0));} //! \brief Return the volume of a cell (element of the dual mesh) scalar_t get_volume_cell(index_t node) { return (m_data(node, cell_vol_0) + m_data(node, cell_vol_1));} //! \brief Return the volume of a cell inside an element virtual scalar_t get_volume_cell_element(index_t element, index_t enode) { if (enode == 0) return m_data(get_node(element, enode), cell_vol_1); else return m_data(get_node(element, enode), cell_vol_0); } private: scalar_t m_height; Matrix m_data; Vector m_face_radius; }; //! \brief Geometry information for a uniform axisymmetric mesh //! //! If (dx==-1) it is computed from the radius and the number of nodes struct UniformAxisymmetricMesh1DGeometry { index_t nb_nodes; //!< Number of nodes in the mesh scalar_t radius; //!< Outside radius of the cylinder scalar_t dx {-1}; //!< Discretization step scalar_t height; //!< Height of the cylinder }; //! \brief Return a shared_ptr to an axisymmetric mesh //! //! \param radius is a vector of the position of the nodes //! \param height is the height of the sample (or depth) Mesh1DPtr SPECMICP_DLL_PUBLIC axisymmetric_mesh1d(Vector radius, scalar_t height); //! \brief Factory method to build a pointer to a uniform axisymmetric 1D mesh //! //! Note: this method buil an AxisymmetricMesh1D instance while //! the specmicp::mesh::axisymmetric_uniform_mesh1d method build a //! specmicp::mesh::AxisymmetricUniformMesh1D instance. Mesh1DPtr SPECMICP_DLL_PUBLIC uniform_axisymmetric_mesh1d(const UniformAxisymmetricMesh1DGeometry& geometry); } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP diff --git a/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp b/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp index 35180b3..64af93e 100644 --- a/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp +++ b/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp @@ -1,129 +1,131 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP #define SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP //! \file axisymmetric_uniform_mesh1d.hpp //! \brief Uniform axisymmetric 1D mesh #include "mesh1d.hpp" namespace specmicp { namespace mesh { //! \brief A uniform axisymmetric 1D mesh //! \deprecated The specmicp::mesh::AxisymmetricMesh1D should be prefered class AxisymmetricUniformMesh1D: public Mesh1D { public: AxisymmetricUniformMesh1D(index_t nb_nodes, scalar_t radius, scalar_t height): Mesh1D(nb_nodes), m_radius(radius), m_radius_int(0.0), m_dx(radius/(nb_nodes-1)), m_height(height) {} AxisymmetricUniformMesh1D(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height): Mesh1D(nb_nodes), m_radius(radius), m_radius_int(radius-(nb_nodes-1)*dx), m_dx(dx), m_height(height) {} scalar_t get_radius_node(index_t node) { return m_radius-m_dx*node; } //! Return the radius of a face of an element scalar_t get_radius_face(index_t element) { return get_radius_node(get_node(element, 1))+m_dx/2; } scalar_t get_position(index_t node) {return get_radius_node(node);} scalar_t get_dx(index_t _) {return m_dx;} scalar_t get_face_area(index_t element) { return 2*M_PI*get_radius_face(element)*m_height;} scalar_t get_volume_element(index_t element) {return M_PI*m_height*( std::pow(get_radius_node(get_node(element, 0)),2) - std::pow(get_radius_node(get_node(element, 1)),2)) ;} scalar_t get_volume_cell(index_t node) { if (node ==0) return M_PI*m_height*(std::pow(m_radius,2)-std::pow(get_radius_face(0),2)); else if (node == nb_nodes()-1) if (m_radius_int == 0.0) return M_PI*m_height*std::pow(m_dx/2.0,2); else return M_PI*m_height*(std::pow(get_radius_face(node-1),2) - std::pow(m_radius_int,2)); else return M_PI*m_height*(std::pow(get_radius_face(node-1),2) - std::pow(get_radius_face(node),2)); } scalar_t get_volume_cell_element(index_t element, index_t enode) { if (enode == 0) { return M_PI*m_height*(std::pow(get_radius_node(get_node(element,enode)),2) - std::pow(get_radius_face(element),2)); } else { return M_PI*m_height*(std::pow(get_radius_face(element),2) - std::pow(get_radius_node(get_node(element,enode)),2)); } } private: scalar_t m_radius; scalar_t m_radius_int; scalar_t m_dx; scalar_t m_height; }; //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr axisymmetric_uniform_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t height) { return std::static_pointer_cast( std::make_shared(nb_nodes, radius, height)); } //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr axisymmetric_uniform_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height) { return std::static_pointer_cast( std::make_shared(nb_nodes, radius, dx, height)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP diff --git a/src/dfpm/meshes/generic_mesh1d.cpp b/src/dfpm/meshes/generic_mesh1d.cpp index 565ea16..bc8f5ff 100644 --- a/src/dfpm/meshes/generic_mesh1d.cpp +++ b/src/dfpm/meshes/generic_mesh1d.cpp @@ -1,122 +1,124 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "generic_mesh1d.hpp" namespace specmicp { namespace mesh { GenericMesh1D::GenericMesh1D(const Vector& coords, scalar_t section): Mesh1D(coords.rows()), m_section(section), m_data(coords.rows(), 4), m_face_coord(coords.rows()-1) { // radius m_data.col(coord) = coords; // Radius of the faces for (index_t element=0; element( std::make_shared(coords, section)); } Mesh1DPtr SPECMICP_DLL_PUBLIC ramp_mesh1d(const Ramp1DMeshGeometry& geometry) { const scalar_t b = geometry.dx_min; const scalar_t a = (geometry.dx_max - geometry.dx_min)/geometry.length_ramp; std::vector coords; coords.reserve( ceil( geometry.length_plateau/geometry.dx_max +2*geometry.length_ramp/(geometry.dx_max+geometry.dx_min) ) +5); scalar_t x = 0; coords.push_back(x); while (x < geometry.length_ramp) { scalar_t hbar = a*x+b; scalar_t mult = std::floor(hbar/geometry.dx_min); scalar_t rem = hbar - mult*geometry.dx_min; if (rem/geometry.dx_min < 0.5) x += mult*geometry.dx_min; else x += (mult+1)*geometry.dx_min; coords.push_back(x); } while(x < geometry.length_plateau+geometry.length_ramp) { x += geometry.dx_max; coords.push_back(x); } Vector eig_coords = Eigen::Map(coords.data(), coords.size()); return generic_mesh1d(eig_coords, geometry.section); } } //end namespace mesh } //end namespace specmicp diff --git a/src/dfpm/meshes/generic_mesh1d.hpp b/src/dfpm/meshes/generic_mesh1d.hpp index 89fdbab..149d071 100644 --- a/src/dfpm/meshes/generic_mesh1d.hpp +++ b/src/dfpm/meshes/generic_mesh1d.hpp @@ -1,129 +1,131 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP #define SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP //! \file generic_mesh1d.hpp //! \brief A cartesian 1D mesh #include "mesh1d.hpp" namespace specmicp { namespace mesh { //! \brief A cartesian 1D mesh class SPECMICP_DLL_PUBLIC GenericMesh1D: public Mesh1D { public: const index_t coord = 0; const index_t cell_vol_0 = 1; const index_t cell_vol_1 = 2; //! \brief Build 1D mesh //! //! \param coords a vector of coordinates //! \param section the section of the mesh GenericMesh1D(const Vector& coords, scalar_t section); //! \brief Return the cooordinates of 'enode' in 'element' scalar_t get_coord(index_t element, index_t enode) {return m_data(get_node(element, enode), coord);} //! \brief Return the position (meaning may vary with the mesh) of the node scalar_t get_position(index_t node) {return m_data(node, coord);} //! \brief Return the length of an element scalar_t get_dx(index_t element) { return get_coord(element, 1) - get_coord(element, 0);} //! \brief Return the area of the face at the middle of an element scalar_t get_face_area(index_t element) { return m_section;} //! \brief Return the volume of an element scalar_t get_volume_element(index_t element) { return (m_data(get_node(element, 0), cell_vol_1) + m_data(get_node(element, 1), cell_vol_0));} //! \brief Return the volume of a cell (element of the dual mesh) scalar_t get_volume_cell(index_t node) { return (m_data(node, cell_vol_0) + m_data(node, cell_vol_1));} //! \brief Return the volume of a cell inside an element virtual scalar_t get_volume_cell_element(index_t element, index_t enode) { if (enode == 0) return m_data(get_node(element, enode), cell_vol_1); else return m_data(get_node(element, enode), cell_vol_0); } private: scalar_t m_section; Matrix m_data; Vector m_face_coord; }; //! \brief Information needed to build a uniform linear 1D mesh //! //! \sa uniform_mesh_1d(const Uniform1DMeshGeometry&) struct SPECMICP_DLL_PUBLIC Uniform1DMeshGeometry { scalar_t dx; index_t nb_nodes; scalar_t section; }; //! \brief Return a uniform 1D mesh Mesh1DPtr SPECMICP_DLL_PUBLIC uniform_mesh1d(const Uniform1DMeshGeometry& geometry); //! \brief Geometry information for a ramp1D //! //! \sa ramp_mesh1d struct SPECMICP_DLL_PUBLIC Ramp1DMeshGeometry { scalar_t dx_max; scalar_t dx_min; scalar_t length_ramp; scalar_t length_plateau; scalar_t section; }; //! \brief Generate a 'ramp' mesh //! //! this version cares about space discretization, not the total length Mesh1DPtr SPECMICP_DLL_PUBLIC ramp_mesh1d(const Ramp1DMeshGeometry& geometry); //! \brief Return a shared_ptr to an axisymmetric mesh //! //! \param coords is a vector of the position of the nodes //! \param section is the section of the sample (or depth) Mesh1DPtr SPECMICP_DLL_PUBLIC generic_mesh1d(const Vector& coords, scalar_t section); } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP diff --git a/src/dfpm/meshes/mesh1d.hpp b/src/dfpm/meshes/mesh1d.hpp index 1d3fc49..4d1e5ad 100644 --- a/src/dfpm/meshes/mesh1d.hpp +++ b/src/dfpm/meshes/mesh1d.hpp @@ -1,102 +1,104 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_MESH_MESH1D_HPP #define SPECMICP_REACTMICP_MESH_MESH1D_HPP //! \file mesh1d.hpp //! \brief Abstract base class for the 1D meshes #include "../types.hpp" #include namespace specmicp { //! \namespace specmicp::mesh //! \brief Meshes for dfpm //! //! The meshes that can be use in dfpm and ReactMiCP. namespace mesh { //! \brief Abstract base class for a 1D mesh class Mesh1D { public: const index_t nen = 2; //!< Number of elemental nodes Mesh1D(index_t nb_nodes): m_nb_nodes(nb_nodes) {} virtual ~Mesh1D() {} //! \brief Return the number of elements index_t nb_elements() {return m_nb_nodes-1;} //! \brief Return the number of nodes index_t nb_nodes() {return m_nb_nodes;} //! \brief Return the node from local nod enumber and element index_t get_node(index_t element, index_t index) { specmicp_assert(index < nen); return element+index; } //! \brief Return the position (meaning may vary with the mesh) of the node virtual scalar_t get_position(index_t node) = 0; //! \brief Return the length of an element virtual scalar_t get_dx(index_t element) = 0; //! \brief Return the area of the face at the middle of an element virtual scalar_t get_face_area(index_t element) = 0; //! \brief Return the volume of an element virtual scalar_t get_volume_element(index_t element) = 0; //! \brief Return the volume of a cell (element of the dual mesh) virtual scalar_t get_volume_cell(index_t node) = 0; //! virtual scalar_t get_volume_cell_element(index_t element, index_t node) = 0; //! \brief Range over the elements range_t range_elements() {return range_t(nb_elements());} //! \brief Range over the nodes range_t range_nodes() {return range_t(nb_nodes());} //! \brief Range over the elemental nodes range_t range_nen() {return range_t(nen);} private: index_t m_nb_nodes; //!< Number of elements }; //! \brief type of a pointer to a mesh //! //! This is a smart pointer allowing the mesh to be shared freely using Mesh1DPtr = std::shared_ptr; } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_MESH1D_HPP diff --git a/src/dfpm/meshes/mesh1dfwd.hpp b/src/dfpm/meshes/mesh1dfwd.hpp index ff45dd4..bf45c76 100644 --- a/src/dfpm/meshes/mesh1dfwd.hpp +++ b/src/dfpm/meshes/mesh1dfwd.hpp @@ -1,50 +1,52 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_MESH_MESH1DFWD #define SPECMICP_REACTMICP_MESH_MESH1DFWD #include //! \file mesh1dfwd.hpp //! \brief define the forward declaration of a 1D mesh namespace specmicp { namespace mesh { class Mesh1D; using Mesh1DPtr = std::shared_ptr; } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_MESH1DFWD diff --git a/src/dfpm/meshes/uniform_mesh1d.hpp b/src/dfpm/meshes/uniform_mesh1d.hpp index b995cc5..a3d2ac3 100644 --- a/src/dfpm/meshes/uniform_mesh1d.hpp +++ b/src/dfpm/meshes/uniform_mesh1d.hpp @@ -1,78 +1,80 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP #define SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP #include "mesh1d.hpp" //! \file uniform_mesh1d.hpp Uniform 1D mesh namespace specmicp { namespace mesh { //! \brief A uniform 1D mesh //! //! \deprecated The specmicp::mesh::GenericMesh1D should be preferred class UniformMesh1D: public Mesh1D { public: UniformMesh1D(index_t nb_nodes, scalar_t dx, scalar_t cross_section): Mesh1D(nb_nodes), m_dx(dx), m_crosssection(cross_section) {} scalar_t get_position(index_t node) {return m_dx*node;} scalar_t get_dx(index_t _) {return m_dx;} scalar_t get_face_area(index_t _) { return m_crosssection;} scalar_t get_volume_element(index_t _) {return m_dx*m_crosssection;} scalar_t get_volume_cell(index_t node) { if (node ==0 or node == nb_nodes()-1) return m_dx*m_crosssection/2; else return m_dx*m_crosssection; } scalar_t get_volume_cell_element(index_t element, index_t enode) { return m_dx*m_crosssection/2; } private: scalar_t m_dx; scalar_t m_crosssection; }; //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr uniform_mesh1d(index_t nb_nodes, scalar_t dx, scalar_t cross_section) { return std::static_pointer_cast(std::make_shared(nb_nodes, dx, cross_section)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP diff --git a/src/dfpm/types.hpp b/src/dfpm/types.hpp index 56c56d1..9c0c443 100644 --- a/src/dfpm/types.hpp +++ b/src/dfpm/types.hpp @@ -1,54 +1,56 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file dfpm/types.hpp //! \brief Define common types for the dfpm modules #ifndef SPECMICP_DFPM_TYPES_HPP #define SPECMICP_DFPM_TYPES_HPP #include "../types.hpp" #include "Eigen/SparseCore" #include namespace specmicp { namespace dfpm { //! \brief The type of a triplet using triplet_t = Eigen::Triplet; //! \brief The type of a list of triplets using list_triplet_t = std::vector; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_TYPES_HPP diff --git a/src/dfpmsolver/dfpm_program.hpp b/src/dfpmsolver/dfpm_program.hpp index 082ebf7..f457c2f 100644 --- a/src/dfpmsolver/dfpm_program.hpp +++ b/src/dfpmsolver/dfpm_program.hpp @@ -1,68 +1,70 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP #define SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP #include "../types.hpp" namespace specmicp { namespace dfpmsolver { //! \brief Base class for a program template class DFPMProgram { public: //! \brief Return a pointer to the true object Derived* derived() {static_cast(this);} //! \brief Return the number of equations index_t get_neq() const {return derived()->get_neq();} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return derived()->get_ndf();} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return derived()->get_tot_ndf();} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return derived()->id_equation(id_dof);} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP diff --git a/src/dfpmsolver/driver.hpp b/src/dfpmsolver/driver.hpp index 8bbe748..5adaf52 100644 --- a/src/dfpmsolver/driver.hpp +++ b/src/dfpmsolver/driver.hpp @@ -1,144 +1,146 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_DRIVER_HPP #define SPECMICP_DFPMSOLVER_DRIVER_HPP #include "../types.hpp" namespace specmicp { //! \namespace specmicp::dfpmsolver //! \brief The DFPM solvers //! //! Contains the solvers to solve the DFPM programs //! //! \sa specmicp::dfpm namespace dfpmsolver { //! \brief Base class for a driver //! //! Options should be a subclass of DriverOptions //! Performance should be a subclass of DriverPerformance //! template class Driver { public: Driver(Program& the_program): m_program(the_program), m_options(), m_scaling_is_initialized(false) { } Driver(Program& the_program, Options some_options): m_program(the_program), m_options(some_options), m_scaling_is_initialized(false) { } // basic program management // ------------------------ //! Return the program Program& program() {return m_program;} //! Return the number of equations index_t get_neq() const {return m_program.get_neq();} // common process // -------------- //! \brief rescale the update if needed //! //! Return the step length scalar_t is_step_too_long(Vector& update); // options // ------- //! \brief Return a read/write reference to the options Options& get_options() {return m_options;} //! \brief Return a read-only reference to the options const Options& get_options() const {return m_options;} // performance // ----------- //! \brief Return a const reference to the performance const Performance& get_perfs() const {return m_performance;} // Scaling // ------- void initialize_scaling() { if (not m_scaling_is_initialized) { m_scaling.resize(get_neq()); m_scaling.setOnes(); } } void set_scaling(const Vector& scale) { specmicp_assert(scale.rows() == get_neq()); m_scaling = scale; m_scaling_is_initialized = true; } const Vector& scaling() const {return m_scaling;} scalar_t scaling(index_t id_eq) const {return m_scaling(id_eq);} protected: //! \brief Read/write access to the performance Performance& get_perfs() {return m_performance;} private: Program& m_program; //!< The program Performance m_performance; //!< The performance Options m_options; //!< The options Vector m_scaling; //!< Scaling factor bool m_scaling_is_initialized; }; } // end namespace dfpmsolver } // end namespace specmicp // implementation // ============== #include "driver.inl" #endif // SPECMICP_DFPMSOLVER_DRIVER_HPP diff --git a/src/dfpmsolver/driver.inl b/src/dfpmsolver/driver.inl index 4a99763..eac6b01 100644 --- a/src/dfpmsolver/driver.inl +++ b/src/dfpmsolver/driver.inl @@ -1,55 +1,57 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_DRIVER_HPP #include "driver.hpp" // syntaxic coloration only #endif namespace specmicp { namespace dfpmsolver { template scalar_t Driver::is_step_too_long(Vector& update) { double steplength = (scaling().asDiagonal()*update).norm(); if (steplength > get_options().maximum_step_length) { get_perfs().maximum_step_taken = true; update = (get_options().maximum_step_length / steplength) * update; steplength = get_options().maximum_step_length; } return steplength; } } // end namespace dfpmsolver } // end namespace specmicp diff --git a/src/dfpmsolver/driver_structs.hpp b/src/dfpmsolver/driver_structs.hpp index a89b17e..f6d6b58 100644 --- a/src/dfpmsolver/driver_structs.hpp +++ b/src/dfpmsolver/driver_structs.hpp @@ -1,108 +1,110 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP #define SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP #include "../types.hpp" #include "../utils/sparse_solvers/sparse_solver_structs.hpp" #define DFPM_DEFAULT_RES_TOL 1e-5 #define DFPM_DEFAULT_ABS_TOL 1e-12 #define DFPM_DEFAULT_STEP_TOL 1e-10 #define DFPM_DEFAULT_TRSHOLD_STATIONARY 1e-4 #define DFPM_DEFAULT_MAX_ITER 200 #define DFPM_DEFAULT_MAX_STEP_LENGTH 1e3 #define DFPM_DEFAULT_MAX_ITER_MAX_LENGTH 50 #define DFPM_DEFAULT_COEFF_ACCEPT_NEWTON 0.9 #define DFPM_DEFAUT_SPARSE_SOLVER specmicp::sparse_solvers::SparseSolver::SparseQR namespace specmicp { namespace dfpmsolver { //! \brief Options of a driver //! struct DriverOptions { //! Maximum iterations allowed int maximum_iterations {DFPM_DEFAULT_MAX_ITER }; //! Maximum number of iterations at maximum step length int max_iterations_at_max_length {DFPM_DEFAULT_MAX_ITER_MAX_LENGTH}; //! The sparse solver to use sparse_solvers::SparseSolver sparse_solver {DFPM_DEFAUT_SPARSE_SOLVER}; //! Tolerance for the residual scalar_t residuals_tolerance {DFPM_DEFAULT_RES_TOL}; //! Absolute tolerance for the residual scalar_t absolute_tolerance {DFPM_DEFAULT_ABS_TOL}; //! Tolerance for the minimum step length scalar_t step_tolerance {DFPM_DEFAULT_STEP_TOL}; //! if ||R||>threshold, the point is classified as stationary scalar_t threshold_stationary_point {DFPM_DEFAULT_TRSHOLD_STATIONARY }; //! Maximum step length allowed scalar_t maximum_step_length {DFPM_DEFAULT_MAX_STEP_LENGTH}; //! Accept Newton step if enough progress is made scalar_t coeff_accept_newton_step {DFPM_DEFAULT_COEFF_ACCEPT_NEWTON}; DriverOptions() {} }; //! \brief Performance of a driver struct DriverPerformance { int nb_call_residuals; int nb_call_jacobian; int nb_iterations; int nb_consecutive_max_step_taken; int nb_max_step_taken; bool maximum_step_taken; scalar_t current_residual; scalar_t absolute_residual; scalar_t current_update; DriverPerformance(): nb_call_residuals(0), nb_call_jacobian(0), nb_iterations(0), nb_consecutive_max_step_taken(0), nb_max_step_taken(0), maximum_step_taken(0), current_residual(0.0), absolute_residual(0.0), current_update(0.0) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP diff --git a/src/dfpmsolver/parabolic_driver.hpp b/src/dfpmsolver/parabolic_driver.hpp index ead108a..a324333 100644 --- a/src/dfpmsolver/parabolic_driver.hpp +++ b/src/dfpmsolver/parabolic_driver.hpp @@ -1,185 +1,187 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP #define SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP #include "../types.hpp" #include "../utils/sparse_solvers/sparse_solver.hpp" #include "driver.hpp" #include "parabolic_structs.hpp" namespace specmicp { namespace dfpmsolver { //! \brief The parabolic driver //! //! Parabolic driver for finite element programs template class ParabolicDriver: public Driver { public: using base=Driver; using base::program; using base::get_neq; using base::get_options; using base::get_perfs; using base::scaling; using base::initialize_scaling; ParabolicDriver(Program& the_program): Driver(the_program), m_velocity(Vector::Zero(the_program.get_tot_ndf())), m_solver(nullptr) {} //! \brief Solve a timestep of length dt ParabolicDriverReturnCode solve_timestep(scalar_t dt, Vector& displacement); //! \brief Restart the current timestep ParabolicDriverReturnCode restart_timestep(Vector& displacement); //! \brief Check if the solution has been found ParabolicDriverReturnCode check_convergence(); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, Vector& residual) { compute_residuals(displacement, m_velocity, residual); } //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual) { program().compute_residuals(displacement, velocity, residual); get_perfs().nb_call_residuals += 1; } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian ); //! \brief Return the norm of the current residuals double norm_residuals() {return m_residuals.norm();} //! \brief Read/Write reference to the velocity vector const Vector& get_velocity() const {return m_velocity;} Vector& velocity() {return m_velocity;} void set_velocity(Vector& velocity_vector); //! \brief Reset the Sparse solver //! This function should be called when a new solver need to be used void reset_solver() {return m_solver.reset(nullptr);} //! \brief Call this function if the pattern of the jacobian has changed void jacobian_pattern_has_changed() {reset_solver();} //! \brief Initialize the computation void initialize_timestep(scalar_t dt, Eigen::VectorXd& displacement); //! \brief Strang Linesearch //! //! ref : //! - Matthies et al. (1979) //! - JHP course notes ParabolicLinesearchReturnCode strang_linesearch( Vector& update, Vector& displacements, scalar_t& lambda ); scalar_t residuals_0() {return m_norm_0;} private: void reset_velocity(); //! \brief Backtracking Linesearch //! //! ref : //! - Algo A6.3.1 : Dennis and Schnabel (1983) //! - Nocedal & Wrigth (2006) ParabolicLinesearchReturnCode backtracking_linesearch( Vector& update, Vector& displacements, scalar_t& lambda_out ); //! Update the variables in displacement void update_variable( const Vector& update, scalar_t lambda, Vector& displacement ); //! \brief Set the predictor void set_predictor(Vector& displacement); //! \brief perform the linesearch ParabolicDriverReturnCode linesearch( Vector &update, Vector &displacements ); //! Compute the residuals for the linesearch double compute_residuals_linesearch( Vector& update, scalar_t lambda, Vector& displacement ); double compute_residuals_strang_linesearch( Vector &update, scalar_t lambda, Vector &displacement ); scalar_t update_norm(const Vector& update); double m_norm_0 {0.0}; double m_current_dt {-1.0}; Eigen::VectorXd m_gradient; Eigen::VectorXd m_velocity; Eigen::VectorXd m_residuals; Eigen::VectorXd m_predictor; Eigen::SparseMatrix m_jacobian; sparse_solvers::SparseSolverPtr, Vector, Vector> m_solver; bool m_velocity_is_initialized {false}; }; } // end namespace dfpmsolver } // end namespace specmicp // implementation // ============== #include "parabolic_driver.inl" #endif // SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP diff --git a/src/dfpmsolver/parabolic_driver.inl b/src/dfpmsolver/parabolic_driver.inl index 7b6791d..032adde 100644 --- a/src/dfpmsolver/parabolic_driver.inl +++ b/src/dfpmsolver/parabolic_driver.inl @@ -1,519 +1,521 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP #include "parabolic_driver.hpp" // for syntaxic coloration only #endif #include "../utils/log.hpp" namespace specmicp { namespace dfpmsolver { template void ParabolicDriver::compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian ) { program().compute_jacobian(displacement, velocity, jacobian, get_options().alpha*m_current_dt); jacobian = jacobian*scaling().asDiagonal(); jacobian.makeCompressed(); get_perfs().nb_call_jacobian += 1; } template ParabolicDriverReturnCode ParabolicDriver::solve_timestep(scalar_t dt, Eigen::VectorXd& displacement) { initialize_timestep(dt, displacement); return restart_timestep(displacement); } template void ParabolicDriver::initialize_timestep(scalar_t dt, Eigen::VectorXd& displacement) { // 1) scaling initialize_scaling(); // 2) predictor, velocity m_residuals = Eigen::VectorXd::Zero(get_neq()); m_current_dt = dt; set_predictor(displacement); reset_velocity(); program().apply_bc(dt, displacement, m_velocity); // 3) initial residuals compute_residuals(displacement, m_velocity, m_residuals); m_norm_0 = norm_residuals(); // - If the norm is too low, we set it to 1 // This is important in reactive transport when // an equation can be driven out of equilibrium // during a timestep if (m_norm_0 < get_options().absolute_tolerance) m_norm_0 = 1.0; // 4) other initialisations get_perfs().nb_iterations = 0; } template void ParabolicDriver::set_predictor(Vector& displacement) { if (get_options().alpha < 1) m_predictor = displacement + (1.0-get_options().alpha)*m_current_dt*m_velocity; else m_predictor = displacement; } template scalar_t ParabolicDriver::update_norm(const Vector& update) { // l-∞ scaled norm scalar_t norm = 0.0; for (index_t dof=0; dof ParabolicDriverReturnCode ParabolicDriver::restart_timestep(Vector& displacement) { ParabolicDriverReturnCode return_code = ParabolicDriverReturnCode::NotConvergedYet; //m_solver.reset(nullptr); Eigen::VectorXd update(get_neq()); update.setZero(); get_perfs().current_update = 0; bool force_recompute_jacobian = true; while (return_code == ParabolicDriverReturnCode::NotConvergedYet) { compute_residuals(displacement, m_velocity, m_residuals); get_perfs().absolute_residual = m_residuals.norm(); get_perfs().current_residual = m_residuals.norm()/m_norm_0; get_perfs().current_update = update_norm(update); DEBUG << " NB iterations : " << get_perfs().nb_iterations << " - res : " << get_perfs().current_residual << " - update : " << get_perfs().current_update; return_code = check_convergence(); if (return_code != ParabolicDriverReturnCode::NotConvergedYet) break; if (m_solver == nullptr) { m_solver = sparse_solvers::get_sparse_solver< Eigen::SparseMatrix, Vector, Vector>(get_options().sparse_solver); compute_jacobian(displacement, m_velocity, m_jacobian); m_solver->analyse_pattern(m_jacobian); m_solver->decompose(m_jacobian); force_recompute_jacobian =false; } else if (force_recompute_jacobian or get_perfs().nb_iterations % get_options().quasi_newton == 0) { compute_jacobian(displacement, m_velocity, m_jacobian); m_solver->decompose(m_jacobian); } get_perfs().nb_iterations += 1; m_gradient = m_jacobian.transpose()*m_residuals; sparse_solvers::SparseSolverReturnCode retcode = m_solver->solve_scaling(m_residuals, scaling(), update); if (retcode != sparse_solvers::SparseSolverReturnCode::Success) { ERROR << "Error when solving linear system : " << (int) retcode << std::endl; return ParabolicDriverReturnCode::ErrorLinearSystem; } //if (update.norm() < get_options().step_tolerance) return_code = ParabolicDriverReturnCode::ErrorMinimized; //else return_code = linesearch(update, displacement); } return return_code; } template ParabolicDriverReturnCode ParabolicDriver::check_convergence() { ParabolicDriverReturnCode termcode = ParabolicDriverReturnCode::NotConvergedYet; const int nb_iterations = get_perfs().nb_iterations; const scalar_t norm_residuals = get_perfs().current_residual; const scalar_t norm_update = get_perfs().current_update; //std::cout << "Residuals : " << nb_iterations << " - " << norm_residuals/m_norm_0 << std::endl; DEBUG << "Residuals : " << nb_iterations << " - " << norm_residuals/m_norm_0; if (norm_residuals < get_options().residuals_tolerance) { termcode = ParabolicDriverReturnCode::ResidualMinimized; } else if (get_perfs().absolute_residual < get_options().absolute_tolerance) { termcode = ParabolicDriverReturnCode::ResidualMinimized; } else if (nb_iterations > 0 and norm_update > 0.0 and norm_update < 1.01*get_options().step_tolerance) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = ParabolicDriverReturnCode::StationaryPoint; } WARNING << "Error is minimized - may indicate a stationnary point"; termcode = ParabolicDriverReturnCode::ErrorMinimized; } else if (nb_iterations > get_options().maximum_iterations) { ERROR << "Maximum number of iteration reached (" << get_options().maximum_iterations << ")"; termcode = ParabolicDriverReturnCode::MaxIterations; } else if (get_perfs().maximum_step_taken) { get_perfs().nb_consecutive_max_step_taken += 1; get_perfs().nb_max_step_taken += 1; if (get_perfs().nb_consecutive_max_step_taken == get_options().max_iterations_at_max_length) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = ParabolicDriverReturnCode::MaxStepTakenTooManyTimes; } } else { get_perfs().nb_consecutive_max_step_taken = 0; } get_perfs().return_code = termcode; return termcode; } template double ParabolicDriver::compute_residuals_linesearch( Vector &update, scalar_t lambda, Vector &displacement ) { Eigen::VectorXd velocity(m_velocity); Eigen::VectorXd residual = Eigen::VectorXd::Zero(get_neq()); program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, velocity); compute_residuals(displacement, velocity, residual); return 0.5*residual.squaredNorm(); } template double ParabolicDriver::compute_residuals_strang_linesearch( Vector &update, scalar_t lambda, Vector &displacement ) { Eigen::VectorXd velocity(m_velocity); Eigen::VectorXd residual = Eigen::VectorXd::Zero(get_neq()); program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, velocity); compute_residuals(displacement, velocity, residual); return update.dot(residual); } template void ParabolicDriver::update_variable( const Vector& update, scalar_t lambda, Vector& displacement ) { program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, m_velocity); } template ParabolicDriverReturnCode ParabolicDriver::linesearch( Vector &update, Vector &displacements ) { base::is_step_too_long(update); get_perfs().maximum_step_taken = false; scalar_t lambda; ParabolicLinesearchReturnCode retcode; switch (get_options().linesearch) { case ParabolicLinesearch::Bactracking: retcode = backtracking_linesearch(update, displacements, lambda); break; case ParabolicLinesearch::Strang: retcode = strang_linesearch(update, displacements, lambda); break; default: throw std::runtime_error("Linesearch type for Parabolic driver is not recognized"); break; } if (retcode != ParabolicLinesearchReturnCode::Success) { return ParabolicDriverReturnCode::LinesearchFailed; } update_variable(update, lambda, displacements); update *= lambda; return ParabolicDriverReturnCode::NotConvergedYet; } namespace internal { //! \brief Return true if a and b have the same sign inline bool have_same_sign(double a, double b) { return (std::copysign(1., a) * std::copysign(1., b) > 0); } } // end namespace internal template ParabolicLinesearchReturnCode ParabolicDriver::strang_linesearch( Vector& update, Vector& displacements, scalar_t& lambda ) { DEBUG << "Strang linesearch"; Eigen::VectorXd xp(displacements); const scalar_t s_tol = 0.5; const scalar_t s_max = 2.0; const int lin_max = 10; scalar_t s_b = 0.0; scalar_t g_b = 0.5*m_residuals.squaredNorm(); scalar_t s_a = 1.0; scalar_t g_a = compute_residuals_strang_linesearch(update, 1.0, xp); scalar_t newtlen = (scaling().asDiagonal()*update).norm(); // const scalar_t s_r = s_a; const scalar_t g_r = g_a; if (std::abs(g_a) <= s_tol*std::abs(g_b)) { DEBUG << "Skip linesearch "; lambda = 1.0; if (lambda == 1.0 and (newtlen > 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } return ParabolicLinesearchReturnCode::Success; } while (internal::have_same_sign(g_a, g_b) and s_a < s_max) { s_b = s_a; s_a = 2*s_a; g_b = g_a; g_a = compute_residuals_strang_linesearch(update, s_a, xp); } scalar_t g_ = g_a; scalar_t g_0 = g_a; scalar_t s = s_a; int l; for (l=0; l= g_r) { WARNING << "Failed to find better update in Strang linesearch"; //lambda = 0.1*s_r; return backtracking_linesearch(update, displacements, lambda); } lambda = s_a; if (lambda == 1.0 and (newtlen > 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } return ParabolicLinesearchReturnCode::Success; } template ParabolicLinesearchReturnCode ParabolicDriver::backtracking_linesearch( Vector& update, Vector& displacements, scalar_t& lambda_out ) { // References // ---------- // - Algo A6.3.1 : Dennis and Schnabel (1983) // - Nocedal & Wrigth (2006) DEBUG << "Linesearch"; Eigen::VectorXd xp(displacements); double fcp; int retcode = 2; // 2 not converged, 1 problem, 0 success const scalar_t alpha = 1e-4; scalar_t newtlen = (scaling().asDiagonal()*update).norm(); scalar_t init_slope = m_gradient.dot(update); const scalar_t rellength = update_norm(update); const scalar_t minlambda = get_options().step_tolerance / rellength; scalar_t lambda = 1.0; scalar_t lambda_prev = lambda; scalar_t merit_value = 0.5*m_residuals.squaredNorm(); // new residual fcp = compute_residuals_linesearch(update, lambda, xp); // Skip linesearch if enough progress is done // ------------------------------------------ if (fcp < get_options().coeff_accept_newton_step *merit_value) { DEBUG << "Skip linesearch "; lambda_out = 1.0; return ParabolicLinesearchReturnCode::Success; } // The linesearch // -------------- scalar_t fc = merit_value; scalar_t fcp_prev; int cnt = 0; do { SPAM << "cnt : " < 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } break; } else if (lambda < minlambda) { retcode = 0; lambda = minlambda; //retcode = 1; break; } else { // Select a new step length // - - - - - - - - - - - - double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const scalar_t factor = 1.0 /(lambda - lambda_prev); const scalar_t x1 = fcp - fc - lambda*init_slope; const scalar_t x2 = fcp_prev - fc - lambda_prev*init_slope; const scalar_t a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const scalar_t b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const scalar_t disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } } if (not std::isfinite(lambda)) { ERROR << "Lambda is non finite - we stop"; return ParabolicLinesearchReturnCode::Divergence; } fcp = compute_residuals_linesearch(update, lambda, xp); ++cnt; } while(retcode == 2 and cnt < 50); if (cnt == 50) { ERROR << "Too much linesearch iterations ! We stop"; return ParabolicLinesearchReturnCode::MaximumIterations; } lambda_out = lambda; switch (retcode) { case 0: return ParabolicLinesearchReturnCode::Success; break; case 1: return ParabolicLinesearchReturnCode::LambdaTooSmall; default: return ParabolicLinesearchReturnCode::NotSupposedToHappen; break; } } template void ParabolicDriver::set_velocity(Vector& velocity_vector) { m_velocity.resize(program().get_tot_ndf()); m_velocity.setZero(); for (index_t dof=0; dof void ParabolicDriver::reset_velocity() { for (index_t dof=0; dof Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP #define SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP #include "../types.hpp" #include #include "dfpm_program.hpp" namespace specmicp { namespace dfpmsolver { //! Concept class for a program template class ParabolicProgram: DFPMProgram> { public: Derived* derived() {static_cast(this);} //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ) { derived()->compute_residuals(displacement, velocity, residual); } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { derived()->compute_jacobian(displacement, velocity, jacobian, alphadt); } //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity) { derived()->update_solution(update, lambda, alpha_dt, predictor, displacement, velocity); } //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP diff --git a/src/dfpmsolver/parabolic_structs.hpp b/src/dfpmsolver/parabolic_structs.hpp index 398aabb..f3e382e 100644 --- a/src/dfpmsolver/parabolic_structs.hpp +++ b/src/dfpmsolver/parabolic_structs.hpp @@ -1,111 +1,113 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP #define SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP #include "driver_structs.hpp" #define DFPM_PARABOLIC_DEFAULT_ALPHA 1.0 #define DFPM_PARABOLIC_DEFAULT_LINESEARCH specmicp::dfpmsolver::ParabolicLinesearch::Bactracking #define DFPM_PARABOLIC_DEFAULT_QUASI_NEWTON 1 namespace specmicp { namespace dfpmsolver { //! \brief The linesearch to use in the parabolic driver enum class ParabolicLinesearch { Bactracking, //!< Bactracking linesearch Strang //!< Strang Linesearch }; //! \brief The return code of the parabolic linesearch enum class ParabolicLinesearchReturnCode { NotSupposedToHappen, //!< For debugging purpose MaximumIterations, //!< Error : maximum iteration reached LambdaTooSmall, //!< Error : step tolerance reached Divergence, //!< Error : divergence Success //!< Success ! }; //! \brief Options of a parabolic driver //! struct ParabolicDriverOptions: public DriverOptions { //! The linesearch to use ParabolicLinesearch linesearch {DFPM_PARABOLIC_DEFAULT_LINESEARCH}; //! Number of iterations without reforming the jacobian int quasi_newton {DFPM_PARABOLIC_DEFAULT_QUASI_NEWTON}; //! Implicit/Cranck-Nicholson parameter (between 0 and 1) scalar_t alpha {DFPM_PARABOLIC_DEFAULT_ALPHA}; ParabolicDriverOptions() {} }; //! \brief Return codes of the parabolic solver //! //! A value greater than NotconvergedYet indicates a succes enum class ParabolicDriverReturnCode { LinesearchFailed = -5, //!< Linesearch has failed (usually indicates a bad system) MaxIterations = -4, //!< Maximum number of iterations reached MaxStepTakenTooManyTimes = -3, //!< Maximum step taken too many times (divergence) ErrorLinearSystem = -2, //!< Error when solving the linear system StationaryPoint = -1, //!< Stationnary points are detected NotConvergedYet = 0, //!< Problem is not converged ResidualMinimized = 1, //!< The residual is minimized (Success) ErrorMinimized = 2 //!< Error is minimized (may be good) }; //! \brief Return true if 'retcode' corresponds to a failure inline bool has_failed(ParabolicDriverReturnCode retcode) { return (retcode <= ParabolicDriverReturnCode::NotConvergedYet); } //! \brief Performance of the parabolic driver struct ParabolicDriverPerformance: public DriverPerformance { ParabolicDriverReturnCode return_code; ParabolicDriverPerformance(): DriverPerformance(), return_code(ParabolicDriverReturnCode::NotConvergedYet) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP diff --git a/src/macros.hpp b/src/macros.hpp index a64c1b7..c9f2cd8 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -1,167 +1,169 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMCICP_MACROS_HPP #define SPECMCICP_MACROS_HPP #include //! \file macros.hpp //! \brief Macros and config // a lot of the eigen stuff may raise an error if in Debug mode #ifdef NDEBUG constexpr bool ndebug { false }; #else constexpr bool ndebug { true }; #endif #define NOEXCEPT noexcept(ndebug) //! \def specmicp_assert //! \brief Assertion macro used in SpecMiCP //! //! This is the assertion macro used in SpecMiCP. //! It can be selectively disabled by declaring SPECMICP_NO_DEBUG. #ifdef SPECMICP_NO_DEBUG #define specmicp_assert #else #define specmicp_assert(x) assert(x) #endif // SPECMICP_NO_DEBUG // deprecation // ----------- //! \def SPECMICP_DEPRECATED //! \brief Declare a symbol to be deprecated //! //! This symbol will be removed shortly. Do not use it. #if defined(__GNUC__) && (__GNUC__ > 4 || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5))) #define SPECMICP_DEPRECATED(message) __attribute__((deprecated(message))) #elif defined(__clang__) && defined(__has_feature) #if __has_feature(attribute_deprecated_with_message) #define SPECMICP_DEPRECATED(message) __attribute__ ((deprecated(message))) #endif #else #define SPECMICP_DEPRECATED #endif // visibility // ---------- //! \def SPECMICP_DLL_PUBLIC //! \brief Declare a symbol to be exported in a shared library //! //! Only symbols defined with this macro will be exported in the shared library. //! The others symbols are hidden. //! //! \sa SPECMICP_DLL_LOCAL //! \def SPECMICP_DLL_LOCAL //! \brief Declare a symbol to be hidden in a shared library //! //! This symbols are not available to the user. They are not part of the API. //! //! \sa SPECMICP_DLL_PUBLIC #if defined(_WIN32) || defined(__CYGWIN__) #ifdef _EXPORTING #ifdef __GNUC__ #define SPECMICP_DLL_PUBLIC __attribute__((dllexport)) #else #define SPECMICP_DLL_PUBLIC __declspec(dllexport) #endif #else #ifdef __GNUC__ #define SPECMICP_DLL_PUBLIC __attribute__((dllimport)) #else #define SPECMICP_DLL_PUBLIC __declspec(dllimport) #endif #endif #else #if __GNUC__ >= 4 #define SPECMICP_DLL_PUBLIC __attribute__ ((visibility("default"))) #define SPECMICP_DLL_LOCAL __attribute__ ((visibility("hidden"))) #else #define SPECMICP_DLL_PUBLIC #define SPECMICP_DLL_LOCAL #endif #endif // likely / unlikely // ----------------- //! \def likely //! \brief Branch prediction information for the compiler //! //! Inform the compiler that this pbranch is very likely //! //! \sa unlikely //! \def unlikely //! \brief Branch prediction information for the compiler //! //! Inform the compiler that this branch is unlikely. //! //! \sa likely #if defined(__GNUC__) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else #define likely(x) (x) #define unlikely(x) (x) #endif // Pure function // --------------- //! \def SPECMICP_PURE_F //! \brief Define a function to have no side effect (but can read global memory) #ifdef __GNUC__ #define SPECMICP_PURE_F __attribute__ ((pure)) #else #define SPECMICP_PURE_F #endif //! \def SPECMICP_CONST_F //! \brief Define a function to have no side effect (but can read global memory) #ifdef __GNUC__ #define SPECMICP_CONST_F __attribute__ ((const)) #else #define SPECMICP_CONST_F #endif #endif // SPECMCICP_MACROS_HPP diff --git a/src/micpsolver/estimate_cond_number.hpp b/src/micpsolver/estimate_cond_number.hpp index 5660505..76f7d69 100644 --- a/src/micpsolver/estimate_cond_number.hpp +++ b/src/micpsolver/estimate_cond_number.hpp @@ -1,115 +1,117 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP #define SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP #include //! \file estimate_cond_number.hpp Estimate the condition number of a matrix namespace specmicp { namespace micpsolver { //! \brief Estimate the condition number of a dense square triangular matrix //! //! References : //! - \cite Cline1979 //! - \cite Hager1984 //! //! @param tmatrix a triangular view of a dense matrix //! @param maxit maximum number of iterations done by the algorithm (2 triangular solve by iteration) //! template double estimate_condition_number(Eigen::TriangularView tmatrix, int maxit=10) { const int n = tmatrix.cols(); Eigen::VectorXd x = 1/n*Eigen::VectorXd::Ones(n); Eigen::VectorXd y(n); int cnt = 0; y = tmatrix.solve(x); while (cnt < maxit) { for (int i=0; i= 0) y(i) = 1; else y(i) = -1; } tmatrix.solveInPlace(y); y.reverseInPlace(); // transpose int j; const double maxi = y.array().abs().maxCoeff(&j); const double gamma = y.dot(x); if (maxi <= gamma) break; // This is a local maximum x= Eigen::VectorXd::Zero(n); x(j) = 1; y = tmatrix.solve(x); ++cnt; } // norm tmatrix // ------------ double nnorm; if (mode == Eigen::Lower) { nnorm = std::abs(tmatrix(0, 0)); for (int i=1; i-1; --i) { double normrow = 0; for (int j=i; j(); } } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP diff --git a/src/micpsolver/micpprog.hpp b/src/micpsolver/micpprog.hpp index 1f6a465..a046cd2 100644 --- a/src/micpsolver/micpprog.hpp +++ b/src/micpsolver/micpprog.hpp @@ -1,113 +1,115 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVER_MICPPROG_HPP #define SPECMICP_MICPSOLVER_MICPPROG_HPP #include "../types.hpp" //! \file micpprog.hpp //! \brief The static interface of a MiCP program namespace specmicp { namespace micpsolver { //! \class MiCPProg //! \brief A base clase for a MiCP program //! //! This class describes a static interface. //! Any MiCP program should derived from this class and implement its methods template class MiCPProg { public: //! \brief Return the derived class Derived& derived() {return static_cast(*this);} //! \brief Return the number of variables //! //! Sould be implemented by the program index_t total_variables() {return derived()->total_variables();} //! \brief Return the number of free variables //! //! Sould be implemented by the variables //! //! The free variables are the variables not subjected to the complementarity condition. index_t nb_free_variables() {return derived()->total_variables();} //! \brief Return the number of constrained variables //! //! Not need to implemented this method by the program. index_t nb_complementarity_variables() {return total_variables() - nb_free_variables();} //! \brief Return the residuals //! //! \param[in] x the variables //! \param[out] residual the residuals void get_residuals(const Vector& x, Vector& residual); //! \brief Return the jacobian //! //! \param[in] x the variables //! \param[out] jacobian the jacobian void get_jacobian(Vector& x, Matrix& jacobian); //! \brief Called at the beginning of an iteration //! //! \param x the variables //! \param norm_residual norm of the residuals of the previous iteration //! \return A boolean indicating if the system can have converged //! //! Return true by default bool hook_start_iteration(const Vector& x, scalar_t norm_residual) {return true;} //! \brief Return the maximum update length that the algorithm can take //! //! This is usually used to impose nonnegativity conditions //! //! \param x the variables //! \param update solution of the linear system //! \return multiplicating factor to scale the update scalar_t max_lambda(const Vector& x, const Vector& update) {return 1.0;} //! \brief Return the value used for infinity static double infinity() {return HUGE_VAL;} }; } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVER_MICPPROG_HPP diff --git a/src/micpsolver/micpsolver.hpp b/src/micpsolver/micpsolver.hpp index 8056c27..4fe91a5 100644 --- a/src/micpsolver/micpsolver.hpp +++ b/src/micpsolver/micpsolver.hpp @@ -1,244 +1,246 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMIC_MICPSOLVER_MICPSOLVER_HPP #define SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include "../types.hpp" #include "micpsolver_base.hpp" #include "ncp_function.hpp" //! \file micpsolver.hpp //! \brief The MiCP solver namespace specmicp { //! \namespace specmicp::micpsolver //! \brief the MiCP Solver(s) and related classes namespace micpsolver { //! \class MiCPSolver //! \brief The MiCP Solver //! //! ### Mathematics //! //! Solve //! - \f$ G(u, v) = 0\f$ //! - \f$ 0 \leq v \perp H(u,v) \geq 0 \f$ //! //! Using the penalized Fisher-Burmeister C-function. //! This is a semismooth Newton solver with many features including : //! //! - Non-monotone linesearch //! - Scaling of the jacobian //! - Check of the condition number of the jacobian //! - Check of the descent directions //! - Crashing //! - ... //! //! References : //! - Munson et al (2001) \cite Munson2001 //! - Facchinei and Pang (2003) \cite Facchinei2003 //! //! ### Usage //! //! The options to customize the solver are contained in the struct //! specmicp::micpsolver::MiCPSolverOptions . //! //! \tparam program_t a subclass of MiCPProg //! //! To separate the program and the solver, the program is passed as a shared_ptr. //! The MiCPSolver is implemented using the CRTP pattern. //! The advantage is that we have compile time polymorphism instead of //! the runtime polymorphism when using the virtual functions. //! I am not sure of the effectiveness of this method (I have not run any benchmarks) //! but since the solver is destined to be called many times any small gain is good to have. //! Also, more compile-time optimization is possible (especially inlining). //! Anyway, that was fun to code... //! //! \sa specmicp::micpsolver::MiCPProgram template class MiCPSolver: public MiCPSolverBaseProgram { public: using base = MiCPSolverBaseProgram; using base::get_options; using base::get_program; using base::get_perfs; using base::get_neq; using base::get_neq_free; //! \brief Constructor //! //! \param prog smart pointer toward an instance of a program_t to solve MiCPSolver(std::shared_ptr prog): MiCPSolverBaseProgram(prog), m_residuals(prog->total_variables()), m_phi_residuals(Vector::Zero(prog->total_variables())), m_jacobian(prog->total_variables(),prog ->total_variables()) {} // Merit function // ############## // Residuals and jacobian // ---------------------- //! \brief Compute the residuals, use internal storage //! //! \param[in] x the variables void compute_residuals(const Vector& x) { base::compute_residuals(x, m_residuals); } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! \param[in] x the variables void compute_jacobian(Vector& x) { base::compute_jacobian(x, m_jacobian); } //! \brief Reformulation of the residuals //! //! Reformulate the problem - assumes that r, the residual, has been computed before //! //! \param[in] x the variables //! \param[in] r the residuals //! \param[out] r_phi a vector of size neq, which will contain the reformulated residuals void reformulate_residuals(const Vector& x, const Vector& r, Vector& r_phi); //! \brief Reformulation of the residuals *inplace* //! //! \param[in] x the variables //! \param[in,out] r the residual, will contain the reformulated residuals void reformulate_residuals_inplace(const Vector &x, Vector &r); //! \brief Reformulation of the jacobian //! //! r is the original vector of residuals (not reformulated) void reformulate_jacobian(const Vector& x) { base::reformulate_jacobian_cck(x, m_residuals, m_jacobian); } // Algorithm // ######### //! \brief Solver the program using x as initial guess //! //! \param[in,out] x the initial guess, as output contains the solution (from the last iteration) MiCPSolverReturnCode solve(Vector& x); //! \brief Setup the residuals //! //! \param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { compute_residuals(x); reformulate_residuals(x, m_residuals, m_phi_residuals); } //! \brief Setup the jacobian //! //! \param[in] x the current solution void setup_jacobian(Eigen::VectorXd& x) { compute_jacobian(x); reformulate_jacobian(x); m_grad_phi = m_jacobian.transpose() * m_phi_residuals; } //! \brief Solve the Newton system //! //! The system will be scaled before being solved, may be expensive and not necessary. //! Do disable the scaling, disable the corresponding options in specmicp::MiCPSolver::MiCPSolverOptions. //! It assumes that the Newton system has been formed //! //! \param[out] update the update to apply to the solution //! //! \sa search_direction_calculation_no_scaling. MiCPSolverReturnCode search_direction_calculation(Vector& update); //! \brief Solve the Newton system - does not scale the jacobian //! //! The system will not be scaled. //! It assumes that the Newton system has been formed //! //! \param[out] update the update to apply to the solution //! //! \sa search_direction_scaling MiCPSolverReturnCode search_direction_calculation_no_scaling(Vector &update); //! \brief Linesearch //! //! It is a backtracking linesearch. //! If the correct option is set, this is a nonmonotone linesearch. //! //! \param[in,out] update the update of the timestep //! \param[in,out] x the current solution //! //! References : //! - \cite Dennis1983 //! - \cite Munson2001 int linesearch(Eigen::VectorXd& update, Eigen::VectorXd& x); //! \brief Crashing //! //! This function improves, if possible, the initial guess //! //! \param[in] x the current solution //! //! Reference : //! - \cite Munson2001 void crashing(Vector &x); private: // Residuals and jacobian Eigen::VectorXd m_residuals; //!< The residuals Eigen::VectorXd m_phi_residuals; //!< The reformulated residuals Eigen::VectorXd m_grad_phi; //!< The gradient of the reformulated residuals Eigen::MatrixXd m_jacobian; //!< The jacobian std::vector m_max_merits; //!< Contains the m best value of the merit function bool m_gradient_step_taken {false}; //!< True if the update was computed using the gradient }; } // end namespace micpsolver } // end namespace specmicp // ###############// // Implementation // // ###############// #include "micpsolver.inl" #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP diff --git a/src/micpsolver/micpsolver.inl b/src/micpsolver/micpsolver.inl index 804617a..2202383 100644 --- a/src/micpsolver/micpsolver.inl +++ b/src/micpsolver/micpsolver.inl @@ -1,448 +1,450 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include "micpsolver.hpp" // for syntaxic coloration... #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include #include "estimate_cond_number.hpp" #include "../utils/log.hpp" //! \file micpsolver.inl implementation of the MiCP solver namespace specmicp { namespace micpsolver { // Main algorithm // ############## template MiCPSolverReturnCode MiCPSolver::solve(Vector &x) { int cnt = 0; if (get_options().use_crashing) crashing(x); else setup_residuals(x); MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(get_neq()); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; // (S.0) Initialization of the iteration // this is a hook for simultaneous fixed-point iterations // implemented to solve the non-ideality model bool may_have_converged = get_program()->hook_start_iteration(x, m_phi_residuals.norm()); // (S.1) Check the convergence setup_residuals(x); get_perfs().current_residual = m_phi_residuals.norm(); DEBUG << "Norm residuals : " << get_perfs().current_residual; retcode = base::check_convergence(cnt, update, x, m_phi_residuals, may_have_converged); get_perfs().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; // (S.2) Compute the jacobian and solve the linear problem setup_jacobian(x); if(get_options().use_scaling) search_direction_calculation(update); else search_direction_calculation_no_scaling(update); // (S.3) Linesearch int termcode = linesearch(update, x); if (termcode != 0) retcode = MiCPSolverReturnCode::LinesearchFailure; get_perfs().return_code = retcode; get_perfs().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; base::projection(x); // project x to the positive quadrant get_perfs().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolver::search_direction_calculation(Eigen::VectorXd& update) { Vector rscaler(Vector::Ones(m_jacobian.cols())); Vector cscaler(Vector::Ones(m_jacobian.rows())); base::scaling_jacobian(m_jacobian, m_phi_residuals, rscaler, cscaler); m_jacobian = rscaler.asDiagonal() * (m_jacobian) * cscaler.asDiagonal(); Eigen::ColPivHouseholderQR solver(m_jacobian.rows(), m_jacobian.cols()); // it needs to be correctly initialized m_gradient_step_taken = false; int m; for (m=0; m 0) { scalar_t cond = estimate_condition_number(solver.matrixR().triangularView()); if (cond > get_options().condition_limit) { m_gradient_step_taken = true; m_jacobian.diagonal() += lambda*rscaler.cwiseProduct(cscaler); continue; } } update = solver.solve(-rscaler.cwiseProduct(m_phi_residuals + m*lambda*m_grad_phi)); update = cscaler.cwiseProduct(update); if (get_options().factor_descent_condition < 0 ) break; // we have a solution // else we compute the descent condition scalar_t descent_cond = m_grad_phi.dot(update); scalar_t norm_grad = m_grad_phi.norm(); scalar_t norm_update = update.norm(); if ((descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian.diagonal() += lambda*rscaler.cwiseProduct(cscaler); } DEBUG << "Gradient step : m = " << m; if (m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template MiCPSolverReturnCode MiCPSolver::search_direction_calculation_no_scaling( Vector& update ) { Eigen::ColPivHouseholderQR solver(m_jacobian.rows(), m_jacobian.cols()); // it needs to be correctly initialized // if everything is ok, this is the only decomposition m_gradient_step_taken = false; int m; // this is an index that increase the contribution of the gradient in the solution // the pure Newton solution is when m=0 for (m=0; m 0) { scalar_t cond = estimate_condition_number(solver.matrixR().triangularView()); if (cond > get_options().condition_limit) { // add the perturbation m_gradient_step_taken = true; m_jacobian.diagonal() += Eigen::VectorXd::Constant(m_jacobian.rows(), lambda); } } update = solver.solve(-(m_phi_residuals + m*lambda*m_grad_phi)); if (get_options().factor_descent_condition < 0 ) break; // we have a solution scalar_t descent_cond = m_grad_phi.dot(update); scalar_t norm_grad = m_grad_phi.norm(); scalar_t norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! // add the perturbation m_gradient_step_taken = true; m_jacobian.diagonal() += Eigen::VectorXd::Constant(m_jacobian.rows(), lambda); } DEBUG << "Gradient step : m = " << m; if (m_gradient_step_taken && m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template void MiCPSolver::crashing(Vector& x) { // steepest descent direction algorithm DEBUG << "Crashing "; const scalar_t beta = 0.5; const scalar_t sigma = 1e-5; int cnt = 0; while (cnt < 10) { setup_residuals(x); setup_jacobian(x); m_grad_phi = m_jacobian.transpose()*m_phi_residuals; Vector xp(get_neq()); int l=0; const int maxl = 10; while (l void MiCPSolver::reformulate_residuals( const Vector &x, const Vector &r, Vector &r_phi ) { // reformulation with copy from r to r_phi r_phi.resizeLike(r); r_phi.block(0, 0, get_neq_free(), 1) = r.block(0, 0, get_neq_free(), 1); for (index_t i = get_neq_free(); i void MiCPSolver::reformulate_residuals_inplace( const Vector& x, Vector& r ) { for (index_t i = get_neq_free(); i int MiCPSolver::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // References // ---------- // - Algo A6.3.1 : Dennis and Schnabel (1983) // - Munson et al. (2001) // - Facchinei (2003) // - Nocedal & Wrigth (2006) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; get_perfs().max_taken = false; int retcode = 2; const double alpha = 1e-4; double newtlen = base::is_step_too_long(p); double init_slope = m_grad_phi.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); double lambda_prev = lambda; // non monotone linesearch // ======================= double merit_value = 0.5*m_phi_residuals.squaredNorm(); // new residual xp = x + lambda*p; base::compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); // Skip linesearch if enough progress is done // ------------------------------------------ if (fcp < get_options().coeff_accept_newton_step *merit_value) { if (m_max_merits.size() > 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } // Select the merit value of reference // ----------------------------------- if (get_options().non_monotone_linesearch) { double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; // check for cycling // - - - - - - - - - if ( m_max_merits.size() ==4 && std::fabs(mmax - merit_value) < get_options().threshold_cycling_linesearch*get_options().fvectol) { //std::cout << merit_value << std::endl; WARNING << "Cycling has been detected by the linesearch - Taking the full Newton step"; x = xp; p = lambda*p; return 3; } } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } } // The linesearch // -------------- double fc = merit_value; double fcp_prev; int cnt = 0; do { fcp = 0.5*new_res.squaredNorm(); if (fcp <= fc - std::min(-alpha*lambda*init_slope,(1-alpha)*fc)) //pg760 Fachinei2003 { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { get_perfs().max_taken = true; } break; } else if (lambda < minlambda) { ERROR << "Linesearch cannot find a solution bigger than the minimal step"; retcode = 1; break; } else { // Select a new step length // - - - - - - - - - - - - double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } if (not std::isfinite(lambda)) { ERROR << "Lambda is non finite in micpsolver linesearch - we stop"; return 3; } } xp = x + lambda*p; base::compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_base.hpp b/src/micpsolver/micpsolver_base.hpp index 1bb0682..3497c25 100644 --- a/src/micpsolver/micpsolver_base.hpp +++ b/src/micpsolver/micpsolver_base.hpp @@ -1,190 +1,192 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP //! \file micpsolver_base.hpp //! \brief Base class for micpsolver #include #include "../types.hpp" #include "micpsolver_structs.hpp" #include "../utils/log.hpp" #include "../utils/options_handler.hpp" #include "../utils/perfs_handler.hpp" namespace specmicp { namespace micpsolver { //! \brief Base class for an MiCP solver //! //! Handle the program, options and performance //! template class MiCPSolverBaseProgram: public OptionsHandler, public PerformanceHandler { public: using program_ptr = std::shared_ptr; using OptionsHandler::get_options; using PerformanceHandler::get_perfs; MiCPSolverBaseProgram(): OptionsHandler(), PerformanceHandler() {} //! \brief Constructor //! //! \param prog shared_ptr to the program MiCPSolverBaseProgram(program_ptr prog): OptionsHandler(), PerformanceHandler(), m_program(prog) {} //! \brief Return the program //! //! This is due to the templating, allow to do get_program()->whatever(); program_ptr& get_program() {return m_program;} //! \brief Return the number of equations index_t get_neq() const {return m_program->total_variables();} //! \brief Return the number of equations corresponding to the free variables (size of G) index_t get_neq_free() const {return m_program->nb_free_variables();} //! \brief Compute the residuals, store it in r //! //! \param[in] x the variables //! \param[out] r vector to store the residuals (must be of the same size as x) void compute_residuals(const Vector& x, Vector& r) { m_program->get_residuals(x, r); get_perfs().nb_call_residuals += 1; } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! \param[in] x the variables //! \param[out] jacobian the jacobian void compute_jacobian(Vector& x, Matrix& jacobian) { m_program->get_jacobian(x, jacobian); get_perfs().nb_call_jacobian += 1; } //! \brief Compute the factors to scale the jacobian //! //! \param[in] jacobian the jacobian to scale (from the reformulated problem) //! \param[in] residuals the residuals corresponding to the jacobian //! \param[out] rscaler scaling factors of the rows //! \param[out] cscaler scaling factors of the columns void scaling_jacobian( const Matrix& jacobian, const Vector& residuals, Vector& rscaler, Vector& cscaler); //! \brief Check for convergence //! //! \param nb_iterations the number of iterations //! \param update the update taken at the previous iteration //! \param solution the current solution //! \param residuals current residuals //! \param may_have_converged a boolean given by the user to indicates if the problem has converged yet //! \return a MiCPSolverReturnCode describing the state of the algorithm MiCPSolverReturnCode check_convergence(int nb_iterations, const Vector& update, const Vector& solution, const Vector &residuals, bool may_have_converged = true); //! \brief Reformulate the jacobian using the cck function //! //! \param x the variables //! \param r the residuals //! \param jacobian the jacobian void reformulate_jacobian_cck( const Vector& x, const Vector& r, Matrix& jacobian ); //! \brief Compute the norm of the update //! //! \tparam p order of the norm (1, 2, ..., Eigen::Infinity) //! \param update the solution of the linear system //! \param solution the solution (variables) template double norm_update(const Vector& update, const Vector& solution) const { return (update.array().abs()/(solution.array().max(1)) ).matrix().template lpNorm

(); } //! \brief Project variables on the feasible set //! //! \param x the variables void projection(Vector& x); //! \brief Return the step corrected step length if it is too long //! //! \param update the solution of the linear system scalar_t is_step_too_long(Vector& update); protected: //! \brief Set the program //! //! \param theprogram shared_ptr to the program program_ptr& set_program(program_ptr theprogram) { m_program = theprogram; } private: program_ptr m_program; }; } // end namespace micpsolver } // end namespace specmicp // ----------------------------------- // // Implementation // // ----------------------------------- // #include "micpsolver_base.inl" #endif // SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP diff --git a/src/micpsolver/micpsolver_base.inl b/src/micpsolver/micpsolver_base.inl index 3e6912e..4d20b88 100644 --- a/src/micpsolver/micpsolver_base.inl +++ b/src/micpsolver/micpsolver_base.inl @@ -1,188 +1,190 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "micpsolver_base.hpp" // syntaxic coloration namespace specmicp { namespace micpsolver { // ref : Munson et al. (2001) template void MiCPSolverBaseProgram::scaling_jacobian( const Matrix& jacobian, const Vector& residuals, Vector& rscaler, Vector& cscaler) { for (int i=0; i MiCPSolverReturnCode MiCPSolverBaseProgram::check_convergence( int nb_iterations, const Vector& update, const Vector& solution, const Vector& residuals, bool may_have_converged ) { MiCPSolverReturnCode termcode = MiCPSolverReturnCode::NotConvergedYet; const scalar_t norm_residuals = residuals.lpNorm(); if (norm_residuals < get_options().fvectol) { if (may_have_converged == true) termcode = MiCPSolverReturnCode::ResidualMinimized; } else if (nb_iterations >0 and norm_update(update, solution) < get_options().steptol) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = MiCPSolverReturnCode::StationaryPoint; } if (may_have_converged == true) { WARNING << "MiCP solver : Error is minimized - may indicate a stationnary point"; termcode = MiCPSolverReturnCode::ErrorMinimized; } } else if (nb_iterations > get_options().max_iter) { ERROR << "Maximum number of iteration reached (" << get_options().max_iter << ")"; termcode = MiCPSolverReturnCode::MaxIterations; } else if (get_perfs().max_taken) { ++get_perfs().nb_consecutive_max_taken; ++get_perfs().nb_max_taken; if (get_perfs().nb_consecutive_max_taken == get_options().maxiter_maxstep) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = MiCPSolverReturnCode::MaxStepTakenTooManyTimes; } } else { get_perfs().nb_consecutive_max_taken = 0; } return termcode; } template void MiCPSolverBaseProgram::reformulate_jacobian_cck( const Vector& x, const Vector& r, Matrix& jacobian ) { // set the z vector : contains 1 for degenerate points Eigen::VectorXd z(Eigen::VectorXd::Zero(get_neq())); for (index_t i=get_neq_free(); i 0) and (x(i) >0)) { c -= (1-lambda)*r(i); d -= (1-lambda)*x(i); } jacobian.row(i) *= d; jacobian(i, i) += c; } } } // Projection of the variables onto the feasible set template void MiCPSolverBaseProgram::projection(Vector& x) { for (index_t i=0; inb_complementarity_variables(); ++i) { if (x(i+get_program()->nb_free_variables()) < get_options().projection_min_variable) { x(i+get_program()->nb_free_variables()) = 0; } } } template scalar_t MiCPSolverBaseProgram::is_step_too_long(Vector& update) { scalar_t steplength = update.norm(); if (steplength > get_options().maxstep) { get_perfs().max_taken = true; update = get_options().maxstep / steplength * update; steplength = get_options().maxstep; } return steplength; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_min.hpp b/src/micpsolver/micpsolver_min.hpp index f836d4d..beebe87 100644 --- a/src/micpsolver/micpsolver_min.hpp +++ b/src/micpsolver/micpsolver_min.hpp @@ -1,124 +1,126 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP //! \file micpsolver_min.hpp micpsolver based on the min function #include "micpsolver_base.hpp" namespace specmicp { namespace micpsolver { //! \brief MiCP solver using the min function template class MiCPSolverMin: public MiCPSolverBaseProgram { public: using base = MiCPSolverBaseProgram; using MiCPSolverBaseProgram::get_options; using MiCPSolverBaseProgram::get_program; using MiCPSolverBaseProgram::get_perf; using MiCPSolverBaseProgram::get_neq; using MiCPSolverBaseProgram::get_neq_free; //! \brief Constructor //! //! @param prog smart pointer toward an instance of a Program to solve MiCPSolverMin(std::shared_ptr prog): MiCPSolverBaseProgram(prog), m_residuals(prog->total_variables()), m_grad_phicck(prog->total_variables()), m_jacobian(prog->total_variables(),prog ->total_variables()) { m_max_merits.reserve(4); } //! \brief Solve the program //! //! @param[in,out] x (in) initial guess, (out) solution MiCPSolverReturnCode solve(Eigen::VectorXd& x); MiCPSolverReturnCode search_direction_calculation(Eigen::VectorXd& x, Eigen::VectorXd& update); int linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x); //! \brief Setup the residuals //! //! @param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { base::compute_residuals(x, m_residuals); } void setup_jacobian(Eigen::VectorXd& x) { base::compute_jacobian(x, m_jacobian); } //! Reduce the system //! //! @return reduced number of freedom int reduce_system(const Eigen::VectorXd& x, Eigen::MatrixXd& reduced_jacobian, Eigen::VectorXd& reduced_residual); void reformulate_residuals_cck_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& residuals); void reformulate_result(const Eigen::VectorXd &x, Eigen::VectorXd &update); private: void sanitize(Eigen::VectorXd &x); Eigen::VectorXd m_residuals; Eigen::VectorXd m_grad_phicck; Eigen::MatrixXd m_jacobian; bool m_gradient_step_taken; std::vector m_max_merits; //!< Contains the m best value of the merit function double m_newton_length; }; } // end namespace micpsolver } // end namespace specm // implementation // -------------- #include "micpsolver_min.inl" #endif // SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP diff --git a/src/micpsolver/micpsolver_min.inl b/src/micpsolver/micpsolver_min.inl index f6a63eb..f7778c8 100644 --- a/src/micpsolver/micpsolver_min.inl +++ b/src/micpsolver/micpsolver_min.inl @@ -1,383 +1,385 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "micpsolver_min.hpp" // for syntaxic coloration #include "utils/log.hpp" #include "ncp_function.hpp" #include "estimate_cond_number.hpp" namespace specmicp { namespace micpsolver { template MiCPSolverReturnCode MiCPSolverMin::solve(Eigen::VectorXd& x) { int cnt = 0; MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(Eigen::VectorXd::Zero(get_neq())); setup_residuals(x); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; DEBUG << "Solution : \n" << x; get_program()->hook_start_iteration(x, m_residuals.norm()); setup_residuals(x); get_perf().current_residual = m_residuals.norm(); SPAM << "Residuals : \n ----- \n" << m_residuals << "\n ----- \n"; retcode = base::check_convergence(cnt, update, x, m_residuals); get_perf().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; get_perf().max_taken = false; setup_jacobian(x); search_direction_calculation(x, update); sanitize(x); int termcode = linesearch(update, x); get_perf().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; base::projection(x); get_perf().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolverMin::search_direction_calculation( Eigen::VectorXd& x, Eigen::VectorXd& update) { Eigen::MatrixXd reduced_jacobian; Eigen::VectorXd reduced_residual; reduce_system(x, reduced_jacobian, reduced_residual); DEBUG << reduced_jacobian; Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; solver.compute(reduced_jacobian); get_perf().nb_factorization += 1; { // first condition : is the factorization ok ? if (solver.info() != Eigen::Success or not solver.isInvertible()) { DEBUG << "Solver.info : " << solver.info() << " - is invertible : " << solver.isInvertible(); m_gradient_step_taken = true; goto after_second_cond; // jump directly to the gradient step } } { // second condition : is the condition number ok ? const double cond = estimate_condition_number(solver.matrixR().triangularView()); DEBUG << "Condition number : " << cond; if (cond > get_options().condition_limit) { m_gradient_step_taken = true; } } after_second_cond: // third condition : is the descent condition respected update = solver.solve(-reduced_residual); m_grad_phicck = reduced_jacobian.transpose()*reduced_residual; const double descent_cond = m_grad_phicck.dot(update); reformulate_result(x, update); base::reformulate_jacobian_cck(x, m_residuals, m_jacobian); reformulate_residuals_cck_inplace(x, m_residuals); m_grad_phicck = m_jacobian.transpose()*m_residuals; m_grad_phicck(0) = 0; if (not m_gradient_step_taken) { m_newton_length = base::is_step_too_long(update); // we compute the descent condition //const double descent_cond = m_grad_phicck.dot(update); const double norm_update = update.norm(); DEBUG << "grad(phi).dot(update) = " << descent_cond << " compared to : " << ( - get_options().factor_descent_condition * std::pow(norm_update, get_options().power_descent_condition)); if (descent_cond > - get_options().factor_descent_condition * std::pow(norm_update, get_options().power_descent_condition)) { m_gradient_step_taken = true; } } if (m_gradient_step_taken) { INFO << "Full gradient step taken !"; update = - m_grad_phicck; m_newton_length = base::is_step_too_long(update); } return MiCPSolverReturnCode::NotConvergedYet; } template int MiCPSolverMin::reduce_system(const Eigen::VectorXd& x, Eigen::MatrixXd& reduced_jacobian, Eigen::VectorXd& reduced_residual) { reduced_jacobian.resizeLike(m_jacobian); // memory is cheap, we will resize at the end reduced_jacobian.setZero(); reduced_residual.resizeLike(m_residuals); // copy identical information int ideq_reduced = get_neq_free(); reduced_jacobian.block(0, 0, get_neq_free(), get_neq_free()) = m_jacobian.block(0, 0, get_neq_free(), get_neq_free()); // select active degree of freedom Eigen::VectorXd to_remove(get_neq()-get_neq_free()); for (int dof=get_neq_free(); dof= m_residuals(dof)) { DEBUG << "Mineral to precipitate : " << dof; reduced_residual(ideq_reduced) = m_residuals(dof); reduced_jacobian.block(ideq_reduced, 0, 1, get_neq_free()) = m_jacobian.block(dof, 0, 1, get_neq_free()); reduced_jacobian.block(0, ideq_reduced, get_neq_free(), 1) = m_jacobian.block(0, dof, get_neq_free(), 1); to_remove(dof-get_neq_free()) = 0; ++ideq_reduced; } else { to_remove(dof-get_neq_free()) = x(dof); } } reduced_residual.block(0, 0, get_neq_free(), 1) -= m_jacobian.block(0, get_neq_free(), get_neq_free(), get_neq()-get_neq_free())*to_remove; reduced_jacobian.conservativeResize(ideq_reduced, ideq_reduced); reduced_residual.conservativeResize(ideq_reduced); DEBUG << "ideq reduced : " << ideq_reduced; return ideq_reduced; } template void MiCPSolverMin::reformulate_result(const Eigen::VectorXd& x, Eigen::VectorXd& update) { update.conservativeResizeLike(x); int tot_to_keep = 0; for (int dof=get_neq_free(); dof= m_residuals(dof)) ++tot_to_keep; } int kept_dof = 1; for (int dof=get_neq()-1; dof>=get_neq_free(); --dof) { // we go backwards to avoid extra copies if (x(dof) >= m_residuals(dof)) { update(dof) = update(get_neq_free()+(tot_to_keep-kept_dof)); ++kept_dof; } else { update(dof) = -x(dof); } } } template void MiCPSolverMin::sanitize(Eigen::VectorXd& x) { if (x(0) <=0) x(0) = 1; for (int dof=get_neq_free(); dof void MiCPSolverMin::reformulate_residuals_cck_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& residuals) { for (int i = get_neq_free(); i int MiCPSolverMin::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // Reference Algo A6.3.1 : Dennis and Schnabel (1983) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; get_perf().max_taken = false; int retcode = 2; const double alpha = get_options().factor_descent_condition; double newtlen = m_newton_length; //double newtlen = p.norm(); double init_slope = m_grad_phicck.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); DEBUG << "Initial lambda : " << lambda; double lambda_prev = lambda; // non monotone linesearch // // - reference : Munson et al. (2001) // ------------------------------------ double merit_value = 0.5*m_residuals.squaredNorm(); // // new residual //reformulate_result(x, p); xp = x + lambda*p; DEBUG << "update \n" << p < 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } DEBUG << "Merit value : " << merit_value; double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } DEBUG << "Merit value used : " << merit_value; double fc = merit_value; double fcp_prev; int cnt = 0; do { DEBUG << "cnt : " << cnt << " - lambda : " << lambda; DEBUG << "fcp : " << fcp << "\n fc+alin : " << fc+alpha*lambda*init_slope << " # fc : " << fc << std::endl; if (fcp <= fc + alpha*lambda*init_slope) { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { get_perf().max_taken = true; } break; } else if (lambda < minlambda) { lambda = get_program()->max_lambda(x, p); xp = x + lambda*p; retcode = 1; break; } else { double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation DEBUG << "not disc : " << - init_slope/(2*b); lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } DEBUG << "lambdatmp : " << lambdatmp; lambda_prev = lambda; fcp_prev = fcp; if (not std::isfinite(lambdatmp)) { lambda = get_program()->max_lambda(x, p); xp = x + lambda*p; retcode = 1; break; } else if ((lambdatmp < 0.1*lambda)) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } DEBUG << "lambda end : " << lambda; } xp = x + lambda*p; //sanitize(xp); DEBUG << "xp : " << std::endl << xp; base::compute_residuals(xp, new_res); reformulate_residuals_cck_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_structs.hpp b/src/micpsolver/micpsolver_structs.hpp index 7738093..326e55a 100644 --- a/src/micpsolver/micpsolver_structs.hpp +++ b/src/micpsolver/micpsolver_structs.hpp @@ -1,259 +1,261 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP //! \file micpsolver_structs.hpp //! \brief structures and enum used by the micpsolver // this file exists to reduce the header dependancy // These are the default options // they are define as macro so they can be used to parse configuration with the correct default values #define MICPSOLVER_DEFAULT_USE_CRASHING false #define MICPSOLVER_DEFAULT_USE_SCALING true #define MICPSOLVER_DEFAULT_USE_NONMONOTONE_LSEARCH true #define MICPSOLVER_DEFAULT_MAX_ITER 100 #define MICPSOLVER_DEFAULT_MAX_ITER_MAXSTEP MICPSOLVER_DEFAULT_MAX_ITER #define MICPSOLVER_DEFAULT_MAX_FACT_STEP 4 #define MICPSOLVER_DEFAULT_RES_TOL 1e-8 #define MICPSOLVER_DEFAULT_STEP_TOL 1e-10 #define MICPSOLVER_DEFAULT_COND_THRESHOLD 1e6 #define MICPSOLVER_DEFAULT_PENALIZATION_FACTOR 0.8 #define MICPSOLVER_DEFAULT_MAX_STEP 100.0 #define MICPSOLVER_DEFAULT_FACTOR_DESC_COND 1e-4 #define MICPSOLVER_DEFAULT_POWER_DESC_COND 2 #define MICPSOLVER_DEFAULT_COEFF_ACCEPT_NEWTON 0.95 #define MICPSOLVER_DEFAULT_FACTOR_GRADIENT 5.0 #define MICPSOLVER_DEFAULT_PROJ_VAR DBL_EPSILON #define MICPSOLVER_DEFAULT_TRHSOLD_STATIONARY 1e-6 #define MICPSOLVER_DEFAULT_TRHSOLD_CYCLING_LSEARCH 1e-5 #include namespace specmicp { namespace micpsolver { //! \brief Options for the MiCPSolver //! //! \sa specmicp::micpsolver::MiCPSolver struct MiCPSolverOptions { //! Use a crashing step to improve the starting guess bool use_crashing {MICPSOLVER_DEFAULT_USE_CRASHING}; //! Use scaling to improve convergence bool use_scaling {MICPSOLVER_DEFAULT_USE_SCALING}; //! Use non monotone linesearch bool non_monotone_linesearch {MICPSOLVER_DEFAULT_USE_NONMONOTONE_LSEARCH}; //!< Maximum number of iterations allowed int max_iter {MICPSOLVER_DEFAULT_MAX_ITER}; //!< the maximum number of step of length maxstep allowed int maxiter_maxstep {MICPSOLVER_DEFAULT_MAX_ITER_MAXSTEP}; //! Max number of factorization in an iteration int max_factorization_step {MICPSOLVER_DEFAULT_MAX_FACT_STEP}; //! Tolerance for minimization of residuals double fvectol {MICPSOLVER_DEFAULT_RES_TOL}; //! Tolerance for minimization of error double steptol {MICPSOLVER_DEFAULT_STEP_TOL}; //! Condition number limit, -1 to disable it double condition_limit {MICPSOLVER_DEFAULT_COND_THRESHOLD}; //! Penalization factor for the penalized Fisher-Burmeister function double penalization_factor {MICPSOLVER_DEFAULT_PENALIZATION_FACTOR}; //! the maximum step allowed double maxstep {MICPSOLVER_DEFAULT_MAX_STEP}; //! factor in front of the descent condition > 0 double factor_descent_condition {MICPSOLVER_DEFAULT_FACTOR_DESC_COND}; //! power used in the traditional format of the descent condition > 2 double power_descent_condition {MICPSOLVER_DEFAULT_POWER_DESC_COND}; //! Accept the newton step without line search if merit(x+d)threshold_stationary_point and ErrorMinimized -> stationary point double threshold_stationary_point {MICPSOLVER_DEFAULT_TRHSOLD_STATIONARY}; //! factor to detect cycling in linesearch double threshold_cycling_linesearch {MICPSOLVER_DEFAULT_TRHSOLD_CYCLING_LSEARCH}; MiCPSolverOptions() {} //! \brief Set the maximum number of iterations void set_maximum_iterations(int maximum_iterations) { max_iter = maximum_iterations; } //! \brief Set the maximum step length void set_maximum_step_length(double step_length) { maxstep = step_length; } //! \brief Set the maximum step length void set_maximum_step_length(double step_length, int max_iter_at_step_length) { maxstep = step_length; maxiter_maxstep = max_iter_at_step_length; } //! \brief Disable the descent condition void disable_descent_direction() { factor_descent_condition = -1.0; } //! \brief Enable the descent condition void enable_descent_direction(double factor, double power) { factor_descent_condition = factor; power_descent_condition = power; } //! \brief Disable the condition check void disable_condition_check() { condition_limit = -1; } //! \brief Enable the condition check void enable_condition_check(double threshold) { condition_limit = threshold; } //! \brief Disable the non-monotone linesearch void disable_non_monotone_linesearch() { non_monotone_linesearch = false; } //! \brief Enable the non-monotone linesearch void enable_non_monotone_linesearch() { non_monotone_linesearch = true; } //! \brief Enable the scaling void enable_scaling() { use_scaling = true; } //! \brief Disable the scaling void disable_scaling() { use_scaling = false; } //! \brief Enable the crashing void enable_crashing() { use_crashing = true; } //! \brief Disable the scaling void disable_crashing() { use_crashing = false; } //! \brief Set tolerance void set_tolerance(double residuals_tolerance) { fvectol = residuals_tolerance; } //! \brief Set tolerances void set_tolerance(double residuals_tolerance, double step_tolerance) { fvectol = residuals_tolerance; steptol = step_tolerance; } }; //! \brief Return code of the MiCP solver //! //! A positive return code means that the algorithm converged (but maybe to a stationnary points) //! A negative return code means that something wrong happened and was detected enum class MiCPSolverReturnCode { LolItsNotSupposedToHappen = -10, //!< bummer... LinesearchFailure = -5, //!< Failure in linesearch MaxStepTakenTooManyTimes = -4, //!< Probably detect a divergence FailedToSolveLinearSystem = -3, //!< Problem in the decomposition... shouldn't be raised, use of the gradient step MaxIterations = -2, //!< Algorithm has reached the maximum number of iterations StationaryPoint = -1, //!< Algorithm is stuck in a stationnary point of the merit function NotConvergedYet = 0, //!< Keep going... Success = 1, //!< Test success (well be careful of stationnary points) ResidualMinimized = 2, //!< The residual is minimized (i.e. close to zero) ErrorMinimized = 3 //!< The error is minimized, may indicate a stationary point }; //! \brief This structure contains counter to check/query the performance of the algorithm //! //! It should be updated after each operations, not at the end struct MiCPPerformance { int nb_call_residuals; //! Number of calls of the residual int nb_call_jacobian; //! Number of calls of the jacobian int nb_factorization; //! Number of factorization performed (may be > number of iterations) int nb_gradient_step; //! Number of gradient steps (too many gradient steps indicate a bad starting guess) int nb_crashing_iterations; //! Number of crashing iterations int nb_iterations; //! Number of iterations bool max_taken; //! Maximum step has been taken int nb_max_taken; //! Number of time the maximum has been taken int nb_consecutive_max_taken; //! Number of consecutive step at max length double current_residual; //! Current residual double current_update; //! Current update MiCPSolverReturnCode return_code; //! Return code MiCPPerformance(): nb_call_residuals(0), nb_call_jacobian(0), nb_factorization(0), nb_gradient_step(0), nb_crashing_iterations(0), nb_iterations(0), max_taken(false), nb_max_taken(0), nb_consecutive_max_taken(0), current_residual(INFINITY), current_update(INFINITY), return_code(MiCPSolverReturnCode::NotConvergedYet) {} //! \brief add two performance instances - useful when restarting a computation in case of failure MiCPPerformance& operator+=(const MiCPPerformance& other) { nb_call_residuals += other.nb_call_residuals; nb_call_jacobian += other.nb_call_jacobian; nb_factorization += other.nb_factorization; nb_gradient_step += other.nb_gradient_step; nb_crashing_iterations += other.nb_crashing_iterations; nb_iterations += other.nb_iterations; return_code = other.return_code; // we take the last one return *this; } }; //! The NCP function that are implemented enum class NCPfunction { penalizedFB, // Penalized Fischer-Burmeister function min // The minimum function }; } // end namespace micpsolver } // end namespace specmicp #endif //SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP diff --git a/src/micpsolver/micpsolverold.hpp b/src/micpsolver/micpsolverold.hpp index 1872468..5348987 100644 --- a/src/micpsolver/micpsolverold.hpp +++ b/src/micpsolver/micpsolverold.hpp @@ -1,324 +1,326 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMIC_MICPSOLVER_MICPSOLVEROLD_HPP #define SPECMIC_MICPSOLVER_MICPSOLVEROLD_HPP #include #include #include "micpsolver_structs.hpp" #include "ncp_function.hpp" //! \file micpsolver.hpp The MiCP solver namespace specmicp { namespace micpsolver { //! \brief Call a NCP-function //! //! @tparam ncp_t the NCP function to use //! @param a first argument //! @param b second argument //! @param t parameter of the NCP function //! template inline double ncp_function(double a, double b, double t); //! \brief Reformulate the jacobian using the NCP-function ncp_t //! //! @tparam ncp_t the NCP-function to use //! @param[in] neq number of equation //! @param[in] neq_free number of free variables //! @param[in] x the variables //! @param[in] r the residuals //! @param[in,out] jacobian the jacobian to reformulate //! @param[in,out] r_reformulated the reformulated residuals //! @param[in] t parameter of the NCP function template inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& r_reformulated, double t ); //! \brief reformulate the result of the Newton system template inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ); //! \brief The MiCP Solver //! //! Solve //! - \f$ G(u, v) = 0\f$ //! - \f$ 0 \leq v \perp H(u,v) \geq 0 \f$ //! //! \tparam Program a subclass of MiCPProg //! //! References : //! - \cite Munson2001 //! - \cite Facchinei2003 //! template class MiCPSolverOLD { public: //! \brief Constructor //! //! @param prog smart pointer toward an instance of a Program to solve MiCPSolverOLD(std::shared_ptr prog): m_program(prog), m_residuals(prog->total_variables()), m_phi_residuals(Eigen::VectorXd::Zero(prog->total_variables())), m_jacobian(prog->total_variables(),prog ->total_variables()), m_max_taken(false), m_consec_max(0) { } //! \brief Return a const reference to the options used by the algorithm const MiCPSolverOptions& get_options() const {return m_options;} //! \brief Return a reference to the options used by the algorithm MiCPSolverOptions& get_options() {return m_options;} //! \brief Set the options void set_options(const MiCPSolverOptions& options) {m_options = options;} //! \brief Return the number of equations int get_neq() const {return m_program->total_variables();} //! \brief Return the number of equations corresponding to the free variables (size of G) int get_neq_free() const {return m_program->nb_free_variables();} // Merit function // ############## //! \brief Reformulation for lower bounded variable double phi_lower_bounded(const double& x, const double& r, const double& l) const { return ncp_function(x-l, r, get_options().penalization_factor);} //! \brief Reformulation for a free variable double phi_free(const double& r) const { return r; } //! \brief Compute the norm of the update template double norm_update(const Eigen::VectorXd& update, const Eigen::VectorXd& solution) const { return (update.array().abs()/(solution.array().max(1)) ).matrix().template lpNorm

(); } // Residuals and jacobian // ---------------------- //! \brief Compute the residuals, store it in r //! //! @param[in] x the variables //! @param[out] r vector to store the residuals (must be of the same size as x) void compute_residuals(const Eigen::VectorXd& x, Eigen::VectorXd& r) { m_program->get_residuals(x, r); get_perf().nb_call_residuals += 1; } //! \brief Compute the residuals, use internal storage //! //! @param[in] x the variables void compute_residuals(const Eigen::VectorXd& x) { return compute_residuals(x, m_residuals); get_perf().nb_call_jacobian += 1; } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! @param[in] x the variables void compute_jacobian(Eigen::VectorXd& x) { m_program->get_jacobian(x, m_jacobian); } //! \brief Reformulation of the residuals //! //! Reformulate the problem - assumes that r, the residual, has been computed before //! //! @param[in] x the variables //! @param[in] r the residuals //! @param[out] r_phi a vector of size neq, which will contain the reformulated residuals void reformulate_residuals(const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::VectorXd& r_phi); //! \brief Reformulation of the residuals *inplace* //! //! @param[in] x the variables //! @param[in,out] r the residual, will contain the reformulated residuals void reformulate_residuals_inplace(const Eigen::VectorXd& x, Eigen::VectorXd &r); //! \brief Reformulation of the jacobian //! //! r is the original vector of residuals (not reformulated) void reformulate_jacobian(const Eigen::VectorXd& x ) { reformulate_jacobian_helper(get_neq(), get_neq_free(), x, m_residuals, m_jacobian, m_phi_residuals, get_options().penalization_factor); } //! \brief Compute the factors to scale the jacobian //! //! @param[in] jacobian the jacobian to scale (from the reformulated problem) //! @param[in] residual the residuals corresponding to the jacobian //! @param[out] rscaler scaling factors of the rows //! @param[out] cscaler scaling factors of the columns void scaling_jacobian(const Eigen::MatrixXd& jacobian, const Eigen::VectorXd& residual, Eigen::VectorXd& rscaler, Eigen::VectorXd& cscaler); // Algorithm // ######### //! \brief Solver the program using x as initial guess //! //! @param[in,out] x the initial guess, as output contains the solution (from the last iteration) MiCPSolverReturnCode solve(Eigen::VectorXd& x); //! \brief Setup the residuals //! //! @param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { compute_residuals(x); reformulate_residuals(x, m_residuals, m_phi_residuals); } //! \brief Setup the jacobian //! //! @param[in] x the current solution void setup_jacobian(Eigen::VectorXd& x) { compute_jacobian(x); reformulate_jacobian(x); m_grad_phi = m_jacobian.transpose() * m_phi_residuals; } //! \brief Check for convergence //! //! @param nb_iterations the number of iterations //! @param update the update taken at the previous iteration //! @param solution the current solution //! @return a MiCPSolverReturnCode describing the state of the algorithm MiCPSolverReturnCode check_convergence(int nb_iterations, Eigen::VectorXd& update, Eigen::VectorXd& solution); //! \brief Solve the Newton system //! //! Assume that the Newton system has been formed //! //! \param[out] update the update to apply to the solution MiCPSolverReturnCode search_direction_calculation(Eigen::VectorXd& update); //! \brief Solve the Newton system - does not scale the jacobian //! //! Assume that the Newton system has been formed //! //! \param[out] update the update to apply to the solution MiCPSolverReturnCode search_direction_calculation_no_scaling(Eigen::VectorXd& update); //! \brief Linesearch //! //! Nonmonotone linesearch //! //! References : //! - \cite Dennis1983 //! - \cite Munson2001 //! int linesearch(Eigen::VectorXd& update, Eigen::VectorXd& x); //! \brief Crashing //! //! This function improves, if possible, the initial guess //! Reference : //! - \cite Munson2001 void crashing(Eigen::VectorXd& x); //! \brief Project variables on the feasible set void projection(Eigen::VectorXd& x); //! \brief Return a const reference to an instance of MiCPPerformance const MiCPPerformance& get_performance() {return m_perf;} protected: //! \brief Return a reference to an instance of MiCPPerformance MiCPPerformance& get_perf() {return m_perf;} private: //! \brief Return the step corrected step length if it is too long double is_step_too_long(Eigen::VectorXd& update); std::shared_ptr m_program; //!< Smart pointer of a program MiCPSolverOptions m_options; //!< The options MiCPPerformance m_perf; //!< The performance // Residuals and jacobian Eigen::VectorXd m_residuals; //!< The residuals Eigen::VectorXd m_phi_residuals; //!< The reformulated residuals Eigen::VectorXd m_grad_phi; //!< The gradient of the reformulated residuals Eigen::MatrixXd m_jacobian; //!< The jacobian std::vector m_max_merits; //!< Contains the m best value of the merit function bool m_max_taken; //!< True if the 'length' of the step was equal or bigger than the maximum step length int m_consec_max; //!< The number of consecutive step were the step length was equal or bigger than the maximum step length bool m_gradient_step_taken; //!< True if the update was computed using the gradient }; } // end namespace micpsolver } // end namespace specmicp // ###############// // Implementation // // ###############// #include "micpsolverold.inl" #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP diff --git a/src/micpsolver/micpsolverold.inl b/src/micpsolver/micpsolverold.inl index 445ff6d..d3d9ec7 100644 --- a/src/micpsolver/micpsolverold.inl +++ b/src/micpsolver/micpsolverold.inl @@ -1,637 +1,639 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "micpsolverold.hpp" // for syntaxic coloration... #include "estimate_cond_number.hpp" #include "utils/log.hpp" #include //! \file micpsolver.inl implementation of the MiCP solver namespace specmicp { namespace micpsolver { // Main algorithm // ############## template MiCPSolverReturnCode MiCPSolverOLD::solve(Eigen::VectorXd &x) { int cnt = 0; if (get_options().use_crashing) crashing(x); else setup_residuals(x); MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(get_neq()); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; SPAM << "Solution : \n" << x; m_program->hook_start_iteration(x, m_phi_residuals.norm()); setup_residuals(x); get_perf().current_residual = m_phi_residuals.norm(); SPAM << "Residuals : \n ----- \n" << m_phi_residuals << "\n ----- \n"; retcode = check_convergence(cnt, update, x); get_perf().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; m_max_taken = false; setup_jacobian(x); if(get_options().use_scaling) search_direction_calculation(update); else search_direction_calculation_no_scaling(update); reformulate_result(get_neq(), get_neq_free(), x, m_residuals, m_grad_phi, update); int termcode = linesearch(update, x); get_perf().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; projection(x); get_perf().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolverOLD::check_convergence(int nb_iterations, Eigen::VectorXd& update, Eigen::VectorXd& solution) { MiCPSolverReturnCode termcode = MiCPSolverReturnCode::NotConvergedYet; const double norm_residuals = m_phi_residuals.lpNorm(); if (norm_residuals < get_options().fvectol) { termcode = MiCPSolverReturnCode::ResidualMinimized; } else if (nb_iterations >0 and norm_update(update, solution) < get_options().steptol) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = MiCPSolverReturnCode::StationaryPoint; } WARNING << "Error is minimized - may indicate a stationnary point"; termcode = MiCPSolverReturnCode::ErrorMinimized; } else if (nb_iterations > get_options().max_iter) { ERROR << "Maximum number of iteration reached (" << get_options().max_iter << ")"; termcode = MiCPSolverReturnCode::MaxIterations; } else if (m_max_taken) { ++m_consec_max; if (m_consec_max == get_options().maxiter_maxstep) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = MiCPSolverReturnCode::MaxStepTakenTooManyTimes; } } else { m_consec_max = 0; } return termcode; } template MiCPSolverReturnCode MiCPSolverOLD::search_direction_calculation(Eigen::VectorXd& update) { Eigen::VectorXd rscaler(Eigen::VectorXd::Ones(m_jacobian.cols())); Eigen::VectorXd cscaler(Eigen::VectorXd::Ones(m_jacobian.rows())); scaling_jacobian(m_jacobian, m_phi_residuals, rscaler, cscaler); m_jacobian = rscaler.asDiagonal() * (m_jacobian) * cscaler.asDiagonal(); Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; int m; for (m=0; m()); if (cond > get_options().condition_limit) { m_gradient_step_taken = true; m_jacobian += rscaler.asDiagonal() * ( lambda*Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols())) * cscaler.asDiagonal(); continue; } update = solver.solve(-rscaler.cwiseProduct(m_phi_residuals + m*lambda*m_grad_phi)); update = cscaler.cwiseProduct(update); double descent_cond = m_grad_phi.dot(update); double norm_grad = m_grad_phi.norm(); double norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian += rscaler.asDiagonal() * ( lambda* Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols()) ) * cscaler.asDiagonal(); } DEBUG << "Gradient step : m = " << m; if (m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template MiCPSolverReturnCode MiCPSolverOLD::search_direction_calculation_no_scaling(Eigen::VectorXd& update) { DEBUG << "Solving linear system"; Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; int m; for (m=0; m()); if (cond > get_options().condition_limit) { continue; } update = solver.solve(-(m_phi_residuals + m*lambda*m_grad_phi)); double descent_cond = m_grad_phi.dot(update); double norm_grad = m_grad_phi.norm(); double norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian += lambda*Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols()); } DEBUG << "Gradient step : m = " << m; if (m ==4) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template void MiCPSolverOLD::crashing(Eigen::VectorXd &x) { DEBUG << "Crashing "; const double beta = 0.5; const double sigma = 1e-5; int cnt = 0; while (cnt < 10) { setup_residuals(x); setup_jacobian(x); m_grad_phi = m_jacobian.transpose()*m_phi_residuals; Eigen::VectorXd xp(get_neq()); int l=0; const int maxl = 10; while (l void MiCPSolverOLD::reformulate_residuals(const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::VectorXd& r_phi) { r_phi.resizeLike(r); r_phi.block(0, 0, get_neq_free(), 1) = r.block(0, 0, get_neq_free(), 1); for (int i = get_neq_free(); i void MiCPSolverOLD::reformulate_residuals_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& r) { for (int i = get_neq_free(); i void MiCPSolverOLD:: scaling_jacobian( const Eigen::MatrixXd& jacobian, const Eigen::VectorXd& r_phi, Eigen::VectorXd& rscaler, Eigen::VectorXd& cscaler) { for (int i=0; i int MiCPSolverOLD::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // Reference Algo A6.3.1 : Dennis and Schnabel (1983) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; m_max_taken = false; int retcode = 2; const double alpha = 1e-6; double newtlen = is_step_too_long(p); double init_slope = m_grad_phi.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); double lambda_prev = lambda; // non monotone linesearch // ----------------------- double merit_value = 0.5*m_phi_residuals.squaredNorm(); // new residual xp = x + lambda*p; compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); // Skip linesearch if enough progress is done if (fcp < get_options().coeff_accept_newton_step *merit_value) { if (m_max_merits.size() > 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } //std::cout << "Merit value : " << merit_value << std::endl; double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } //std::cout << "Merit value used : " << merit_value << std::endl; double fc = merit_value; double fcp_prev; int cnt = 0; do { fcp = 0.5*new_res.squaredNorm(); //std::cout << "fcp : " << fcp << "\n fc+alin : " << fc+alpha*lambda*init_slope << " # fc : " << fc << std::endl; if (fcp <= fc - std::min(-alpha*lambda*init_slope,(1-alpha)*fc)) //pg760 Fachinei2003 { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { m_max_taken = true; } break; } else if (lambda < minlambda) { retcode = 1; break; } else { double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } } xp = x + lambda*p; compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } // Projection of the variables onto the feasible set template void MiCPSolverOLD::projection(Eigen::VectorXd &x) { for (int i=0; inb_complementarity_variables(); ++i) { if (x(i+m_program->nb_free_variables()) < get_options().projection_min_variable) { x(i+m_program->nb_free_variables()) = 0; } } } template double MiCPSolverOLD::is_step_too_long(Eigen::VectorXd& update) { double steplength = update.norm(); if (steplength > get_options().maxstep) { m_max_taken = true; update = get_options().maxstep / steplength * update; steplength = get_options().maxstep; } return steplength; } // ================================================= // // // // NCP functions and reformulation // // // // ================================================= // template <> inline double ncp_function(double a, double b, double t) { return penalized_fisher_burmeister(a, b, t); } template <> inline double ncp_function(double a, double b, double _) { return std::min(a, b); } template <> inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& _, double t ) { // set the z vector : contains 1 for degenerate points Eigen::VectorXd z(Eigen::VectorXd::Zero(neq)); for (int i=neq_free; i 0) and (x(i) >0)) { c -= (1-lambda)*r(i); d -= (1-lambda)*x(i); } grad_fi = d*grad_fi; grad_fi(i) += c; } jacobian.block(i, 0, 1, neq) = grad_fi.transpose(); } } template <> inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& r_phi, double _ ) { std::vector to_keep; to_keep.reserve(10); Eigen::VectorXd to_remove(neq-neq_free); for (int i=neq_free; i= r(i)) { to_remove(i-neq_free) = 0; to_keep.push_back(i); } else to_remove(i-neq_free) = x(i); } r_phi.block(0, 0, neq_free, 1) -= jacobian.block(0, neq_free, neq_free, neq-neq_free)*to_remove; int new_i = neq_free; for (auto it=to_keep.begin(); it!=to_keep.end(); ++it) { //r_phi.block(0, 0, neq_free, 1) += x(*it)*jacobian.block(0, *it, neq_free, 1); jacobian.block(new_i, 0, 1, neq_free) = jacobian.block(*it, 0, 1, neq_free); // the bottom right corner is 0 jacobian.block(0, new_i, neq_free, 1) = jacobian.block(0, *it, neq_free, 1); r_phi(new_i) = r_phi(*it); ++new_i; } r_phi.conservativeResize(new_i); jacobian.conservativeResize(new_i, new_i); DEBUG << jacobian; } template <> inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ) {} template <> inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ) { //std::cout << " Update \n ------- \n " << update << std::endl; int tot_to_keep = 0; for (int i=neq_free; i= orig_r(i)) ++tot_to_keep; } //std::cout << " update \n ------ \n" << update.block(neq_free, 0, tot_to_keep, 1) << std::endl; update.conservativeResize(neq); grad_phi.conservativeResize(neq); int kept_i = 1; for (int i=neq-1; i>=neq_free; --i) { // we go backwards to avoid extra copies //std::cout << i << " # " << x(i) << " - " << orig_r(i) << std::endl; if (x(i) >= orig_r(i)) { //std::cout << i << std::endl; update(i) = update(neq_free+(tot_to_keep-kept_i)); //std::cout << update(i) << std::endl; grad_phi(i) = grad_phi(neq_free+(tot_to_keep-kept_i)); ++kept_i; } else { //x(i) = 0.0; //update(i) = 0.0; update(i) = -x(i); grad_phi(i) = x(i); } } } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/ncp_function.hpp b/src/micpsolver/ncp_function.hpp index 8a9733a..3042ae4 100644 --- a/src/micpsolver/ncp_function.hpp +++ b/src/micpsolver/ncp_function.hpp @@ -1,92 +1,94 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_MICPSOLVE_NCPFUNCTION_HPP #define SPECMICP_MICPSOLVE_NCPFUNCTION_HPP #include #include "../macros.hpp" //! \file ncp_function.hpp implements the ncp function namespace specmicp { namespace micpsolver { //! \brief The Fisher-Burmeister NCP-function //! //! \param a first variable of the NCP-function //! \param b second variable of the NCP-function //! //! References: //! - \cite Munson2001 //! - \cite Facchinei2003 template ScalarT SPECMICP_CONST_F fisher_burmeister(ScalarT a, ScalarT b) { ScalarT s = std::abs(a) + std::abs(b); if (s != 0) { s = s*std::sqrt((a*a)/(s*s) + (b*b)/(s*s)); } if ( a + b <= 0) { return s - (a + b); } else { return -2*a*b/(s + (a+b)); } } //! \brief The penalized Fisher-Burmeister NCP-function //! //! \param t in (0, 1), penalization factor //! \param a first variable of the NCP-function //! \param b second varaible of the NCP-function //! //! References: //! - \cite Chen1997a //! - \cite Chen2000 //! - \cite Munson2001 template ScalarT SPECMICP_CONST_F penalized_fisher_burmeister(ScalarT a, ScalarT b, ScalarT t) { specmicp_assert(t >= 0); specmicp_assert(t <= 1); return t*fisher_burmeister(a,b)-(1.0-t)*std::max(0.0, a)*std::max(0.0, b); } } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVE_NCPFUNCTION_HPP diff --git a/src/odeint/butcher_tableau.hpp b/src/odeint/butcher_tableau.hpp index 1faac87..a10c7a8 100644 --- a/src/odeint/butcher_tableau.hpp +++ b/src/odeint/butcher_tableau.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ODEINT_BUTCHERTABLEAU_HPP #define SPECMICP_ODEINT_BUTCHERTABLEAU_HPP //! \file butcher_tableau.hpp Butcher tableau for embedded runge kutta method #include #include "../types.hpp" namespace specmicp { namespace odeint { template class ButcherTableau { public: static const int RK_order = order; static const int RK_evaluations = s+1; ButcherTableau(const std::array& aa, const std::array, s>& ba, const std::array& ca, const std::array& csa ): m_a(aa), m_b(ba), m_c(ca), m_cs(csa) {} ButcherTableau(std::array&& aa, std::array, s>&& ba, std::array&& ca, std::array&& csa ): m_a(aa), m_b(ba), m_c(ca), m_cs(csa) {} double a(int i) const {return m_a[i-2];} double b(int i, int j) const {return m_b[i-2][j-1];} double c(int i) const {return m_c[i-1];} double cs(int i) const {return m_cs[i-1];} private: std::array m_a; std::array, s> m_b; std::array m_c; std::array m_cs; }; const ButcherTableau<5, 5> butcher_cash_karp45({1.0/5.0, 3.0/10.0, 3.0/5.0, 1.0, 7.0/8.0}, {{{1.0/5.0, 0, 0, 0, 0}, {3.0/40.0, 9.0/40.0, 0, 0, 0}, {3.0/10.0, -9.0/10.0, 6.0/5.0, 0, 0}, {-11.0/54.0, 5.0/2.0, -70.0/27.0, 35.0/27.0, 0}, {1631.0/55296.0, 175.0/512.0, 575.0/13824.0, 44275.0/110592.0, 253.0/4096.0} }}, {37.0/378.0, 0.0, 250.0/621.0, 125.0/594.0, 0.0, 512.0/1771.0}, {2825.0/27648.0, 0.0, 18575.0/48384.0, 13525.0/55296.0, 277.0/14336.0, 1.0/4.0} ); using ButcherTableauCashKarp_t = ButcherTableau<5, 5>; const ButcherTableau<5, 6> butcher_dormand_prince45( {1.0/5.0, 3.0/10.0, 4.0/5.0, 8.0/9.0, 1.0, 1.0}, { {{1.0/5.0, 0, 0, 0, 0, 0}, {3.0/40.0, 9.0/40.0, 0, 0, 0, 0}, {44.0/45.0, -56.0/15.0, 32.0/9.0, 0, 0, 0}, {19372.0/6561.0, -25360.0/2187.0, 64448.0/6561.0, -212.0/729.0, 0, 0}, {9017.0/3168.0, -355.0/33.0, 46732.0/5247.0, 49.0/176.0, -5103.0/18656.0, 0}, {35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0} }}, {35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0, 0.0}, {5179.0/57600.0, 0.0, 7571.0/16695.0, 393.0/640.0, -92097.0/339200.0, 187.0/2100.0, 1.0/40.0} ); using ButcherTableauDormandPrince_t = ButcherTableau<5, 6>; } // end namespace odeint } // end namespace specmicp #endif // SPECMICP_ODEINT_BUTCHERTABLEAU_HPP diff --git a/src/odeint/odeint_types.hpp b/src/odeint/odeint_types.hpp index 84b019c..b9b4094 100644 --- a/src/odeint/odeint_types.hpp +++ b/src/odeint/odeint_types.hpp @@ -1,125 +1,127 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ODEINT_ODEINTTYPES_HPP #define SPECMICP_ODEINT_ODEINTTYPES_HPP //! \file odeint_types.hpp common types for odeint #include "../types.hpp" #include #include namespace specmicp { //! \namespace specmicp::odeint //! \brief ODE integrators and related structs namespace odeint { namespace internal { //! \brief implementation for the vector type (which may not be a vector for dim=1) template struct vector_trait { using type = Eigen::Matrix; }; //! Specialisation for dimension 1 (scalar) template <> struct vector_trait<1> { using type = scalar_t; }; //! Specialization for dimension 2 (fixed-size vector) template <> struct vector_trait<2> { using type = Eigen::Matrix; }; //! Specialization for dimension 3 (fixed-size vector) template <> struct vector_trait<3> { using type = Eigen::Matrix; }; } // end namespace internal //! The vector type template using vector_t = typename internal::vector_trait::type; //! Return the maximum coefficient of the vector template inline scalar_t max_coeff(const vector_t& vec) {return vec.maxCoeff();} template <> inline scalar_t max_coeff<1>(const vector_t<1>& vec) {return vec;} //! \brief Type of the function f in dy/dx=f(x,y) template using rhs_f = std::function&, vector_t&)>; //! \brief Return true of all members of 'vec' are non-negative template inline bool is_nonnegative(vector_t& vec) { return (vec.array() >= Eigen::VectorXd::Zero(vec.rows()).array()).all(); } template <> inline bool is_nonnegative<1>(vector_t<1>& vec) { return vec >= 0.0; } //! \brief Project to the positive quadrant template inline void set_non_negative(vector_t& vec) { vec = vec.cwiseMax(Eigen::VectorXd::Zero(vec.rows())); } template <> inline void set_non_negative<1>(vector_t<1>& vec) { vec = std::max(0.0, vec); } } // end namespace odeint } // end namespace specmicp #endif // SPECMICP_ODEINT_ODEINTTYPES_HPP diff --git a/src/odeint/runge_kutta_step.hpp b/src/odeint/runge_kutta_step.hpp index af0c820..0b62775 100644 --- a/src/odeint/runge_kutta_step.hpp +++ b/src/odeint/runge_kutta_step.hpp @@ -1,196 +1,198 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP #define SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP //! \file runge_kutta_step.hpp //! \brief stepping algorithm for the embedded runge kutta ODE integration method #include "odeint_types.hpp" #include "butcher_tableau.hpp" #include "runge_kutta_step_structs.hpp" #include "../utils/options_handler.hpp" namespace specmicp { namespace odeint { struct StepLength { static constexpr scalar_t not_available = -1.0; scalar_t test; scalar_t did; scalar_t next; scalar_t total; StepLength(scalar_t h_test): test(h_test), did(not_available), next(not_available), total(0.0) {} StepLength(scalar_t h_test, scalar_t h_total): test(h_test), did(not_available), next(not_available), total(h_total) {} void get_next() { test=next; did=not_available; next=not_available; } bool is_next_available() {return next != not_available;} bool is_total_time_fixed() {return total > 0.0;} scalar_t remaining(scalar_t t) {return (total-t);} }; //! \brief Base class for computing a step of the Range Kutta algorithm template class EmbeddedRungeKuttaStep : public OptionsHandler { public: using vec_t = vector_t; EmbeddedRungeKuttaStep( const rhs_f& rhs, const butcher_tableau_t& butcher): m_rhs(rhs), m_butcher(butcher) {} EmbeddedRungeKuttaStep( const rhs_f& rhs, const butcher_tableau_t& butcher, EmbeddedRungeKuttaStepOptions& options ): OptionsHandler(options), m_rhs(rhs), m_butcher(butcher) {} //! \brief compute a step //! //! \param y initial value //! \param dydx initial value of the right hand site //! \param x value of the integration variable //! \param timestep the integration step //! \param y_out value at the end of the step (y+timestep) //! \param y_err estimation of the truncation error void run_step( const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err); protected: //! Return the value of the right hand side at x for value y void get_rhs( scalar_t x, const vector_t& y, vec_t& dydx ) {return m_rhs(x, y, dydx);} //! Return the Butcher tableau butcher_tableau_t& butcher() {return m_butcher;} private: rhs_f m_rhs; butcher_tableau_t m_butcher; }; //! Embedded Runge Kutta of fifth order template class EmbeddedRungeKuttaStep45: EmbeddedRungeKuttaStep { public: using base = EmbeddedRungeKuttaStep; using vec_t = typename base::vec_t; using base::butcher; using base::get_rhs; using base::get_options; //check that template argument are consistent static_assert(butcher_tableau_t::RK_order == 5, "The butcher tableau must correspond to a Runge-Kutta method of order 5"); static_assert(butcher_tableau_t::RK_evaluations == 6 || butcher_tableau_t::RK_evaluations == 7, "The number of functions evaluations must be 6 or 7 for an embedded Runge-Kutta method"); EmbeddedRungeKuttaStep45(const rhs_f& rhs, const butcher_tableau_t& butcher): base(rhs, butcher) { } EmbeddedRungeKuttaStep45( const rhs_f& rhs, const butcher_tableau_t& butcher, EmbeddedRungeKuttaStepOptions options ): base(rhs, butcher, options) { } void run_step(const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err); void rk_step(vector_t &y, const vector_t& dydx, double& x, StepLength& stepl); }; //! typedef to create a Dormant-Prince method template using DormandPrinceStep = EmbeddedRungeKuttaStep45; template DormandPrinceStep get_dormand_prince_step(const rhs_f& rhs) {return DormandPrinceStep(rhs, butcher_dormand_prince45);} //! typedef to create a Cash-Karp method template using CashKarpStep = EmbeddedRungeKuttaStep45; template CashKarpStep get_cash_karp_step(const rhs_f& rhs) {return CashKarpStep(rhs, butcher_cash_karp45);} template T get_rk_step(const rhs_f& rhs) { if (std::is_same>::value) return get_cash_karp_step(rhs); else if (std::is_same>::value) return get_dormand_prince_step(rhs); } } // end namespace odeint } // end namespace specmicp #include "runge_kutta_step.inl" #endif // SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP diff --git a/src/odeint/runge_kutta_step.inl b/src/odeint/runge_kutta_step.inl index b3043a7..b486d7a 100644 --- a/src/odeint/runge_kutta_step.inl +++ b/src/odeint/runge_kutta_step.inl @@ -1,124 +1,126 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP #include "runge_kutta_step.hpp" // syntaxic coloration only #endif namespace specmicp { namespace odeint { template void EmbeddedRungeKuttaStep45::run_step(const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err) { vec_t ak2, ak3, ak4, ak5, ak6; vec_t ytemp; ytemp = y + butcher().b(2, 1)*timestep*dydx; get_rhs(x + butcher().a(2)*timestep, ytemp, ak2); ytemp = y + timestep*(butcher().b(3,1)*dydx + butcher().b(3, 2)*ak2); get_rhs(x + butcher().a(3)*timestep, ytemp, ak3); ytemp = y + timestep*(butcher().b(4,1)*dydx + butcher().b(4, 2)*ak2 + butcher().b(4, 3)*ak3); get_rhs(x + butcher().a(4)*timestep, ytemp, ak4); ytemp = y + timestep*(butcher().b(5,1)*dydx + butcher().b(5, 2)*ak2 + butcher().b(5, 3)*ak3 + butcher().b(5, 4)*ak4); get_rhs(x + butcher().a(5)*timestep, ytemp, ak5); ytemp = y + timestep*(butcher().b(6,1)*dydx + butcher().b(6, 2)*ak2 + butcher().b(6, 3)*ak3 + butcher().b(6, 4)*ak4 + butcher().b(6, 5)*ak5); get_rhs(x + butcher().a(6)*timestep, ytemp, ak6); if (butcher_tableau_t::RK_evaluations == 6) { y_out = y + timestep*(butcher().c(1)*dydx + butcher().c(2)*ak2 + butcher().c(3)*ak3 + butcher().c(4)*ak4 + butcher().c(5)*ak5 + butcher().c(6)*ak6); y_err = timestep * ( (butcher().c(1) - butcher().cs(1))*dydx + (butcher().c(2) - butcher().cs(2))*ak2 + (butcher().c(3) - butcher().cs(3))*ak3 + (butcher().c(4) - butcher().cs(4))*ak4 + (butcher().c(5) - butcher().cs(5))*ak5 + (butcher().c(6) - butcher().cs(6))*ak6 ); } else { vec_t ak7; ytemp = y + timestep*(butcher().b(7,1)*dydx + butcher().b(7, 2)*ak2 + butcher().b(7, 3)*ak3 + butcher().b(7, 4)*ak4 + butcher().b(7, 5)*ak5 + butcher().b(7, 6)*ak6); get_rhs(x + butcher().a(7)*timestep, ytemp, ak7); y_out = y + timestep*(butcher().c(1)*dydx + butcher().c(2)*ak2 + butcher().c(3)*ak3 + butcher().c(4)*ak4 + butcher().c(5)*ak5 + butcher().c(6)*ak6 + butcher().c(7)*ak7); y_err = timestep * ( (butcher().c(1) - butcher().cs(1))*dydx + (butcher().c(2) - butcher().cs(2))*ak2 + (butcher().c(3) - butcher().cs(3))*ak3 + (butcher().c(4) - butcher().cs(4))*ak4 + (butcher().c(5) - butcher().cs(5))*ak5 + (butcher().c(6) - butcher().cs(6))*ak6 + (butcher().c(7) - butcher().cs(7))*ak7 ); } if (get_options().non_negativity) set_non_negative(y_out); } template void EmbeddedRungeKuttaStep45::rk_step(vector_t& y, const vector_t& dydx, double& x, StepLength& stepl) { vector_t y_err; vector_t y_temp; double h = stepl.test; scalar_t errmax; for (int i=0; i(y_err) / get_options().eps; if (errmax < 1) break; double htemp = get_options().safety*h*std::pow(errmax, get_options().p_shrink); h = (h >= 0.0 ? std::max(htemp, 0.1*h) : std::min(htemp, 0.1*h)); double xnew = x+h; if (xnew == x) {throw std::runtime_error("stepsize underflow");} } stepl.did = h; x += h; if (errmax > get_options().errcon) {stepl.next = get_options().safety*h*std::pow(errmax, get_options().p_grow);} else {stepl.next = 5.0*h;} y = y_temp; } } // end namespace odeint } // end namespace specmicp diff --git a/src/odeint/runge_kutta_step_structs.hpp b/src/odeint/runge_kutta_step_structs.hpp index 00ea5b0..49a1030 100644 --- a/src/odeint/runge_kutta_step_structs.hpp +++ b/src/odeint/runge_kutta_step_structs.hpp @@ -1,67 +1,69 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP #define SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP #include "../types.hpp" namespace specmicp { namespace odeint { struct EmbeddedRungeKuttaStepOptions { scalar_t safety; scalar_t p_grow; scalar_t p_shrink; scalar_t errcon; scalar_t max_try; scalar_t eps; bool non_negativity; EmbeddedRungeKuttaStepOptions(): safety(0.9), p_grow(-0.2), p_shrink(-0.25), errcon(1.89e-4), max_try(20), eps(1e-5), non_negativity(false) {} }; } // end namespace odeint } // end namespace specmicp #endif// SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP diff --git a/src/physics/constants.hpp b/src/physics/constants.hpp index 802470f..e4bbcf8 100644 --- a/src/physics/constants.hpp +++ b/src/physics/constants.hpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_CONSTANTS_CONSTANTS_HPP #define SPECMICP_CONSTANTS_CONSTANTS_HPP //! \file constants.hpp //! \brief Contains physical constants namespace specmicp { //! \namespace specmicp::constants //! \brief Constants used by SpecMiCP namespace constants { constexpr double gas_constant = 8.3144621; //!< Perfect gas constant (J / K mol) constexpr double water_density_25 = 997.05; //!< Density of water (kg / m^3) constexpr double water_density_25_kgl = 0.99705; //!< Density of water (kg / L) constexpr double water_viscosity = 8.937e-4; //!< Viscosity water (Pa.s) constexpr double water_molar_mass = 18.01528e-3; //!< Molar mass water (kg / mol) constexpr double Adebye = 0.5092; //!< constant 'A' for Debye-Huckel activity coefficient constexpr double Bdebye = 0.3283; //!< constant 'B' for Debye-Huckel activity coefficient constexpr double faraday_constant = 9.6485339924e4 ; //! the Faraday constant (C / mol) } // end namespace constants } // end namespace specmicp #endif // SPECMICP_CONSTANTS_CONSTANTS_HPP diff --git a/src/physics/io/units.cpp b/src/physics/io/units.cpp index 44c4f13..7ec64b2 100644 --- a/src/physics/io/units.cpp +++ b/src/physics/io/units.cpp @@ -1,75 +1,77 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "units.hpp" #include "../units.hpp" namespace specmicp { namespace io { //! \brief Transform a length unit into a string std::string length_unit_to_string(units::LengthUnit length_u) { std::string str; str.reserve(2); switch (length_u) { case units::LengthUnit::meter: str = "m"; break; case units::LengthUnit::decimeter: str = "dm"; break; case units::LengthUnit::centimeter: str = "cm"; break; } return str; } //! \brief Return a string describing the surface unit std::string surface_unit_to_string(units::LengthUnit length_u) { return length_unit_to_string(length_u) + "^2"; } //! \brief Return a string describing the volume unit std::string volume_unit_to_string(units::LengthUnit length_u) { return length_unit_to_string(length_u) + "^3"; } } //end namespace io } //end namespace specmicp diff --git a/src/physics/io/units.hpp b/src/physics/io/units.hpp index 3c59076..e7e8ae1 100644 --- a/src/physics/io/units.hpp +++ b/src/physics/io/units.hpp @@ -1,72 +1,74 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_UNITS_HPP #define SPECMICP_IO_UNITS_HPP //! \file physics/io/units.hpp //! \brief Print information about the units #include "../../types.hpp" #include namespace specmicp { namespace units { enum class LengthUnit; } //end namespace units //! \namespace specmicp::io //! \brief Input/output helper functions namespace io { //! \brief Transform a length unit into a string std::string SPECMICP_DLL_PUBLIC SPECMICP_PURE_F length_unit_to_string(units::LengthUnit length_u); //! \brief Return a string describing the surface unit std::string SPECMICP_DLL_PUBLIC SPECMICP_PURE_F surface_unit_to_string(units::LengthUnit length_u); //! \brief Return a string describing the volume unit std::string SPECMICP_DLL_PUBLIC SPECMICP_PURE_F volume_unit_to_string(units::LengthUnit length_u); } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_UNITS_HPP diff --git a/src/physics/laws.cpp b/src/physics/laws.cpp index 0a54bd0..dbaf0ca 100644 --- a/src/physics/laws.cpp +++ b/src/physics/laws.cpp @@ -1,76 +1,78 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "laws.hpp" #include "units.hpp" #include namespace specmicp { namespace laws { scalar_t debye_huckel(scalar_t sqrtI, scalar_t zi, scalar_t ao) { if (zi == 0.0) return 0.0; scalar_t res = 0.0; const scalar_t zisquare = std::pow(zi, 2); res = - constants::Adebye*zisquare*sqrtI; const scalar_t denom = (1 + ao*constants::Bdebye*sqrtI); res /= denom; return res; } scalar_t extended_debye_huckel(scalar_t I, scalar_t sqrtI, scalar_t zi, scalar_t ao, scalar_t bdot) { const scalar_t tmp = debye_huckel(sqrtI, zi, ao); return tmp + bdot*I; } scalar_t extended_debye_huckel(scalar_t I, scalar_t zi, scalar_t ao, scalar_t bdot) { const scalar_t tmp = debye_huckel(std::sqrt(I), zi, ao); return tmp + bdot*I; } scalar_t density_water(scalar_t temperature, units::LengthUnit length_unit, units::MassUnit mass_unit) { scalar_t scaling = 1.0; if (mass_unit == units::MassUnit::gram) scaling *= 1e-3; if (length_unit == units::LengthUnit::centimeter) scaling *= 1e-6; else if (length_unit == units::LengthUnit::decimeter) scaling = 1e-3; return scaling*constants::water_density_25; } } // end namespace laws } // end namespace specmicp diff --git a/src/physics/laws.hpp b/src/physics/laws.hpp index 69156a3..af56647 100644 --- a/src/physics/laws.hpp +++ b/src/physics/laws.hpp @@ -1,134 +1,136 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_LAWS_LAWS_HPP #define SPECMICP_LAWS_LAWS_HPP //! \file laws.hpp //! \brief Simple physical laws #include "../types.hpp" #include "constants.hpp" namespace specmicp { namespace units { enum class LengthUnit; enum class MassUnit; } //end namespace units //! \namespace specmicp::laws //! \brief Physical laws namespace laws { //! \brief Return the pressure of a perfect gas //! //! \param n the number of moles (mol) //! \param V the volume (m^3) //! \param T the temperature (K) inline constexpr scalar_t pressure_perfect_gas(scalar_t n, scalar_t V, scalar_t T=298.15) { return n*constants::gas_constant*T/V; } //! \brief Return the number of moles for a perfect gas //! //! \param P the pressure (Pa) //! \param V the volume (m^3) //! \param T the temperature (K) inline constexpr scalar_t mole_perfect_gas(scalar_t P, scalar_t V, scalar_t T=298.15) { return P*V/(constants::gas_constant*T); } //! \brief The Debye-Huckel law //! //! at 25°C //! //! \f[ \log \gamma_k = - \frac{A z_k^2 \sqrt{I}}{1 + a B \sqrt{I}} \f] //! //! \param sqrtI square root of the ionic strength //! \param zi Charge of the ion //! \param ao ion size parameter //! scalar_t SPECMICP_DLL_PUBLIC SPECMICP_PURE_F debye_huckel(scalar_t sqrtI, scalar_t zi, scalar_t ao); //! \brief The Bdot law //! //! at 25°C //! //! \f[ \log \gamma_k = - \frac{A z_k^2 \sqrt{I}}{1 + a B \sqrt{I}} + \dot{B} I \f] //! //! //! \param I square ionic strength //! \param zi Charge of the ion //! \param ao ion size parameter //! \param bdot 'bdot' parameter //! scalar_t SPECMICP_DLL_PUBLIC SPECMICP_PURE_F extended_debye_huckel(scalar_t I, scalar_t zi, scalar_t ao, scalar_t bdot); //! \brief The Bdot law //! //! at 25°C //! //! This version accepts the value of \f$\sqrt{I}\f$. //! //! \f[ \log \gamma_k = - \frac{A z_k^2 \sqrt{I}}{1 + a B \sqrt{I}} + \dot{B} I \f] //! //! \param I square ionic strength //! \param sqrtI square root of the ionic strength //! \param zi Charge of the ion //! \param ao ion size parameter //! \param bdot 'bdot' parameter //! scalar_t SPECMICP_DLL_PUBLIC SPECMICP_PURE_F extended_debye_huckel(scalar_t I, scalar_t sqrtI, scalar_t zi, scalar_t ao, scalar_t bdot); //! \brief Return the density of water in the correct units //! //! \param temperature the temperature //! \param length_unit the lenght unit //! \param mass_unit the mass unit scalar_t SPECMICP_DLL_PUBLIC SPECMICP_PURE_F density_water(scalar_t temperature, units::LengthUnit length_unit, units::MassUnit mass_unit); } // end namespace laws } // end namespace specmicp #endif // SPECMICP_LAWS_LAWS_HPP diff --git a/src/physics/maths.hpp b/src/physics/maths.hpp index 866c78e..6a45701 100644 --- a/src/physics/maths.hpp +++ b/src/physics/maths.hpp @@ -1,114 +1,116 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_MATHS_HPP #define SPECMICP_UTILS_MATHS_HPP /*! \file maths.hpp \brief Simple math functions */ #include "../types.hpp" namespace specmicp { //! \brief Average methods available enum class Average { arithmetic, geometric, harmonic }; //! \brief Average two numbers //! //! \tparam average the average method template scalar_t SPECMICP_CONST_F average(scalar_t a, scalar_t b); template<> inline scalar_t SPECMICP_CONST_F average(scalar_t a, scalar_t b) { return (a + b)/2.0; } template<> inline scalar_t SPECMICP_CONST_F average(scalar_t a, scalar_t b) { return 2.0/(1.0/a + 1.0/b); } template<> inline scalar_t SPECMICP_CONST_F average(scalar_t a, scalar_t b) { return std::sqrt(a*b); } //! \brief Average a vector //! //! \tparam average the average method //! \param vector the vector to average template scalar_t SPECMICP_CONST_F average(const Vector& vector); template<> inline scalar_t SPECMICP_CONST_F average(const Vector& vector) { return vector.sum()/vector.rows(); } template<> inline scalar_t SPECMICP_CONST_F average(const Vector& vector) { return std::pow(vector.prod(), 1.0/vector.rows()); } template<> inline scalar_t SPECMICP_CONST_F average(const Vector& vector) { scalar_t sum = 0; for (index_t ind=0; ind Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "units.hpp" #include namespace specmicp { namespace units { scalar_t scaling_factor(LengthUnit length_unit) { scalar_t scaling = NAN; // just to be sure in case another unit is added switch(length_unit) { case LengthUnit::meter: scaling = 1.0; break; case LengthUnit::decimeter: scaling = 0.1; break; case LengthUnit::centimeter: scaling = 0.01; } return scaling; } scalar_t convert_pressure(scalar_t pressure_si, LengthUnit length_unit) { scalar_t pressure; switch (length_unit) { case LengthUnit::meter: pressure = pressure_si; break; case LengthUnit::decimeter: pressure = 1e-2*pressure_si; break; case LengthUnit::centimeter: pressure = 1e-4*pressure_si; } return pressure; } AmountUnit parse_amount_unit(const std::string& unit) { AmountUnit amounts; parse_amount_unit(unit, amounts); return amounts; } void parse_amount_unit(std::string unit, AmountUnit& amounts) { auto n = unit.find("/"); amounts.type = AmountUnitType::Unknown; amounts.factor_si = -1; scalar_t factor; if (n == std::string::npos) { unit.erase(std::remove(unit.begin(), unit.end(), ' '), unit.end()); factor = is_mass_unit(unit); if (factor > 0) { amounts.type = AmountUnitType::Mass; amounts.factor_si = factor; return; } factor = is_mole_unit(unit); if (factor > 0) { amounts.type = AmountUnitType::NumberOfMoles; amounts.factor_si = factor; return; } factor = is_volume_unit(unit); if (factor > 0) { amounts.type = AmountUnitType::Volume; amounts.factor_si = factor; return; } } else { // composite unit std::string numer = unit.substr(0, n); numer.erase(std::remove(numer.begin(), numer.end(), ' '), numer.end()); std::string denom = unit.substr(n+1, unit.size()-n); denom.erase(std::remove(denom.begin(), denom.end(), ' '), denom.end()); scalar_t factor_numer = -1; scalar_t factor_denom = -1; factor_denom = is_volume_unit(denom); if (factor_denom > 0) { // concentration factor_numer = is_mass_unit(numer); if (factor_numer > 0) { amounts.type = AmountUnitType::MassConcentration; amounts.factor_si = factor_numer / factor_denom; return; } factor_numer = is_mole_unit(numer); if (factor_numer > 0) { amounts.type = AmountUnitType::MoleConcentration; amounts.factor_si = factor_numer / factor_denom; return; } return; } factor_denom = is_mass_unit(denom); if (factor_denom > 0) { factor_numer = is_mole_unit(numer); if (factor_numer > 0) { amounts.type = AmountUnitType::Molality; amounts.factor_si = factor_numer / factor_denom; return; } } } } scalar_t is_mass_unit(const std::string& unit) { scalar_t factor = -1; if (unit == "kg" or unit == "kilogram") factor = 1; else if (unit == "g" or unit == "gram") factor = 1e-3; return factor; } scalar_t is_length_unit(const std::string& unit) { scalar_t factor = -1; if (unit == "m" or unit == "meter") factor = 1; else if (unit == "dm" or unit == "decimeter") factor = 0.1; else if (unit == "cm" or unit == "centimeter") factor = 0.01; else if (unit == "mm" or unit == "millimeter") factor = 1e-3; return factor; } scalar_t is_volume_unit(const std::string& unit) { scalar_t factor = -1; if (unit == "m^3" or unit == "cubicmeter") factor = 1; else if (unit == "dm^3" or unit == "cubicdecimeter") factor = 1e-3; else if (unit == "cm^3" or unit == "cubiccentimeter") factor = 1e-6; else if (unit == "mm^3" or unit == "cubicmillimeter") factor = 1e-9; return factor; } scalar_t is_mole_unit(const std::string &unit) { scalar_t factor = -1; if (unit == "mol" or unit == "moles") factor = 1; else if (unit == "mmol" or unit == "millimoles") factor = 1e-3; return factor; } } //end namespace units } //end namespace specmicp diff --git a/src/physics/units.hpp b/src/physics/units.hpp index b6fc128..39e213b 100644 --- a/src/physics/units.hpp +++ b/src/physics/units.hpp @@ -1,189 +1,191 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UNITS_UNITS #define SPECMICP_UNITS_UNITS #include "../types.hpp" //! \file physics/units.hpp //! \brief units management and conversion namespace specmicp { //! \namespace specmicp::units //! \brief Units management namespace units { //! units used for length enum class LengthUnit { meter, decimeter, centimeter }; //! \brief Return the scaling factor from the SI unit to the given unit //! //! Ex: if length_unit=cm, it returns 1e-2 scalar_t scaling_factor(LengthUnit length_unit) SPECMICP_CONST_F; //! units used for mass enum class MassUnit { kilogram, gram }; //! \brief Simple struct which contains the unit information struct UnitsSet { MassUnit mass; //!< The unit to use for mass LengthUnit length; //!< The unit to use for length (also area and volume) //! \brief Defaults are the SI unit system UnitsSet(): mass(MassUnit::kilogram), length(LengthUnit::meter) {} }; //! \brief Base class that handles the units //! //! To be inherited by other classes that need units class UnitBaseClass { public: UnitBaseClass() {} UnitBaseClass(UnitsSet units): m_units(units) {} //! \brief Return the units const UnitsSet& get_units() const {return m_units;} //! \brief Set the units void set_units(UnitsSet units) {m_units = units;} //! \brief Return the Mass unit MassUnit mass_unit() const {return m_units.mass;} //! \brief Return the Length unit LengthUnit length_unit() const {return m_units.length;} //! \brief Return the mass unit MassUnit& mass_unit() {return m_units.mass;} //! \brief Return the length unit LengthUnit& length_unit() {return m_units.length;} private: UnitsSet m_units; }; //! \brief the type of an 'amount' unit enum class AmountUnitType { Mass, Volume, NumberOfMoles, MoleConcentration, MassConcentration, Molality, Unknown }; //! \brief Description of an amount unit struct AmountUnit { AmountUnitType type; //!< The unit type scalar_t factor_si; //!< unit*factor_si = SI unit }; //! \brief Find the unit and factor of 'unit' //! //! \param unit the unit to analyse //! \param amounts void parse_amount_unit(std::string unit, AmountUnit& amounts); //! \brief Finf the unit and factor of 'unit' AmountUnit parse_amount_unit(const std::string& unit); //! \brief Check if 'unit' is a mass unit //! //! \return if it is a mass unit return the factor to transform it to its SI equivalent, else return a negative number scalar_t is_mass_unit(const std::string& unit); //! \brief Check if 'unit' is a length unit //! //! \return if it is a length unit return the factor to transform it to its SI equivalent, else return a negative number scalar_t is_length_unit(const std::string& unit); //! \brief Check if 'unit' is a volume unit //! //! \return if it is a volume unit return the factor to transform it to its SI equivalent, else return a negative number scalar_t is_volume_unit(const std::string& unit); //! \brief Check if 'unit' is a mole unit //! //! \return if it is a mole unit return the factor to transform it to its SI equivalent, else return a negative number scalar_t is_mole_unit(const std::string& unit); // Temperature // ----------- //! \brief Convert a temperature from Celsius to Kelvin inline constexpr scalar_t celsius(scalar_t tc) {return tc + 273.15;} //! \brief Convert a temperature from Kelvin to Celsius inline constexpr scalar_t to_celsius(scalar_t tk) { return tk - 273.15;} //! \brief Convert a pressure from bar to pascal inline constexpr scalar_t bar(scalar_t pb) {return 1e5*pb;} //! \brief Convert a pressure from pascal to bar inline constexpr scalar_t to_bar(scalar_t ppa) {return 1e-5*ppa;} //! \brief Convert a pressure from atm to pascal inline constexpr scalar_t atm(scalar_t patm) {return 101325*patm;} //! \brief Convert a pressure from pascal to atm inline constexpr scalar_t to_atm(scalar_t ppa) {return ppa/101325;} // Volume // ------ //! Convert liter to cubic meter inline constexpr scalar_t liter(scalar_t vl) {return 1e-3*vl;} //! convert cubic meter to liter inline constexpr scalar_t to_liter(scalar_t vcm) {return 1e3*vcm;} // Pressure // -------- scalar_t SPECMICP_DLL_PUBLIC convert_pressure(scalar_t pressure_si, LengthUnit length_unit); } // end namespace units } // end namespace specmicp #endif // SPECMICP_UNITS_UNITS diff --git a/src/physics/unsaturated_laws.cpp b/src/physics/unsaturated_laws.cpp index 7857c21..7ff036f 100644 --- a/src/physics/unsaturated_laws.cpp +++ b/src/physics/unsaturated_laws.cpp @@ -1,89 +1,91 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "unsaturated_laws.hpp" #include "laws.hpp" #include "units.hpp" namespace specmicp { namespace laws { scalar_t kelvin_equation(scalar_t rh) { return -(constants::gas_constant * units::celsius(25.0) * constants::water_density_25 / constants::water_molar_mass )*std::log(rh); } scalar_t invert_kelvin_equation(scalar_t pc) { return std::exp( -constants::water_molar_mass / ( constants::gas_constant * units::celsius(25.0) * constants::water_density_25 ) * pc ); } scalar_t capillary_pressure_BaroghelBouny( scalar_t saturation, scalar_t a, scalar_t b ) { auto tmp = std::pow(saturation, -b) - 1.0; return a*std::pow(tmp, 1.0-1.0/b); } scalar_t relative_liquid_permeability_Mualem( scalar_t saturation, scalar_t m ) { auto tmp = 1.0 - std::pow(saturation, 1.0/m); auto tmp2 = 1.0 - std::pow(tmp, m); return std::sqrt(saturation) * std::pow(tmp2, 2); } scalar_t relative_gas_permeability_Mualem( scalar_t saturation, scalar_t m ) { auto tmp = 1.0 - std::pow(saturation, 1.0/m); return std::sqrt(1.0-saturation)*std::pow(tmp, 2*m); } } //end namespace laws } //end namespace specmicp diff --git a/src/physics/unsaturated_laws.hpp b/src/physics/unsaturated_laws.hpp index 8020866..f8d18f1 100644 --- a/src/physics/unsaturated_laws.hpp +++ b/src/physics/unsaturated_laws.hpp @@ -1,115 +1,117 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PHYSICS_UNSATURATEDLAWS_HPP #define SPECMICP_PHYSICS_UNSATURATEDLAWS_HPP //! \file physics/unsaturated_laws.hpp //! \brief Common laws and models in unsaturated porous medium #include "../types.hpp" namespace specmicp { namespace laws { //! \brief Return the capillary pressure as function of the relative humidity scalar_t SPECMICP_DLL_PUBLIC kelvin_equation(scalar_t rh); //! \brief Return the relative humidity as function of the capillary pressure scalar_t SPECMICP_DLL_PUBLIC invert_kelvin_equation(scalar_t pc); //! \brief Capillary Pressure model used by V. Baroghel-Bouny et al. //! //! \f$ Pc(S_l) = a (S_l^{-b} - 1)^{1-1/b} \f$ //! //! \param saturation the liquid saturation //! \param a fitting coefficient, unit of pressure //! \param b fitting coefficient, dimensioneless, >1 scalar_t SPECMICP_DLL_PUBLIC capillary_pressure_BaroghelBouny( scalar_t saturation, scalar_t a, scalar_t b ); //! \brief The Mualem model for relative liquid permeability //! //! \f$ k_{rl}(S_l) = \sqrt{S_l}\left(1 - \left(1-S_l^{1/m}\right)^m\right)^2 \f$ //! //! \param saturation the liquid saturation //! \param m a fitting coefficient //! //! In Baroghel-Bouny et al. m=1.0/b scalar_t SPECMICP_DLL_PUBLIC relative_liquid_permeability_Mualem( scalar_t saturation, scalar_t m ); //! \brief The mualem Model for relative gas permeability //! //! \f$ k_{rg} = \sqrt{1-S_l} \left(1 - S)l^{1/m} \right)^{2m} scalar_t SPECMICP_DLL_PUBLIC relative_gas_permeability_Mualem( scalar_t saturation, scalar_t m ); //! \brief Type of a model of the saturation using saturation_model_f = std::function; //! \brief Return a model function of the saturation //! //! \tparam F a model where saturation is the first parameter //! \tparam ...Args Parameter pack representing the parameters of the model //! \return a function taking only the saturation //! //! Bind the argument of the model template saturation_model_f make_saturation_model(F func, Args...args) { return [func,args...](scalar_t saturation) -> scalar_t { return func(saturation, args...); }; } //! \brief Return a relative humidity model from a capillary pressure model //! //! Use the kelvin equation inline saturation_model_f make_rh_model(saturation_model_f cap_pressure) { return [cap_pressure](scalar_t saturation) -> scalar_t { return invert_kelvin_equation(cap_pressure(saturation)); }; } } //end namespace laws } //end namespace specmicp #endif // SPECMICP_PHYSICS_UNSATURATEDLAWS_HPP diff --git a/src/reactmicp.hpp b/src/reactmicp.hpp index f67cc2a..b3697b4 100644 --- a/src/reactmicp.hpp +++ b/src/reactmicp.hpp @@ -1,42 +1,44 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ //! \file reactmicp.hpp //! \brief Include all reactmicp // The saturated system #include "reactmicp_saturated.hpp" // The unsaturated system #include "reactmicp_unsaturated.hpp" diff --git a/src/reactmicp/equilibrium_curve/chemistry.cpp b/src/reactmicp/equilibrium_curve/chemistry.cpp index ee0dc65..7990a42 100644 --- a/src/reactmicp/equilibrium_curve/chemistry.cpp +++ b/src/reactmicp/equilibrium_curve/chemistry.cpp @@ -1,137 +1,139 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "chemistry.hpp" #include "../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../specmicp/adimensional/adimensional_system_solver.hpp" #include "../../utils/log.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { // EquilibriumCurveSpeciation:: void EquilibriumCurveSpeciation::output() { index_t size = m_eqcurve.rows(); if (m_cnt == size) m_eqcurve.conservativeResize(size+500, 4); m_eqcurve.block(size, 0, m_eqcurve.rows()-size, 4).setZero(); AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); m_eqcurve(m_cnt, 0) = sol.total_solid_concentration(m_idc); m_eqcurve(m_cnt, 1) = sol.total_aqueous_concentration(m_idc); m_eqcurve(m_cnt, 2) = sol.porosity(); m_eqcurve(m_cnt, 3) = m_eqcurve(m_cnt, 2)>0.92?2.219e-5:1e4*std::exp(9.95*m_eqcurve(m_cnt, 2)-29.08); std::cout << m_eqcurve(m_cnt, 0) << " \t " << m_eqcurve(m_cnt, 1) << std::endl; } Matrix EquilibriumCurveSpeciation::get_equilibrium_curve(scalar_t end_total_concentration, scalar_t delta) { m_cnt = 0; solve_first_problem(); output(); AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); index_t nb_steps = std::abs(end_total_concentration - constraints().total_concentrations(m_idc))/( std::abs(delta)*sol.total_aqueous_concentration(m_idc)); std::cout << nb_steps << std::endl; m_eqcurve = Matrix::Zero(nb_steps, 4); m_delta = delta; ///(nb_steps-1); while (constraints().total_concentrations(m_idc) > end_total_concentration) { //std::cout << m_cnt << " - " << conditions().total_concentrations(m_idc) << std::endl; run_step(); ++m_cnt; } m_eqcurve.conservativeResize(m_cnt, 4); return m_eqcurve; } void EquilibriumCurveSpeciation::update_problem() { Vector diff_conc = get_perturbation(); scalar_t coeff = m_delta; for (index_t component: m_data->range_component()) { if (std::abs(constraints().total_concentrations(component)) < 1e-4) { constraints().total_concentrations(component) = 0.0; diff_conc(component) = 0.0; } if (constraints().total_concentrations(component) != 0 and std::copysign(1.0, constraints().total_concentrations(component) + coeff*diff_conc(component)) != std::copysign(1.0, constraints().total_concentrations(component)) ) { //std::cout << "Component : " << component << std::endl; coeff = std::copysign(0.9*constraints().total_concentrations(component), m_delta); coeff /= diff_conc(component); } } //std::cout << "Update : " << std::endl << coeff*diff_conc << std::endl; constraints().total_concentrations += coeff*diff_conc; // std::cout << "total concentrations : " << std::endl << conditions().total_concentrations << std::endl; } Vector EquilibriumCurveSpeciation::get_perturbation() { AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); Vector tot_aq_conc(m_data->nb_component()); tot_aq_conc.setZero(); for (index_t component: m_data->range_aqueous_component()) { tot_aq_conc(component) = sol.total_aqueous_concentration(component); } //tot_aq_conc *= m_delta/tot_aq_conc.norm(); return tot_aq_conc; } void EquilibriumCurveSpeciation::error_handling(std::string msg) const { ERROR << msg; ERROR << " Total concentration " << std::endl << constraints().total_concentrations << std::endl; throw std::runtime_error(msg); } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/chemistry.hpp b/src/reactmicp/equilibrium_curve/chemistry.hpp index a5329d7..7b96360 100644 --- a/src/reactmicp/equilibrium_curve/chemistry.hpp +++ b/src/reactmicp/equilibrium_curve/chemistry.hpp @@ -1,89 +1,91 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP #define SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP #include "../../types.hpp" #include "../../specmicp/adimensional/equilibrium_curve.hpp" #include "../../physics/units.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { class SPECMICP_DLL_PUBLIC EquilibriumCurveSpeciation: public EquilibriumCurve, public units::UnitBaseClass { public: EquilibriumCurveSpeciation( RawDatabasePtr thedatabase, AdimensionalSystemConstraints constraints, index_t id_component, AdimensionalSystemSolverOptions options ): EquilibriumCurve(thedatabase, constraints), UnitBaseClass(options.units_set), m_data(thedatabase), m_idc(id_component) { solver_options() = options; } void output(); void update_problem(); Matrix get_equilibrium_curve(scalar_t end_total_concentration, scalar_t delta); Vector get_perturbation(); void error_handling(std::string msg) const; private: RawDatabasePtr m_data; index_t m_idc; Matrix m_eqcurve; index_t m_cnt; scalar_t m_delta; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp b/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp index 7ad28b2..dfcd301 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp @@ -1,109 +1,111 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "eqcurve_coupler.hpp" #include "../../dfpm/meshes/mesh1d.hpp" #include "../../dfpm/1dtransport/diffusion_parameters.hpp" #include "../../dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { EquilibriumCurveCoupler::EquilibriumCurveCoupler(Matrix& eq_curve, mesh::Mesh1DPtr the_mesh , dfpmsolver::ParabolicDriverOptions options): m_eqcurve(eq_curve), m_mesh(the_mesh), m_param(std::make_shared(m_mesh->nb_nodes())), m_aqueous_concentrations(the_mesh->nb_nodes()), m_solid_concentrations(the_mesh->nb_nodes()), m_transport_program(the_mesh, m_param, {0,}), m_transport_solver(m_transport_program) { m_transport_solver.get_options() = options; index_t last = m_eqcurve.last(); m_aqueous_concentrations(0) = m_eqcurve.totaq_concentration(last); m_solid_concentrations(0) = m_eqcurve.totsolid_concentration(last); m_param->porosity(0) = m_eqcurve.porosity(last); m_param->diffusion_coefficient(0) = m_eqcurve.diffusion_coefficient(last); index_t first = m_eqcurve.first(); for (index_t node=1; nodenb_nodes(); ++node) { m_aqueous_concentrations(node) = m_eqcurve.totaq_concentration(first); m_solid_concentrations(node) = m_eqcurve.totsolid_concentration(first); m_param->porosity(node) = m_eqcurve.porosity(first); m_param->diffusion_coefficient(node) = m_eqcurve.diffusion_coefficient(first); } } void EquilibriumCurveCoupler::run_step(scalar_t timestep) { dfpmsolver::ParabolicDriverReturnCode retcode = m_transport_solver.solve_timestep(timestep, m_aqueous_concentrations); if (retcode <= dfpmsolver::ParabolicDriverReturnCode::NotConvergedYet) { throw std::runtime_error("Cannot solve the transport problem, retcode : "+std::to_string((int) retcode)); } chemistry_step(); } void EquilibriumCurveCoupler::chemistry_step() { for (index_t node=1; nodenb_nodes(); ++node) { index_t index = m_eqcurve.find_point(m_solid_concentrations(node)); //std::cout << index << std::endl; scalar_t ceq = m_eqcurve.totaq_concentration(index); //std::cout << m_solid_concentrations(node) << " - diff : " << m_eqcurve.porosity(index)*(ceq-m_aqueous_concentrations(node)) << std::endl; m_solid_concentrations(node) -= std::min( m_solid_concentrations(node), m_eqcurve.porosity(index)*(ceq-m_aqueous_concentrations(node))); m_aqueous_concentrations(node) = ceq; // ###FIXME -> locate node using previous guess index = m_eqcurve.find_point(m_solid_concentrations(node)); m_param->porosity(node) = m_eqcurve.porosity(index); m_param->diffusion_coefficient(node)= m_eqcurve.diffusion_coefficient(index); } } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp b/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp index 612ed1e..51b4bfd 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp @@ -1,87 +1,89 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_EQCURVECOUPLER_HPP #define SPECMICP_REACTMICP_EQCURVECOUPLER_HPP #include "eqcurve_extractor.hpp" #include "../../dfpm/meshes/mesh1dfwd.hpp" #include "../../dfpm/1dtransport/diffusion.hpp" #include "../../dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace dfpm { struct SaturatedDiffusion1DParameters; } // end namespace dfpm namespace reactmicp { //! \namespace specmicp::eqcurve //! \brief Equilibrium approach to reactive transport namespace eqcurve { class SPECMICP_DLL_PUBLIC EquilibriumCurveCoupler { public: EquilibriumCurveCoupler(Matrix& eq_curve, mesh::Mesh1DPtr the_mesh, dfpmsolver::ParabolicDriverOptions options ); void run_step(scalar_t timestep); Vector& solid_concentrations() {return m_solid_concentrations;} Vector& aqueous_concentrations() {return m_aqueous_concentrations;} void chemistry_step(); private: EquilibriumCurveExtractor m_eqcurve; mesh::Mesh1DPtr m_mesh; std::shared_ptr m_param; Vector m_aqueous_concentrations; Vector m_solid_concentrations; dfpm::SaturatedDiffusion1D m_transport_program; dfpmsolver::ParabolicDriver m_transport_solver; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVECOUPLER_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp b/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp index 549deb0..66e805f 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp @@ -1,98 +1,100 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "eqcurve_extractor.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { index_t EquilibriumCurveExtractor::find_point(scalar_t x) { index_t index; const index_t size = m_eqcurve.rows(); index_t lower_index = 0; index_t upper_index = size+1; while (upper_index - lower_index > 1) { index = (upper_index + lower_index) /2; if ((x >= xs_offset(index)) == is_increasing()) lower_index = index; else upper_index = index; } if (x == xs_offset(1)) index = 0; else if (x == xs_offset(size)) index = size-1; else index = std::max((specmicp::index_t) 0, lower_index-1); return index; } scalar_t EquilibriumCurveExtractor::interpolate(index_t index, scalar_t x, index_t col) { // limit if (is_increasing()) { if (x <= m_eqcurve(first(), 0)) return m_eqcurve(first(), col); else if (x >= m_eqcurve(last(), 0)) return m_eqcurve(last(), col); } else { if (x >= m_eqcurve(first(), 0)) return m_eqcurve(first(), col); else if (x <= m_eqcurve(last(), 0)) return m_eqcurve(last(), col); } scalar_t y; const scalar_t diff = slope(index, col); y = m_eqcurve(index, col) + diff*(m_eqcurve(index+1,0)-x); return y; } scalar_t EquilibriumCurveExtractor::slope(index_t index, index_t col) { if (index == last()) return (m_eqcurve(index-1,col)-m_eqcurve(index,col))/(m_eqcurve(index-1,0)-m_eqcurve(index,0)); return (m_eqcurve(index+1,col)-m_eqcurve(index,col))/(m_eqcurve(index+1,0)-m_eqcurve(index,0)); } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp b/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp index 39dadb7..ad1cbcd 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp @@ -1,99 +1,101 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP #define SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP #include "../../types.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { class SPECMICP_DLL_PUBLIC EquilibriumCurveExtractor { public: EquilibriumCurveExtractor(const Matrix& eq_curve): m_eqcurve(eq_curve) { m_is_increasing = (xs_offset(m_eqcurve.rows()) >= xs_offset(1)); } EquilibriumCurveExtractor(Matrix&& eq_curve): m_eqcurve(eq_curve) { m_is_increasing = (xs_offset(m_eqcurve.rows()) >= xs_offset(1)); } index_t find_point(scalar_t x); index_t first() {return 0;} index_t last() {return m_eqcurve.rows()-1;} bool is_increasing() {return m_is_increasing;} scalar_t totsolid_concentration(index_t index) { return m_eqcurve(index, 0); } scalar_t totaq_concentration(index_t index) { return m_eqcurve(index, 1); } scalar_t porosity(index_t index) { return m_eqcurve(index, 2); } scalar_t diffusion_coefficient(index_t index) { return m_eqcurve(index, 3); } scalar_t interpolate(index_t index, scalar_t x, index_t col); scalar_t slope(index_t index, index_t col); private: scalar_t SPECMICP_DLL_LOCAL xs_offset(index_t offset_index) { return m_eqcurve(offset_index-1, 0); } Matrix m_eqcurve; bool m_is_increasing; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp index e7eb4c1..100fd44 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp @@ -1,265 +1,267 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "eqcurve_solid_transport.hpp" #include "../../dfpm/meshes/mesh1d.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { // SolidDiffusion:: SolidDiffusion::SolidDiffusion( mesh::Mesh1DPtr the_mesh, const Matrix& eq_curve, std::vector list_bcs ): m_tot_ndf(the_mesh->nb_nodes()), m_mesh(the_mesh), m_eqcurve(eq_curve), m_internal_flow(Vector::Zero(m_tot_ndf)), m_external_flow(Vector::Zero(m_tot_ndf)), m_in_jac(false) { number_equations(list_bcs); } void SolidDiffusion::number_equations(std::vector list_bcs) { m_id_equations = Eigen::VectorXi::Zero(m_tot_ndf); for (auto it=list_bcs.begin(); it!=list_bcs.end(); ++it) { m_id_equations(*it) = no_equation; } index_t neq = 0; for (index_t node: m_mesh->range_nodes()) { if (m_id_equations(node) == no_equation) continue; m_id_equations(node) = neq; ++ neq; } m_neq = neq; } void SolidDiffusion::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual ) { m_internal_flow.setZero(); residual.resize(get_neq()); residual.setZero(); for (index_t element: m_mesh->range_elements()) { Vector elem_residuals(2); elem_residuals.setZero(); element_residuals(element, displacement, velocity, elem_residuals); for (index_t enode: m_mesh->range_nen()) { const index_t id_eq = id_equation(m_mesh->get_node(element, enode)); if (id_eq == no_equation) continue; residual(id_eq) += elem_residuals(enode); } } //std::cout << "residual : " << std::endl << residual << std::endl; //std::cout << "flow : " << std::endl << m_internal_flow << std::endl; } void SolidDiffusion::element_residuals( index_t element, const Vector& displacement, const Vector& velocity, Vector& elem_residuals ) { Eigen::Matrix jacob; Eigen::Matrix evelocity, econc; //scalar_t mass_coeff = -(m_mesh->get_volume_element(element)/2.0); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const scalar_t sc_0 = displacement(node_0); const scalar_t sc_1 = displacement(node_1); const index_t index_0 = m_eqcurve.find_point(sc_0); const index_t index_1 = m_eqcurve.find_point(sc_1); //std::cout << element << " # " << index_0 << " - " << index_1 << std::endl; const scalar_t cc_0 = m_eqcurve.interpolate(index_0, sc_0, 1); //std::max(m_eqcurve.totaq_concentration(m_eqcurve.last()), m_eqcurve.interpolate(index_0, sc_0, 1)); const scalar_t cc_1 = m_eqcurve.interpolate(index_1, sc_1, 1); //std::max(m_eqcurve.totaq_concentration(m_eqcurve.last()), m_eqcurve.interpolate(index_1, sc_1, 1)); const scalar_t porosity_0 = m_eqcurve.interpolate(index_0, sc_0, 2); const scalar_t porosity_1 = m_eqcurve.interpolate(index_1, sc_1, 2); //const scalar_t diffcoeff_0 = m_eqcurve.interpolate(index_0, sc_0, 3); //const scalar_t diffcoeff_1 = m_eqcurve.interpolate(index_1, sc_1, 3); const scalar_t porosity = ( porosity_0 + porosity_1 )/2.0; const scalar_t diff_coeff = porosity>0.92?2.219e-5:1e4*std::exp(9.95*porosity-29.08); // const scalar_t diff_coeff = 1.0/(0.5/diffcoeff_0 + // 0.5/diffcoeff_1); scalar_t flux_coeff = ( m_mesh->get_face_area(element) / m_mesh->get_dx(element) //* porosity * diff_coeff ); // if (m_eqcurve.slope(index_1, 1) != 0) // { // std::cout << element << " # " << m_eqcurve.slope(index_0, 1) << " - " << m_eqcurve.slope(index_0, 2) // << " # " << m_eqcurve.slope(index_1, 1) << " - " << m_eqcurve.slope(index_1, 2) << std::endl; // } evelocity << (+ m_eqcurve.slope(index_0, 1)*porosity_0 + m_eqcurve.slope(index_0, 2)*cc_0 + 1.0)*mass_coeff_0*velocity(node_0), (+ m_eqcurve.slope(index_1, 1)*porosity_1 + m_eqcurve.slope(index_1, 2)*cc_1 + 1.0)*mass_coeff_1*velocity(node_1); jacob << 1.0, -1.0, -1.0, 1.0; jacob *= flux_coeff; econc << cc_0, cc_1; // if (element == 0) // std::cout << econc << std::endl; elem_residuals += jacob*econc; m_internal_flow(node_0) += elem_residuals(0); m_internal_flow(node_1) += elem_residuals(1); elem_residuals += evelocity; // for (index_t en: m_mesh->range_nen()) // { // elem_residuals(en) += evelocity(en); // elem_residuals(en) += (m_mesh->get_volume_element(element)/2.0 // *external_flow(m_mesh->get_node(element, en))); // } } void SolidDiffusion::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { m_in_jac = true; dfpm::list_triplet_t jacob; const index_t estimation = m_mesh->nb_nodes()*(m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { element_jacobian(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); m_in_jac = false; } void SolidDiffusion::element_jacobian( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt) { Eigen::VectorXd element_residual_orig(Eigen::VectorXd::Zero(2)); element_residuals(element, displacement, velocity, element_residual_orig); for (index_t en: m_mesh->range_nen()) { Eigen::VectorXd element_residual(Eigen::VectorXd::Zero(2)); const index_t node = m_mesh->get_node(element, en); const index_t dof = node; const index_t idc = id_equation(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-6) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; element_residuals(element, displacement, velocity, element_residual); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr: m_mesh->range_nen()) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = id_equation(noder); if (idr == no_equation) continue; jacobian.push_back(dfpm::triplet_t(idr, idc, (element_residual(enr) - element_residual_orig(enr))/h)); } } } void SolidDiffusion::update_solution(const Vector &update, scalar_t lambda, scalar_t alpha_dt, Vector &predictor, Vector &displacement, Vector &velocity ) { for (index_t node: m_mesh->range_nodes()) { const index_t id = id_equation(node); if (id == no_equation) continue; velocity(node) += lambda*update(id); } displacement = predictor + alpha_dt*velocity; } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp index 790a073..e451782 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp @@ -1,143 +1,145 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP #define SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP #include #include "../../types.hpp" #include "../../dfpm/types.hpp" #include "../../dfpmsolver/parabolic_program.hpp" #include "../../dfpm/meshes/mesh1dfwd.hpp" #include "eqcurve_extractor.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { class SPECMICP_DLL_PUBLIC SolidDiffusion: public dfpmsolver::ParabolicProgram { public: SolidDiffusion( mesh::Mesh1DPtr the_mesh, const Matrix& eqcurve, std::vector list_bcs ); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return 1;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_id_equations(id_dof);} void element_residuals(index_t element, const Vector& displacement, const Vector& velocity, Vector& element_residual ); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ); //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); void element_jacobian( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} //! \brief Return the value of the external flow for dof 'id_dof' scalar_t external_flow(index_t id_dof) const {return m_external_flow(id_dof);} //! \brief Return a reference to the value of the external flow for dof 'id_dof' scalar_t& external_flow(index_t id_dof) {return m_external_flow(id_dof);} //! \brief Return a reference to the vector of external flow Vector& external_flow() {return m_external_flow;} private: void SPECMICP_DLL_LOCAL number_equations(std::vector list_bcs); index_t m_tot_ndf; index_t m_neq; Eigen::VectorXi m_id_equations; mesh::Mesh1DPtr m_mesh; EquilibriumCurveExtractor m_eqcurve; Vector m_internal_flow; Vector m_external_flow; bool m_in_jac; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP diff --git a/src/reactmicp/io/configuration.cpp b/src/reactmicp/io/configuration.cpp index 46f9ae3..4d8dbe7 100644 --- a/src/reactmicp/io/configuration.cpp +++ b/src/reactmicp/io/configuration.cpp @@ -1,283 +1,285 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "configuration.hpp" #include "../../utils/io/yaml.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 #include #define S_DFPM "transport_options" #define S_DFPM_A_MAX_ITER "maximum_iteration" #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_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_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" 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'."); } } void configure_reactmicp_options( reactmicp::solver::ReactiveTransportOptions& options, const YAML::Node& configuration ) { 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); } 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 ) { 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(); 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; } } //end namespace io } //end namespace specmicp diff --git a/src/reactmicp/io/configuration.hpp b/src/reactmicp/io/configuration.hpp index 654a904..bb8d367 100644 --- a/src/reactmicp/io/configuration.hpp +++ b/src/reactmicp/io/configuration.hpp @@ -1,87 +1,89 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +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" 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; } //end namespace solver } //end namespace reactmicp namespace io { class OutputNodalVariables; void SPECMICP_DLL_PUBLIC configure_transport_options( dfpmsolver::ParabolicDriverOptions& options, const YAML::Node& configuration ); void SPECMICP_DLL_PUBLIC configure_reactmicp_options( reactmicp::solver::ReactiveTransportOptions& options, const YAML::Node& 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); } //end namespace io } //end namespace specmicp #endif // SPECMICP_REACTMICP_IO_CONFIGURATION_HPP diff --git a/src/reactmicp/io/hdf5_unsaturated.cpp b/src/reactmicp/io/hdf5_unsaturated.cpp index 0d8c6d3..44dcb3c 100644 --- a/src/reactmicp/io/hdf5_unsaturated.cpp +++ b/src/reactmicp/io/hdf5_unsaturated.cpp @@ -1,243 +1,245 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "hdf5_unsaturated.hpp" #include "../systems/unsaturated/variables.hpp" #include #include "../../utils/io/specmicp_hdf5.hpp" #include "../../utils/io/hdf5_eigen.hpp" #include "../../specmicp/io/hdf5_adimensional.hpp" #include "../../database/data_container.hpp" #include "../../utils/compat.hpp" #include using namespace specmicp::reactmicp::systems::unsaturated; #define MAIN_VARIABLES_GRPNAME "main_variables" #define CHEMISTRY_SOLUTION_GRPNAME "chemistry_solution" #define TRANSPORT_PROPERTIES_GRPNAME "transport_properties" #define LIQUID_SATURATION_DSET "liquid_saturation" #define AQUEOUS_CONC_DSET "aqueous_concentration" #define SOLID_CONC_DSET "solid_concentration" #define PRESSURE_DSET "partial_pressure" #define CAP_PRESSURE_DSET "capillary_pressure" #define POROSITY_DSET "porosity" #define LIQUID_DIFFUSIVITY_DSET "liquid_diffusivity" #define REL_LIQUID_DIFFUSIVITY_DSET "relative_liquid_diffusivity" #define LIQUID_PERMEABILITY_DSET "liquid_permeability" #define REL_LIQUID_PERMEABILITY_DSET "relative_liquid_permeability" #define RESISTANCE_GAS_DIFFUSIVITY_DSET "resistance_gas_diffusivity" #define REL_GAS_DIFFUSIVITY_DSET "relative_gas_diffusivity" namespace specmicp { namespace io { //! \brief Implementation of the UnsaturatedHDF5Saver //! //! \internal struct SPECMICP_DLL_LOCAL UnsaturatedHDF5Saver::UnsaturatedHDF5SaverImpl { public: std::shared_ptr m_vars; //!< the variables database::RawDatabasePtr m_database; //!< the database UnsaturatedHDF5SaverImpl(std::shared_ptr vars): m_vars(vars), m_database(vars->get_database()) {} //! \brief Save the main variables //! //! \param file HDF5 file //! \param section section where to save the main variables void save_main_variables( io::HDF5File& file, const std::string& section ); //! \brief Save the chemical solution //! //! \param file HDF5 file //! \param section section where to save the chemical solutions void save_chemical_solution( io::HDF5File& file, const std::string& section ); //! \brief Save the transport properties //! //! \param file HDF5 file //! \param section section where to save the transport properties void save_transport_properties( io::HDF5File& file, const std::string& section ); }; UnsaturatedHDF5Saver::UnsaturatedHDF5Saver( std::shared_ptr vars): m_impl(make_unique(vars)) {} UnsaturatedHDF5Saver::~UnsaturatedHDF5Saver() = default; void UnsaturatedHDF5Saver::save_timepoint(HDF5File& file, const std::string& name, const std::string& section) { auto group_name = file.complete_name(name, section); auto group = file.create_group(group_name); m_impl->save_main_variables(file, group_name); m_impl->save_chemical_solution(file, group_name); m_impl->save_transport_properties(file, group_name); } // Implementation // ============== void UnsaturatedHDF5Saver::UnsaturatedHDF5SaverImpl::save_main_variables( HDF5File& file, const std::string& section ) { auto group_name = file.complete_name(MAIN_VARIABLES_GRPNAME, section); auto group = file.create_group(group_name); // water { auto water_grp_name = file.complete_name( m_database->get_label_component(0), group_name); auto water_group = file.create_group(water_grp_name); save_eigen_matrix(file, LIQUID_SATURATION_DSET, water_grp_name, m_vars->get_liquid_saturation().variable); save_eigen_matrix(file, AQUEOUS_CONC_DSET, water_grp_name, m_vars->get_water_aqueous_concentration().variable); save_eigen_matrix(file, SOLID_CONC_DSET, water_grp_name, m_vars->get_solid_concentration(0).variable); if (m_vars->component_has_gas(0)) { save_eigen_matrix(file, PRESSURE_DSET, water_grp_name, m_vars->get_pressure_main_variables(0).variable); } save_eigen_matrix(file, CAP_PRESSURE_DSET, water_grp_name, m_vars->get_capillary_pressure().variable); } for (index_t aq_component: m_database->range_aqueous_component()) { auto aqcomp_grp_name = file.complete_name( m_database->get_label_component(aq_component), group_name); auto aqcomp_group = file.create_group(aqcomp_grp_name); save_eigen_matrix(file, AQUEOUS_CONC_DSET, aqcomp_grp_name, m_vars->get_aqueous_concentration(aq_component).variable); save_eigen_matrix(file, SOLID_CONC_DSET, aqcomp_grp_name, m_vars->get_solid_concentration(aq_component).variable); if (m_vars->component_has_gas(aq_component)) { save_eigen_matrix(file, PRESSURE_DSET, aqcomp_grp_name, m_vars->get_pressure_main_variables(aq_component).variable); } } } void UnsaturatedHDF5Saver::UnsaturatedHDF5SaverImpl::save_chemical_solution( HDF5File& file, const std::string& section ) { auto group_name = file.complete_name(CHEMISTRY_SOLUTION_GRPNAME, section); auto group = file.create_group(group_name); for (auto node: m_vars->get_mesh()->range_nodes()) { save_adimensional_system_solution(file, std::to_string(node), group_name, m_vars->get_adim_solution(node)); } } // time to get ugly and use macro // this is simply a quick wrapper that call the save_eigen matrix function // It avoids all the boilerplate #define save_transport_property(name, var) \ save_eigen_matrix(file, name, group_name, \ m_vars->get_##var ().variable) void UnsaturatedHDF5Saver::UnsaturatedHDF5SaverImpl::save_transport_properties( HDF5File& file, const std::string& section ) { auto group_name = file.complete_name(TRANSPORT_PROPERTIES_GRPNAME, section); auto group = file.create_group(group_name); save_transport_property(POROSITY_DSET, porosity); save_transport_property(LIQUID_DIFFUSIVITY_DSET, liquid_diffusivity); save_transport_property(REL_LIQUID_DIFFUSIVITY_DSET, relative_liquid_diffusivity); save_transport_property(LIQUID_PERMEABILITY_DSET, liquid_permeability); save_transport_property(REL_LIQUID_PERMEABILITY_DSET, relative_liquid_permeability); save_transport_property(RESISTANCE_GAS_DIFFUSIVITY_DSET, resistance_gas_diffusivity); save_transport_property(REL_GAS_DIFFUSIVITY_DSET, relative_gas_diffusivity); } #undef save_transport_property // we remove the ugly macro, no one saws anything :) } //end namespace io } //end namespace specmicp diff --git a/src/reactmicp/io/hdf5_unsaturated.hpp b/src/reactmicp/io/hdf5_unsaturated.hpp index 202dd51..7d93cda 100644 --- a/src/reactmicp/io/hdf5_unsaturated.hpp +++ b/src/reactmicp/io/hdf5_unsaturated.hpp @@ -1,90 +1,92 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_REACTMICP_HDF5_UNSATURATED_HPP #define SPECMICP_IO_REACTMICP_HDF5_UNSATURATED_HPP //! \file reactmicp/io/hdf5_unsaturated.hpp //! \brief HDF5 formatter for the unsaturated system #include "../../types.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class UnsaturatedVariables; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp namespace io { class HDF5File; //! \brief Save the unsaturated set of variables in HDF5 format //! class SPECMICP_DLL_PUBLIC UnsaturatedHDF5Saver { using UnsaturatedVariables = reactmicp::systems::unsaturated::UnsaturatedVariables; public: UnsaturatedHDF5Saver(std::shared_ptr vars); ~UnsaturatedHDF5Saver(); //! \brief Save the variables //! //! All the values will be saved in a new group 'section/name' void save_timepoint(HDF5File& file, const std::string& name, const std::string& section ); private: struct SPECMICP_DLL_LOCAL UnsaturatedHDF5SaverImpl; //! \brief implementation details //! \internal std::unique_ptr m_impl; // delete copy and assignement operator, no need for them UnsaturatedHDF5Saver(const UnsaturatedHDF5Saver& other) = delete; UnsaturatedHDF5Saver& operator= (const UnsaturatedHDF5Saver& other) = delete; }; } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_REACTMICP_HDF5_UNSATURATED_HPP diff --git a/src/reactmicp/io/reactive_transport.cpp b/src/reactmicp/io/reactive_transport.cpp index d3c1c2a..34f10d7 100644 --- a/src/reactmicp/io/reactive_transport.cpp +++ b/src/reactmicp/io/reactive_transport.cpp @@ -1,180 +1,182 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "reactive_transport.hpp" #include #include "../../reactmicp/solver/reactive_transport_solver_structs.hpp" #include "../../utils/timer.hpp" #include "../../utils/io/csv_formatter.hpp" namespace specmicp { namespace io { //! \brief Print the ReactMiCP header void print_reactmicp_header( OutFile& output ) { output << "// ================================== //\n" << "// //\n" << "// ReactMiCP //\n" << "// //\n" << "// ================================== //\n\n" << "A reactive transport solver based on SpecMiCP.\n" << "------------------------------------------- \n\n"; output.flush(); } //! \brief Print the performance information from the ReactMiCP solver void print_reactmicp_performance_short( OutFile& output, const reactmicp::solver::ReactiveTransportPerformance& perf ) { output << "------------------------------------------- \n" << " Performance \n " << "------------------------------------------- \n\t" << " - Return code : " << reactmicp_return_code_to_string(perf.return_code) << "\n\t" << " - Residuals : " << perf.residuals << "\n\t" << " - Number of iterations : " << perf.nb_iterations << "\n" << "------------------------------------------- \n"; } //! \brief Print the time spent in the different staggers void print_reactmicp_timer( OutFile& output, const reactmicp::solver::ReactiveTransportTimer& timer ) { output << "------------------------------------------- \n" << "Time spent in each stagger \n" << "------------------------------------------- \n\t" << "- Transport : " << timer.transport_time << " s\n\t" << "- Chemistry : " << timer.chemistry_time << " s\n\t" << "- Upscaling : " << timer.upscaling_time << " s\n" << "----------------------------------------- \n"; } //! \brief Print time and timer at the end of the computation void print_reactmicp_end( OutFile& output, const Timer& total_timer, const reactmicp::solver::ReactiveTransportTimer& timer ) { scalar_t elapsed_s = total_timer.elapsed_time(); index_t hours = static_cast(elapsed_s) / 3600; index_t elapsed_minutes = elapsed_s - hours*3600; index_t minute = elapsed_minutes / 60; index_t seconds = elapsed_minutes - 60*minute; output << " ====================================================== \n"; output << "computation finished at " << total_timer.get_ctime_stop(); output << " Duration of the computation : " << total_timer.elapsed_time() << " s" << "( " << hours << "h " << minute << "min " << seconds << "s )\n"; print_reactmicp_timer(output, timer); output.flush(); } //! \brief Print the header for the performance table //! //! \sa print_reactmicp_performance_long void print_reactmicp_performance_long_header( OutFile& output ) { output << "Id\t T\t dt\t Return_code\t Iterations \t Residuals\t Time\t Transport_time\t Chemistry_time\n"; } //! \brief Print a row in the performance table //! //! The performance table contains information about an iteration of the reactmicp solver //! //! \sa print_reactmicp_performance_long_header void print_reactmicp_performance_long( OutFile& output, index_t cnt, scalar_t total, const reactmicp::solver::ReactiveTransportPerformance& perfs ) { output << cnt << "\t " << total << "\t " << perfs.timestep << "\t " << (int) perfs.return_code << "\t " << perfs.nb_iterations << "\t " << perfs.residuals << "\t " << perfs.total_time << "\t" << perfs.transport_time << "\t" << perfs.chemistry_time << "\n"; } //! \brief Transform a ReactiveTransportreturnCode into a string std::string reactmicp_return_code_to_string( reactmicp::solver::ReactiveTransportReturnCode retcode) { using RetCode = reactmicp::solver::ReactiveTransportReturnCode; switch (retcode) { case RetCode::ResidualMinimized: return "ResidualMinimized"; case RetCode::ErrorMinimized: return "ErrorMinimized"; default: switch (retcode) { case RetCode::StationaryPoint: return "StationaryPoint"; case RetCode::MaximumIterationsReached: return "MaximumIterationsReached"; case RetCode::GoodEnough: return "Good enough..."; case RetCode::TransportBypass: return "Transport Bypass"; case RetCode::TransportFailure: return "TransportFailure"; case RetCode::ChemistryFailure: return "ChemistryFailure"; case RetCode::UpscalingFailure: return "UpscalingFailure"; default: return "Unknow error code !"; } } } } // end namespace io } // end namespace specmicp diff --git a/src/reactmicp/io/reactive_transport.hpp b/src/reactmicp/io/reactive_transport.hpp index 8693f39..6d16365 100644 --- a/src/reactmicp/io/reactive_transport.hpp +++ b/src/reactmicp/io/reactive_transport.hpp @@ -1,114 +1,116 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_REACTMICP_HPP #define SPECMICP_IO_REACTMICP_HPP //! \file reactmicp/io/reactive_transport.hpp //! \brief Print information from the reactive transport module #include "../../types.hpp" #include namespace specmicp { // forward declaration class Timer; namespace reactmicp { namespace solver { struct ReactiveTransportPerformance; struct ReactiveTransportTimer; enum class ReactiveTransportReturnCode; } //end namespace solver } //end namespace reactmicp namespace io { class OutFile; //! \brief Print the ReactMiCP header void SPECMICP_DLL_PUBLIC print_reactmicp_header( OutFile& output ); //! \brief Print the performance information from the ReactMiCP solver void SPECMICP_DLL_PUBLIC print_reactmicp_performance_short( OutFile& output, const reactmicp::solver::ReactiveTransportPerformance& perf ); //! \brief Print the time spent in the different staggers void SPECMICP_DLL_PUBLIC print_reactmicp_timer( OutFile& output, const reactmicp::solver::ReactiveTransportTimer& timer ); //! \brief Print time and timer at the end of the computation void SPECMICP_DLL_PUBLIC print_reactmicp_end( OutFile& output, const Timer& total_timer, const reactmicp::solver::ReactiveTransportTimer& timer ); //! \brief Print the header for the performance table //! //! \sa print_reactmicp_performance_long void SPECMICP_DLL_PUBLIC print_reactmicp_performance_long_header( OutFile& output ); //! \brief Print a row in the performance table //! //! The performance table contains information about an iteration of the reactmicp solver //! //! \sa print_reactmicp_performance_long_header void SPECMICP_DLL_PUBLIC print_reactmicp_performance_long( OutFile& output, index_t cnt, scalar_t total, const reactmicp::solver::ReactiveTransportPerformance& perfs ); //! \brief Transform a ReactiveTransportreturnCode into a string std::string SPECMICP_DLL_PUBLIC reactmicp_return_code_to_string( reactmicp::solver::ReactiveTransportReturnCode retcode); } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_REACTMICP_HPP diff --git a/src/reactmicp/io/saturated_react.cpp b/src/reactmicp/io/saturated_react.cpp index 321435f..011b9f1 100644 --- a/src/reactmicp/io/saturated_react.cpp +++ b/src/reactmicp/io/saturated_react.cpp @@ -1,702 +1,704 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "saturated_react.hpp" #include #include #include #include #include "../../dfpm/meshes/mesh1d.hpp" #include "../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../utils/dateandtime.hpp" #include "../../physics/io/units.hpp" #include "../systems/saturated_react/variables.hpp" #include "../../utils/io/csv_formatter.hpp" #include "../../dfpm/io/meshes.hpp" #include "../../utils/compat.hpp" #include "../../database/database_holder.hpp" using namespace specmicp::reactmicp::systems::satdiff; namespace specmicp { namespace io { void print_csv_header(CSVFile& ofile) { ofile.insert_comment_line("ReactMiCP"); ofile.insert_comment_line("---------"); ofile.insert_comment_date(); } void print_components_total_aqueous_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, CSVFile& ofile ) { print_csv_header(ofile); ofile.insert_comment_line("Total aqueous concentrations profiles"); ofile.insert_comment_line( "length unit : " + io::length_unit_to_string(units_set.length)); ofile.insert_comment_line( "concentration unit : mol/" + io::volume_unit_to_string(units_set.length)); ofile << "Position"; for (index_t component: the_database->range_aqueous_component()) { ofile.separator(); ofile << the_database->get_label_component(component); } ofile.eol(); for (index_t node: the_mesh->range_nodes()) { ofile << the_mesh->get_position(node); for (index_t component: the_database->range_aqueous_component()) { ofile.separator(); ofile << variables->aqueous_concentration(node, component); } ofile.eol(); } ofile.flush(); } //! \brief Print the total aqueous concentrations in the CSV format in the file 'filepath' void print_components_total_aqueous_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ) { CSVFile ofile(filepath); print_components_total_aqueous_concentration(the_database, variables, the_mesh, units_set, ofile); } //! \brief Print the total solid concentrations in the CSV format in 'ofile' void print_components_total_solid_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, CSVFile& ofile ) { print_csv_header(ofile); ofile.insert_comment_line( "length unit : " + io::length_unit_to_string(units_set.length)); ofile.insert_comment_line( "concentration unit : mol/" + io::volume_unit_to_string(units_set.length)); ofile << "Position"; for (index_t component: the_database->range_aqueous_component()) { ofile.separator(); ofile << the_database->get_label_component(component); } ofile.eol(); for (index_t node: the_mesh->range_nodes()) { ofile << the_mesh->get_position(node); for (index_t component: the_database->range_aqueous_component()) { ofile.separator(); ofile << variables->solid_concentration(node, component); } ofile.eol(); } ofile.flush(); } //! \brief Print the total solid concentrations in the CSV format in the file 'filepath' void print_components_total_solid_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ) { CSVFile ofile(filepath); print_components_total_solid_concentration(the_database, variables, the_mesh, units_set, ofile); } //! \brief Print the solid phases profiles in 'ofile' inline void print_minerals_profile(RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, CSVFile& ofile ) { print_csv_header(ofile); ofile.insert_comment_line("Solid phase profiles"); ofile.insert_comment_line( "length unit : " + io::length_unit_to_string(units_set.length)); ofile << "Position"; for (index_t mineral: the_database->range_mineral()) { ofile.separator(); ofile << the_database->get_label_mineral(mineral); } ofile.separator(); ofile << "Porosity"; ofile.separator(); ofile << "pH"; ofile.eol(); for (index_t node: the_mesh->range_nodes()) { ofile << the_mesh->get_position(node); AdimensionalSystemSolutionExtractor extractor(variables->equilibrium_solution(node), the_database, units::UnitsSet()); for (index_t mineral: the_database->range_mineral()) { ofile.separator(); ofile << extractor.volume_fraction_mineral(mineral); } ofile.separator(); ofile << variables->porosity(node); ofile.separator(); ofile << extractor.pH(); ofile.eol(); } ofile.flush(); } //! \brief Print the solid phases profiles in 'filepath' void print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ) { CSVFile ofile(filepath); print_minerals_profile( the_database, variables, the_mesh, units_set, ofile ); } // declaration of implementation // ============================= //! \brief The implementation details of OutputNodalVariables //! //! \internal struct OutputNodalVariables::OutputNodalVariablesImpl: public database::DatabaseHolder { using equilibrium_var_f = std::function ; OutputNodalVariablesImpl( const RawDatabasePtr& the_database, const mesh::Mesh1DPtr& the_mesh, const units::UnitsSet& the_units): database::DatabaseHolder(the_database), m_mesh(the_mesh), m_units(the_units) {} // attributes mesh::Mesh1DPtr m_mesh; units::UnitsSet m_units; std::vector m_index_aqueous {}; std::vector m_index_solid {}; std::vector m_index_conc {}; CSVFile m_out_poro {}; CSVFile m_out_diffusivity {}; std::vector m_out_aqueous {}; std::vector m_out_solid {}; std::vector m_out_conc {}; std::vector m_out_equilibrium_vars {}; std::vector m_func_equilibrium_vars {}; std::vector m_out_custom {}; std::vector m_func_custom {}; // functions void print_csv_column_headers(CSVFile& out); void register_porosity(const std::string& filepath); void register_diffusion_coefficient(const std::string &filepath); void register_total_aqueous_concentration( index_t component, const std::string& filepath ); void register_total_concentration( index_t component, const std::string& filepath ); void register_total_solid_concentration( index_t component, const std::string& filepath ); void register_molality_component( index_t component, const std::string& filepath); void register_pH(const std::string& filepath); void register_volume_fraction_mineral( index_t mineral, const std::string& filepath ); void register_saturation_index_mineral_kinetic( index_t mineral_kinetic, const std::string& filepath); void register_custom_function( custom_f getter_function, const std::string& filepath, const std::string& msg ); void output(scalar_t time, SaturatedVariablesPtr var); }; // Main functions // =============== OutputNodalVariables::OutputNodalVariables( RawDatabasePtr the_database, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& the_units ): m_impl(make_unique(the_database, the_mesh, the_units)) {} OutputNodalVariables::~OutputNodalVariables() = default; void OutputNodalVariables::register_porosity(const std::string &filepath) { m_impl->register_porosity(filepath); } void OutputNodalVariables::register_diffusion_coefficient(const std::string &filepath) { m_impl->register_diffusion_coefficient(filepath); } void OutputNodalVariables::register_total_aqueous_concentration( index_t component, const std::string& filepath ) { specmicp_assert_component_bounds(component, m_impl->get_database()); m_impl->register_total_aqueous_concentration(component, filepath); } void OutputNodalVariables::register_total_concentration( index_t component, const std::string& filepath ) { specmicp_assert_component_bounds(component, m_impl->get_database()); m_impl->register_total_concentration(component, filepath); } void OutputNodalVariables::register_total_solid_concentration( index_t component, const std::string& filepath ) { specmicp_assert_component_bounds(component, m_impl->get_database()); m_impl->register_total_solid_concentration(component, filepath); } void OutputNodalVariables::register_molality_component( index_t component, const std::string& filepath ) { specmicp_assert_component_bounds(component, m_impl->get_database()); m_impl->register_molality_component(component, filepath); } void OutputNodalVariables::register_pH(const std::string& filepath) { m_impl->register_pH(filepath); } void OutputNodalVariables::register_volume_fraction_mineral(index_t mineral, const std::string& filepath) { specmicp_assert_mineral_bounds(mineral, m_impl->get_database()); m_impl->register_volume_fraction_mineral(mineral, filepath); } void OutputNodalVariables::register_saturation_index_mineral_kinetic( index_t mineral_kinetic, const std::string& filepath ) { specmicp_assert_mineral_kinetic_bounds(mineral_kinetic, m_impl->get_database()); m_impl->register_saturation_index_mineral_kinetic(mineral_kinetic, filepath); } void OutputNodalVariables::register_custom_function( custom_f getter_function, const std::string& filepath, const std::string& msg ) { m_impl->register_custom_function(getter_function, filepath, msg); } void OutputNodalVariables::output(scalar_t time, reactmicp::solver::VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); m_impl->output(time, true_var); } std::function OutputNodalVariables::get_output_for_reactmicp() { return std::bind(std::mem_fn( &OutputNodalVariables::output), this, std::placeholders::_1, std::placeholders::_2); } RawDatabasePtr OutputNodalVariables::get_database() { return m_impl->get_database(); } // ######################################### // // Implementation // // ########################################## void OutputNodalVariables::OutputNodalVariablesImpl::print_csv_column_headers(CSVFile& out) { out.insert_comment_unit("time", "s"); out.insert_comment_unit("length", io::length_unit_to_string(m_units.length)); out << "Time"; for (index_t node: m_mesh->range_nodes()) { out.separator(); out << m_mesh->get_position(node); } out.eol(); } void OutputNodalVariables::OutputNodalVariablesImpl::register_porosity( const std::string &filepath ) { m_out_poro.open(filepath); m_out_poro.insert_comment_line("ReactMiCP - porosity"); m_out_poro.insert_comment_date(); print_csv_column_headers(m_out_poro); } void OutputNodalVariables::OutputNodalVariablesImpl::register_diffusion_coefficient( const std::string &filepath ) { m_out_diffusivity.open(filepath); m_out_diffusivity.insert_comment_line("ReactMiCP - diffusion coefficient"); m_out_diffusivity.insert_comment_date(); m_out_diffusivity.insert_comment_unit("diffusion coefficient", io::surface_unit_to_string(m_units.length)+"/s"); print_csv_column_headers(m_out_diffusivity); } void OutputNodalVariables::OutputNodalVariablesImpl::register_total_aqueous_concentration( index_t component, const std::string& filepath ) { m_index_aqueous.push_back(component); m_out_aqueous.emplace_back(filepath); auto i = m_out_aqueous.size() - 1; m_out_aqueous[i].open(filepath); m_out_aqueous[i].insert_comment_line("ReactMiCP - aqueous concentration"); m_out_aqueous[i].insert_comment_date(); m_out_aqueous[i].insert_comment_unit("Concentration", "mol/"+io::volume_unit_to_string(m_units.length)); print_csv_column_headers(m_out_aqueous[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_total_concentration( index_t component, const std::string& filepath ) { m_index_conc.push_back(component); m_out_conc.emplace_back(filepath); auto i = m_out_conc.size() - 1; m_out_conc[i].open(filepath); m_out_conc[i].insert_comment_line("ReactMiCP - Total concentration"); m_out_conc[i].insert_comment_date(); m_out_conc[i].insert_comment_unit("Concentration", "mol/"+io::volume_unit_to_string(m_units.length)); print_csv_column_headers(m_out_conc[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_total_solid_concentration( index_t component, const std::string& filepath ) { m_index_solid.push_back(component); m_out_solid.emplace_back(filepath); auto i = m_out_solid.size() - 1; m_out_solid[i].insert_comment_line("ReactMiCP - solid concentration"); m_out_solid[i].insert_comment_date(); m_out_solid[i].insert_comment_unit("Concentration", "mol/"+io::volume_unit_to_string(m_units.length)); print_csv_column_headers(m_out_solid[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_molality_component( index_t component, const std::string& filepath ) { m_func_equilibrium_vars.emplace_back(std::bind( std::mem_fn(&AdimensionalSystemSolutionExtractor::molality_component), std::placeholders::_1, component )); m_out_equilibrium_vars.emplace_back(filepath); auto i = m_out_equilibrium_vars.size() -1; m_out_equilibrium_vars[i].insert_comment_line("ReactMiCP - molality component "+m_data->get_label_component(component)); m_out_equilibrium_vars[i].insert_comment_date(); m_out_equilibrium_vars[i].insert_comment_unit("molality", "mol/kg"); print_csv_column_headers(m_out_equilibrium_vars[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_pH( const std::string& filepath ) { m_func_equilibrium_vars.emplace_back(std::bind( std::mem_fn(&AdimensionalSystemSolutionExtractor::pH), std::placeholders::_1 )); m_out_equilibrium_vars.emplace_back(filepath); auto i = m_out_equilibrium_vars.size() -1; m_out_equilibrium_vars[i].insert_comment_line("ReactMiCP - pH"); m_out_equilibrium_vars[i].insert_comment_date(); print_csv_column_headers(m_out_equilibrium_vars[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_volume_fraction_mineral( index_t mineral, const std::string& filepath ) { m_func_equilibrium_vars.emplace_back(std::bind( std::mem_fn(&AdimensionalSystemSolutionExtractor::volume_fraction_mineral), std::placeholders::_1, mineral )); m_out_equilibrium_vars.emplace_back(filepath); auto i = m_out_equilibrium_vars.size() -1; m_out_equilibrium_vars[i].insert_comment_line("ReactMiCP - volume fraction mineral "+m_data->get_label_mineral(mineral)); m_out_equilibrium_vars[i].insert_comment_date(); print_csv_column_headers(m_out_equilibrium_vars[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_saturation_index_mineral_kinetic( index_t mineral_kinetic, const std::string& filepath) { m_func_equilibrium_vars.emplace_back(std::bind( std::mem_fn(&AdimensionalSystemSolutionExtractor::saturation_index_kinetic), std::placeholders::_1, mineral_kinetic )); m_out_equilibrium_vars.emplace_back(filepath); auto i = m_out_equilibrium_vars.size() -1; m_out_equilibrium_vars[i].insert_comment_line("ReactMiCP - Saturation index mineral " + m_data->get_label_mineral_kinetic(mineral_kinetic)); m_out_equilibrium_vars[i].insert_comment_date(); print_csv_column_headers(m_out_equilibrium_vars[i]); } void OutputNodalVariables::OutputNodalVariablesImpl::register_custom_function( custom_f getter_function, const std::string& filepath, const std::string& msg ) { m_func_custom.push_back(getter_function); m_out_custom.emplace_back(filepath); auto i = m_out_custom.size() -1; CSVFile& out = m_out_custom[i]; out.insert_comment_line("ReactMiCP"); out.insert_comment_line(msg); out.insert_comment_date(); print_csv_column_headers(out); } void OutputNodalVariables::OutputNodalVariablesImpl::output(scalar_t time, SaturatedVariablesPtr variables) { // upscaling // --------- if (m_out_poro.is_open()) { m_out_poro << time; for (index_t node: m_mesh->range_nodes()) { m_out_poro.separator(); m_out_poro << variables->porosity(node); } m_out_poro.endl(); } if (m_out_diffusivity.is_open()) { m_out_diffusivity << time; for (index_t node: m_mesh->range_nodes()) { m_out_diffusivity.separator(); m_out_diffusivity << variables->diffusion_coefficient(node); } m_out_diffusivity.endl(); } // equilibrium vars // ---------------- if (m_out_equilibrium_vars.size() > 0) { for (std::vector::size_type var=0; var< m_out_equilibrium_vars.size(); ++var) { m_out_equilibrium_vars[var] << time; } for (index_t node: m_mesh->range_nodes()) { AdimensionalSystemSolutionExtractor extr(variables->equilibrium_solution(node), m_data, m_units); for (std::vector::size_type var=0; var< m_out_equilibrium_vars.size(); ++var) { m_out_equilibrium_vars[var].separator(); m_out_equilibrium_vars[var] << m_func_equilibrium_vars[var](&extr); } } for (std::vector::size_type var=0; var< m_out_equilibrium_vars.size(); ++var) { m_out_equilibrium_vars[var].endl(); } } // nodal vars // ----------- for (std::vector::size_type aqueous=0; aqueous< m_index_aqueous.size(); ++aqueous) { m_out_aqueous[aqueous] << time; } for (std::vector::size_type solid=0; solid< m_index_solid.size(); ++solid) { m_out_solid[solid] << time; } for (std::vector::size_type tot=0; tot< m_index_conc.size(); ++tot) { m_out_conc[tot] << time; } for (index_t node: m_mesh->range_nodes()) { for (std::vector::size_type aqueous=0; aqueous< m_index_aqueous.size(); ++aqueous) { m_out_aqueous[aqueous].separator(); m_out_aqueous[aqueous] << variables->aqueous_concentration(node, m_index_aqueous[aqueous]); } for (std::vector::size_type solid=0; solid< m_index_solid.size(); ++solid) { m_out_solid[solid].separator(); m_out_solid[solid] << variables->solid_concentration(node, m_index_solid[solid]); } for (std::vector::size_type tot=0; tot< m_index_conc.size(); ++tot) { m_out_conc[tot].separator(); m_out_conc[tot] << variables->porosity(node)*variables->aqueous_concentration(node, m_index_conc[tot]) + variables->solid_concentration(node, m_index_conc[tot]); } } for (std::vector::size_type aqueous=0; aqueous< m_index_aqueous.size(); ++aqueous) { m_out_aqueous[aqueous].endl(); } for (std::vector::size_type solid=0; solid< m_index_solid.size(); ++solid) { m_out_solid[solid].endl(); } for (std::vector::size_type tot=0; tot< m_index_conc.size(); ++tot) { m_out_conc[tot].endl(); } // custom functions for (std::vector::size_type var=0; var< m_out_custom.size(); ++var) { auto& out = m_out_custom[var]; out << time; for (index_t node: m_mesh->range_nodes()) { out.separator(); out << m_func_custom[var](node, variables); } out.endl(); } } } // end namespace io } // end namespace specmicp diff --git a/src/reactmicp/io/saturated_react.hpp b/src/reactmicp/io/saturated_react.hpp index 42fe81e..a74264b 100644 --- a/src/reactmicp/io/saturated_react.hpp +++ b/src/reactmicp/io/saturated_react.hpp @@ -1,182 +1,184 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_SATURATEDREACT_HPP #define SPECMICP_IO_SATURATEDREACT_HPP //! \file saturated_react.hpp //! \brief Print information about the saturated reactive transport module #include "../../types.hpp" #include "../../utils/io/csv_formatter.hpp" #include "../../physics/units.hpp" #include #include #include namespace specmicp { // forward declarations class AdimensionalSystemSolutionExtractor; namespace database { struct DataContainer; } //end namespace database using RawDatabasePtr = std::shared_ptr; namespace mesh { class Mesh1D; using Mesh1DPtr = std::shared_ptr; } //end namespace mesh namespace reactmicp { namespace solver { class VariablesBase; using VariablesBasePtr = std::shared_ptr; } //end namespace solver namespace systems { namespace satdiff { class SaturatedVariables; using SaturatedVariablesPtr = std::shared_ptr; } //end namespace satdiff } //end namespace systems } //end namespace reactmicp namespace io { using namespace specmicp::reactmicp::systems::satdiff; //! \brief Print the total aqueous concentrations in the CSV format in the file 'filepath' void SPECMICP_DLL_PUBLIC print_components_total_aqueous_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ); //! \brief Print the total solid concentrations in the CSV format in the file 'filepath' void SPECMICP_DLL_PUBLIC print_components_total_solid_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ); //! \brief Print the solid phases profiles in 'filepath' void SPECMICP_DLL_PUBLIC print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ); //! \brief Output Nodal variables requested by the user //! //! This class can be used during a ReacMiCP simulation to //! output nodal variables in CSV files class SPECMICP_DLL_PUBLIC OutputNodalVariables { public: OutputNodalVariables(RawDatabasePtr the_database, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& the_units); ~OutputNodalVariables(); OutputNodalVariables(OutputNodalVariables&) = delete; OutputNodalVariables* operator= (OutputNodalVariables&) = delete; //! \brief The total aqueous concentration of 'component' will be saved in 'filepath' void register_total_aqueous_concentration(index_t component, const std::string& filepath); //! \brief The total solid concentration of 'component' will be saved in 'filepath' void register_total_solid_concentration(index_t component, const std::string& filepath); //! \brief The total concentration of 'component' will be saved in 'filepath' void register_total_concentration(index_t component, const std::string& filepath); //! \brief The porosity will be saved in 'filepath' void register_porosity(const std::string& filepath); //! \brief The diffusion_coefficient will be save in 'filepath' void register_diffusion_coefficient(const std::string& filepath); //! \brief The molality of 'component' will be saved in 'filepath' void register_molality_component(index_t component, const std::string& filepath); //! \brief The pH will be saved in 'filepath' void register_pH(const std::string& filepath); //! \brief The volume fraction of 'mineral' will be saved in 'filepath' void register_volume_fraction_mineral(index_t mineral, const std::string& filepath); //! \brief The saturation index of mineral kinetic will be saved in 'filepath' void register_saturation_index_mineral_kinetic( index_t mineral_kinetic, const std::string& filepath ); //! \brief A function that return a scalar from a node in a variables using custom_f = std::function ; //! \brief Register a custom function void register_custom_function( custom_f getter_function, const std::string& filepath, const std::string& msg ); //! \brief Output the variables in their respective files void output(scalar_t time, reactmicp::solver::VariablesBasePtr var); //! \brief Return the output function for the ReactMiCP solver std::function get_output_for_reactmicp(); //! \brief Return the database RawDatabasePtr get_database(); private: //! \brief Implementation details for OutputNodalVariables //! //! \internal struct OutputNodalVariablesImpl; std::unique_ptr m_impl; }; } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_SATURATEDREACT_HPP diff --git a/src/reactmicp/solver/reactive_transport_solver.cpp b/src/reactmicp/solver/reactive_transport_solver.cpp index c8fe29a..76032a6 100644 --- a/src/reactmicp/solver/reactive_transport_solver.cpp +++ b/src/reactmicp/solver/reactive_transport_solver.cpp @@ -1,285 +1,287 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "reactive_transport_solver.hpp" #include "staggers_base/staggers_base.hpp" #include "../../utils/log.hpp" #include "../../utils/timer.hpp" namespace specmicp { namespace reactmicp { namespace solver { namespace internal { // This contains internal information for the reactive transport solver // It is used to check the convergence struct ReactiveTransportResiduals { index_t nb_iterations; scalar_t transport_residual_0; scalar_t transport_residuals; scalar_t update; ReactiveTransportResiduals(): nb_iterations(0), transport_residual_0(-1), transport_residuals(-1), update(-1) {} }; } // end namespace internal // ReactiveTransportSolver:: // Solve a timestep // // Attention : This function uses goto to handle return code and performance ReactiveTransportReturnCode ReactiveTransportSolver::solve_timestep( scalar_t timestep, VariablesBasePtr variables ) { return solve_timestep(timestep, variables.get()); } ReactiveTransportReturnCode ReactiveTransportSolver::solve_timestep( scalar_t timestep, VariablesBase* variables ) { // start the timer Timer tot_timer; tot_timer.start(); // initialization internal::ReactiveTransportResiduals residuals; reset_perfs(); get_perfs().timestep = timestep; // copy of variables // ? m_transport_stagger->initialize_timestep(timestep, variables); m_chemistry_stagger->initialize_timestep(timestep, variables); m_upscaling_stagger->initialize_timestep(timestep, variables); // residuals.transport_residual_0 = m_transport_stagger->get_residual_0(variables); ReactiveTransportReturnCode retcode = one_iteration(variables, residuals); // check for failure if (retcode < ReactiveTransportReturnCode::StaggerFailure) { ERROR << "Failed to solve the iteration, return code : " << (int) retcode; goto set_return; } retcode = check_convergence(variables, residuals, retcode); ++residuals.nb_iterations; // if sequential non-iterative algorithm if (get_options().is_snia()) { goto end; } // else while (retcode == ReactiveTransportReturnCode::NotConvergedYet) { retcode = one_iteration(variables, residuals); // check for failure if (retcode < ReactiveTransportReturnCode::StaggerFailure) { ERROR << "Failed to solve the iteration, return code : " << (int) retcode; goto set_return; } retcode = check_convergence(variables, residuals, retcode); ++residuals.nb_iterations; } // wrapup end: // upscaling, if needed if (not get_options().implicit_upscaling) { Timer timer; timer.start(); StaggerReturnCode upscaling_ret_code = m_upscaling_stagger->restart_timestep(variables); if (upscaling_ret_code <= StaggerReturnCode::NotConvergedYet) { retcode = ReactiveTransportReturnCode::UpscalingFailure; goto set_return; } else if (upscaling_ret_code == StaggerReturnCode::UserTermination) retcode = ReactiveTransportReturnCode::UserTermination; timer.stop(); m_timer.upscaling_time += timer.elapsed_time(); } // record performance and return code set_return: tot_timer.stop(); get_perfs().total_time = tot_timer.elapsed_time(); get_perfs().nb_iterations = residuals.nb_iterations; get_perfs().return_code = retcode; get_perfs().residuals = residuals.transport_residuals/residuals.transport_residual_0; return retcode; } ReactiveTransportReturnCode ReactiveTransportSolver::one_iteration( VariablesBasePtr variables, internal::ReactiveTransportResiduals& residuals ) { return one_iteration(variables.get(), residuals); } ReactiveTransportReturnCode ReactiveTransportSolver::one_iteration( VariablesBase* variables, internal::ReactiveTransportResiduals& residuals ) { Timer timer; bool bypass = false; bool user_termination = false; // Transport // --------- timer.start(); StaggerReturnCode transport_ret_code = m_transport_stagger->restart_timestep(variables); if (transport_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::TransportFailure; } else if (transport_ret_code == StaggerReturnCode::ErrorMinimized) { bypass = true; } timer.stop(); const scalar_t ttime = timer.elapsed_time(); m_timer.transport_time += ttime; get_perfs().transport_time += ttime; // Chemistry // --------- timer.start(); StaggerReturnCode chemistry_ret_code = m_chemistry_stagger->restart_timestep(variables); if (chemistry_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::ChemistryFailure; } timer.stop(); const scalar_t ctime = timer.elapsed_time(); m_timer.chemistry_time += ctime; get_perfs().chemistry_time += ctime; // Upscaling // --------- if (get_options().implicit_upscaling) { timer.start(); StaggerReturnCode upscaling_ret_code = m_upscaling_stagger->restart_timestep(variables); if (upscaling_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::UpscalingFailure; } else if (upscaling_ret_code == StaggerReturnCode::UserTermination) { user_termination = true; } timer.stop(); m_timer.upscaling_time += timer.elapsed_time(); } // Final residuals // --------------- residuals.transport_residuals = m_transport_stagger->get_residual(variables); residuals.update = m_transport_stagger->get_update(variables); if (user_termination) return ReactiveTransportReturnCode::UserTermination; else if (bypass) return ReactiveTransportReturnCode::TransportBypass; else return ReactiveTransportReturnCode::NotConvergedYet; } // Check the convergence ReactiveTransportReturnCode ReactiveTransportSolver::check_convergence( VariablesBase* _, const internal::ReactiveTransportResiduals& residuals, ReactiveTransportReturnCode iteration_return_code ) { const scalar_t relative_residual = residuals.transport_residuals/residuals.transport_residual_0; // Residual if (relative_residual < get_options().residuals_tolerance or residuals.transport_residuals < get_options().absolute_residuals_tolerance) { return ReactiveTransportReturnCode::ResidualMinimized; } // Step else if (residuals.update < get_options().step_tolerance) { if (relative_residual < get_options().good_enough_tolerance) { return ReactiveTransportReturnCode::ErrorMinimized; } else return ReactiveTransportReturnCode::StationaryPoint; } else if (iteration_return_code == ReactiveTransportReturnCode::TransportBypass) { return ReactiveTransportReturnCode::TransportBypass; } else if (iteration_return_code == ReactiveTransportReturnCode::UserTermination) { return ReactiveTransportReturnCode::UserTermination; } // Number of iterations else if (residuals.nb_iterations >= get_options().maximum_iterations) { if (relative_residual < get_options().good_enough_tolerance) { return ReactiveTransportReturnCode::GoodEnough; } return ReactiveTransportReturnCode::MaximumIterationsReached; } return ReactiveTransportReturnCode::NotConvergedYet; } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/reactive_transport_solver.hpp b/src/reactmicp/solver/reactive_transport_solver.hpp index 0dd0389..86aac4f 100644 --- a/src/reactmicp/solver/reactive_transport_solver.hpp +++ b/src/reactmicp/solver/reactive_transport_solver.hpp @@ -1,179 +1,181 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP #define SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP //! \file reactive_transport_solver.hpp The reactive transport solver //! \namespace specmicp::reactmicp::solver Namespace containing the algorithms for the reactive transport solver #include "../../types.hpp" #include #include "reactive_transport_solver_structs.hpp" #include "../../utils/options_handler.hpp" #include "../../utils/perfs_handler.hpp" // forward declarations // ==================== namespace specmicp { namespace reactmicp { namespace solver { class VariablesBase; using VariablesBasePtr = std::shared_ptr; class TransportStaggerBase; class ChemistryStaggerBase; class UpscalingStaggerBase; using TransportStaggerPtr = std::shared_ptr; using ChemistryStaggerPtr = std::shared_ptr; using UpscalingStaggerPtr = std::shared_ptr; namespace internal { struct ReactiveTransportResiduals; } // end namespace internal } // end namespace solver } // end namespace reactmicp } // end namespace specmicp // Reactive Transport Solver // ========================= namespace specmicp { //! \namespace specmicp::reactmicp //! \brief The ReactMiCP solver and systems namespace reactmicp { //! \namespace specmicp::reactmicp::solver //! \brief The ReactMiCP solver namespace solver { //! \brief The reactive transport solver //! //! This class solves a reactive transport problem. //! The details of the problem are implemented in the staggers. //! //! There is three staggers : //! - The transport stagger //! - The chemistry stagger //! - The upscaling stagger //! //! The transport stagger also implements the residuals used to checked the convergence. //! //! This algorithm do not update, modify the variables. //! The details must be implemented in the staggers. //! The variables shared by the algorithm is a shared_ptr to the abstract base class specmicp::reactmicp::solver::VariablesBase //! To be useful, this variable must be casted to the true class in the staggers. class SPECMICP_DLL_PUBLIC ReactiveTransportSolver: public OptionsHandler, public PerformanceHandler { public: //! \brief Build a reactive transport //! //! \param transport_stagger shared_ptr to a transport stagger //! \param chemistry_stagger shared_ptr to a chemistry stagger //! \param upscaling_stagger shared_ptr to an upscaling stagger ReactiveTransportSolver( TransportStaggerPtr transport_stagger, ChemistryStaggerPtr chemistry_stagger, UpscalingStaggerPtr upscaling_stagger ): m_transport_stagger(transport_stagger), m_chemistry_stagger(chemistry_stagger), m_upscaling_stagger(upscaling_stagger) {} //! \brief Solve a timestep //! //! \param timestep The duration of the timestep //! \param variables shared_ptr to the variables ReactiveTransportReturnCode solve_timestep( scalar_t timestep, VariablesBasePtr variables ); //! \brief Solve a timestep //! //! \param timestep The duration of the timestep //! \param variables shared_ptr to the variables ReactiveTransportReturnCode solve_timestep( scalar_t timestep, VariablesBase* variables ); //! \brief Return the timer ReactiveTransportTimer& get_timer() {return m_timer;} private: // members //! \brief One iteration inside the timestep //! //! \param variables shared_ptr to the variables //! \param residuals struct containing the residuals information ReactiveTransportReturnCode SPECMICP_DLL_LOCAL one_iteration( VariablesBasePtr variables, internal::ReactiveTransportResiduals& residuals ); //! \brief One iteration inside the timestep //! //! \param variables raw ptr to the variables //! \param residuals struct containing the residuals information ReactiveTransportReturnCode SPECMICP_DLL_LOCAL one_iteration( VariablesBase* variables, internal::ReactiveTransportResiduals& residuals ); //! \brief Check the convergence //! //! \param variables shared_ptr to the variables //! \param residuals struct containing the residuals information ReactiveTransportReturnCode SPECMICP_DLL_LOCAL check_convergence( VariablesBase* variables, const internal::ReactiveTransportResiduals& residuals, ReactiveTransportReturnCode iteration_return_code ); private: // attributes TransportStaggerPtr m_transport_stagger; //!< The transport stagger ChemistryStaggerPtr m_chemistry_stagger; //!< The chemistry stagger UpscalingStaggerPtr m_upscaling_stagger; //!< The upscaling stagger ReactiveTransportTimer m_timer; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP diff --git a/src/reactmicp/solver/reactive_transport_solver_structs.hpp b/src/reactmicp/solver/reactive_transport_solver_structs.hpp index 41dabfd..cb90d6e 100644 --- a/src/reactmicp/solver/reactive_transport_solver_structs.hpp +++ b/src/reactmicp/solver/reactive_transport_solver_structs.hpp @@ -1,131 +1,133 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP #define SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP #include "../../types.hpp" //! \file reactive_transport_solver_structs.hpp //! \brief Structs used by the reactive transport solver #define REACTMICP_DEFAULT_RES_TOL 1e-4 #define REACTMICP_DEFAULT_ABS_TOL 1e-14 #define REACTMICP_DEFAULT_STEP_TOL 1e-10 #define REACTMICP_DEFAULT_GOOD_ENOUTH_TOL 1e-2 #define REACTMICP_DEFAULT_MAX_ITER 100 #define REACTMICP_DEFAULT_IMPL_UPSCALING true namespace specmicp { namespace reactmicp { namespace solver { //! \brief Return codes used by the reactive transport solver enum class ReactiveTransportReturnCode { UpscalingFailure = -13, //!< Upscaling stagger has failed ChemistryFailure = -12, //!< Chemistry stagger has failed TransportFailure = -11, //!< Transport stagger has failed StaggerFailure = -10, //!< A stagger has failed MaximumIterationsReached = - 2, //!< Maximum number of fixed-point iterations is reached StationaryPoint = - 1, //!< The solver has reached a stationnary points NotConvergedYet = 0, //!< The solver has not converged yet ResidualMinimized = 1, //!< The residuals are minimized ErrorMinimized = 2, //!< The error is minimized (may indicate a stationnary point) GoodEnough = 3, //!< Good enough TransportBypass = 5, //!< Transport is minimized, no need to do iterations UserTermination = 6, //!< User requested termination through one of the stagger }; //! \brief Options used by the reactive transport solver struct SPECMICP_DLL_PUBLIC ReactiveTransportOptions { //! Relative tolerance for the residuals scalar_t residuals_tolerance {REACTMICP_DEFAULT_RES_TOL}; //! Absolute tolerance for the residuals scalar_t absolute_residuals_tolerance {REACTMICP_DEFAULT_ABS_TOL}; //! Absolute tolerance for the step scalar_t step_tolerance {REACTMICP_DEFAULT_STEP_TOL}; //! Relative tolerance to detect a stationnary point scalar_t good_enough_tolerance {REACTMICP_DEFAULT_GOOD_ENOUTH_TOL}; //! Maximum number of iterations allowed index_t maximum_iterations {REACTMICP_DEFAULT_MAX_ITER}; //! When true, the upscaling problem is solved at each iteration bool implicit_upscaling {REACTMICP_DEFAULT_IMPL_UPSCALING}; //! \brief Use a Sequential Non-iterative Algorithm void set_snia() {maximum_iterations = 1;} //! \brief Return true if the problem is solved using a SNIA bool is_snia() {return maximum_iterations <= 1;} ReactiveTransportOptions() {} }; //! \brief Struct containing performance information //! //! This is valid for one timestep. struct SPECMICP_DLL_PUBLIC ReactiveTransportPerformance { scalar_t timestep; //!< Timestep used index_t nb_iterations; //!< The number of fixed-point iterations for this timestep ReactiveTransportReturnCode return_code; //!< The return code of the timestep scalar_t residuals; //!< The norm of the residuals at the end of the timestep scalar_t total_time; //!< Time spent solving one timestep scalar_t transport_time; //!< Time spent solving the transport problem scalar_t chemistry_time; //!< Time spent solving the chemistry problem ReactiveTransportPerformance(): nb_iterations(0), return_code(ReactiveTransportReturnCode::NotConvergedYet), residuals(HUGE_VAL), total_time(0.0), transport_time(0.0), chemistry_time(0.0) {} }; //! \brief Struct containing the execution time of the staggers struct SPECMICP_DLL_PUBLIC ReactiveTransportTimer { scalar_t transport_time; scalar_t chemistry_time; scalar_t upscaling_time; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP diff --git a/src/reactmicp/solver/runner.cpp b/src/reactmicp/solver/runner.cpp index 8e375af..76fb15d 100644 --- a/src/reactmicp/solver/runner.cpp +++ b/src/reactmicp/solver/runner.cpp @@ -1,127 +1,129 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "runner.hpp" #include "../io/reactive_transport.hpp" #include "../../utils/timer.hpp" #include #include "staggers_base/variables_base.hpp" #include "../../utils/io/csv_formatter.hpp" namespace specmicp { namespace reactmicp { namespace solver { void ReactiveTransportRunner::run_until(scalar_t target, VariablesBasePtr variables) { Timer total_time; VariablesBase* vars = variables.get(); total_time.start(); m_timestepper.set_total_target(target); m_output_target = m_timestepper.get_total()+m_simulinfo.output_step; io::OutFile out_iter( m_simulinfo.complete_filepath( std::string("iter"), std::string("dat"))); io::print_reactmicp_header(out_iter); if (m_simulinfo.print_iter_info) { io::print_reactmicp_performance_long_header(out_iter); } scalar_t dt = m_timestepper.get_options().restart_timestep; auto retcode = ReactiveTransportReturnCode::NotConvergedYet; while(retcode >= ReactiveTransportReturnCode::NotConvergedYet and m_timestepper.get_total() < m_timestepper.get_total_target()) { Timer step_timer; step_timer.start(); retcode = m_solver.solve_timestep(dt, vars); step_timer.stop(); if (m_simulinfo.print_iter_info) io::print_reactmicp_performance_long( out_iter, m_cnt, m_timestepper.get_total()+dt, m_solver.get_perfs() ); dt = m_timestepper.next_timestep( dt, retcode, m_solver.get_perfs().nb_iterations ); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = m_timestepper.get_options().restart_timestep; vars->reset_main_variables(); retcode = m_solver.solve_timestep(dt, vars); if (m_simulinfo.print_iter_info) io::print_reactmicp_performance_long( out_iter, m_cnt, m_timestepper.get_total()+dt, m_solver.get_perfs() ); dt = m_timestepper.next_timestep( dt, retcode, m_solver.get_perfs().nb_iterations ); } ++m_cnt; // output if (m_timestepper.get_total() > m_output_target) { m_output_function(m_timestepper.get_total(), variables); m_output_target += m_simulinfo.output_step; } if (retcode == reactmicp::solver::ReactiveTransportReturnCode::UserTermination) break; } total_time.stop(); io::print_reactmicp_end(out_iter, total_time, get_timer()); } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/runner.hpp b/src/reactmicp/solver/runner.hpp index 31657e7..93388f4 100644 --- a/src/reactmicp/solver/runner.hpp +++ b/src/reactmicp/solver/runner.hpp @@ -1,131 +1,133 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_RUNNER_HPP #define SPECMICP_REACTMICP_SOLVER_RUNNER_HPP #include "reactive_transport_solver.hpp" #include "timestepper.hpp" #include #include namespace specmicp { namespace reactmicp { namespace solver { //! \struct SimulationInformation //! \brief Information about the simulation struct SPECMICP_DLL_PUBLIC SimulationInformation { std::string name; //!< Name of the simulation std::string output_prefix; //!< prefix for the output files bool print_iter_info{true}; //!< If true, print the iteration informations scalar_t output_step; //!< output step SimulationInformation(std::string name_simul, scalar_t outputstep): name(name_simul), output_prefix(name_simul+"_"), output_step(outputstep) {} std::string complete_filepath(const std::string& name, const std::string& suffix) const { return output_prefix+name+"."+suffix; } std::string complete_filepath(std::string&& name, std::string&& suffix) const { return output_prefix+name+"."+suffix; } }; using output_f = std::function; inline void dummy_output(scalar_t _, VariablesBasePtr __) {} class SPECMICP_DLL_PUBLIC ReactiveTransportRunner { public: ReactiveTransportRunner(ReactiveTransportSolver& solver, scalar_t lower_dt_bound, scalar_t upper_dt_bound, const SimulationInformation& info): m_solver(solver), m_timestepper(lower_dt_bound, upper_dt_bound, 0, 2.0), m_simulinfo(info) { } void run_until(scalar_t target, VariablesBasePtr variables); void set_output_policy(output_f output_policy) { m_output_function = output_policy; } ReactiveTransportOptions& get_options() { return m_solver.get_options(); } TimestepperOptions& get_timestepper_options() { return m_timestepper.get_options(); } ReactiveTransportPerformance& get_perfs() { return m_solver.get_perfs(); } ReactiveTransportTimer& get_timer() { return m_solver.get_timer(); } private: index_t m_cnt{0}; ReactiveTransportSolver& m_solver; Timestepper m_timestepper; const SimulationInformation& m_simulinfo; output_f m_output_function{dummy_output}; scalar_t m_output_target; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_RUNNER_HPP diff --git a/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp b/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp index a063371..491d170 100644 --- a/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp @@ -1,85 +1,87 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP //! \file chemistry_stagger_base.hpp The base class for a chemistry stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for a transport stagger //! //! Implement the chemistry (equilibrium, kinetics, ...) in a derived class class ChemistryStaggerBase { public: virtual ~ChemistryStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a raw pointer to the variables virtual void initialize(VariablesBase * const var) {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables void initialize(std::shared_ptr var) { return initialize(var.get()); } //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a raw pointer to the variables virtual void initialize_timestep(scalar_t dt, VariablesBase * const var) = 0; //! \brief Solve the equation for the timestep //! //! \param var a raw ptr to the variables virtual StaggerReturnCode restart_timestep(VariablesBase * const var) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/decl.inl b/src/reactmicp/solver/staggers_base/decl.inl index c69769b..f416b46 100644 --- a/src/reactmicp/solver/staggers_base/decl.inl +++ b/src/reactmicp/solver/staggers_base/decl.inl @@ -1,54 +1,56 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_DECL_INL #define SPECMICP_REACTMICP_SOLVER_DECL_INL //! \file decl.inl common declaration needed for the *stagger_base headers #include "../../../types.hpp" #include namespace specmicp { namespace reactmicp { namespace solver { // forward declaration class VariablesBase; enum class StaggerReturnCode; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_DECL_INL diff --git a/src/reactmicp/solver/staggers_base/stagger_structs.hpp b/src/reactmicp/solver/staggers_base/stagger_structs.hpp index 489725b..0d113b5 100644 --- a/src/reactmicp/solver/staggers_base/stagger_structs.hpp +++ b/src/reactmicp/solver/staggers_base/stagger_structs.hpp @@ -1,63 +1,65 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP #define SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP //! \file stagger_structs.hpp common structs for the staggers namespace specmicp { namespace reactmicp { namespace solver { //! \brief Return code error used by a stagger //! //! Success of the stagger should be tested as : //! return code > NotConvergedYet enum class StaggerReturnCode { LolThatsNotSupposedToHappen = -5, //!< Mainly for debugging purposes UnknownError = -4, //!< Generic error, when used, an entry in the log is necessary MaximumIterationsReached = -3, //!< Maximum number of iterations reached in the code StationaryPoint = -2, //!< Stagger is stuck in a Stationary point NotConvergedYet = -1, //!< The stagger has not converged yet // ----------------------------- UserTermination = 1, //!< The simulation should be stopped ResidualMinimized = 2, //!< The residuals are minimized ErrorMinimized = 3 //!< The error is minimized }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP diff --git a/src/reactmicp/solver/staggers_base/staggers_base.hpp b/src/reactmicp/solver/staggers_base/staggers_base.hpp index b8d2623..0ed3a1e 100644 --- a/src/reactmicp/solver/staggers_base/staggers_base.hpp +++ b/src/reactmicp/solver/staggers_base/staggers_base.hpp @@ -1,39 +1,41 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file staggers_base.hpp Include headers of the staggers base directory #include "variables_base.hpp" #include "transport_stagger_base.hpp" #include "chemistry_stagger_base.hpp" #include "upscaling_stagger_base.hpp" #include "stagger_structs.hpp" diff --git a/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp b/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp index 2fc6464..b3d3b1b 100644 --- a/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp @@ -1,110 +1,112 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP //! \file transport_stagger_base.hpp The base class for the transport stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for a transport stagger //! class TransportStaggerBase { public: virtual ~TransportStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var raw pointer to the variables virtual void initialize(VariablesBase * const var) {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var shared_ptr to the variables void initialize(std::shared_ptr var) { return initialize(var.get()); } //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the first residual may be computed, the predictor saved, ... //! \param dt the duration of the timestep //! \param var raw pointer to the variables virtual void initialize_timestep( scalar_t dt, VariablesBase * const var ) = 0; //! \brief Solve the equation for the timetep //! //! \param var raw pointer to the variables virtual StaggerReturnCode restart_timestep( VariablesBase * const var ) = 0; //! \brief Compute the residuals norm //! //! \param var raw pointer to the variables virtual scalar_t get_residual( VariablesBase * const var ) = 0; //! \brief Compute the residuals norm //! //! \param var raw pointer to the variables virtual scalar_t get_residual_0( VariablesBase * const var ) = 0; //! \brief Obtain the norm of the step size //! //! This is used to check if the algorithm has reach a stationary points. //! It should look like : return main_variables.norm() //! //! \param var shared_ptr to the variables virtual scalar_t get_update( VariablesBase * const var ) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp b/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp index f616722..ba3d85b 100644 --- a/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp @@ -1,89 +1,91 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP //! \file upscaling_stagger_base.hpp The base class for the upscaling stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for an upscaling stagger //! class UpscalingStaggerBase { public: virtual ~UpscalingStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a raw pointer to the variables virtual void initialize(VariablesBase * const var) {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables void initialize(std::shared_ptr var) { return initialize(var.get()); } //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a raw pointer to the variables virtual void initialize_timestep( scalar_t dt, VariablesBase * const var ) = 0; //! \brief Solve the equation for the timestep //! //! \param var a raw pointer to the variables virtual StaggerReturnCode restart_timestep( VariablesBase * const var ) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/variables_base.hpp b/src/reactmicp/solver/staggers_base/variables_base.hpp index 6369be9..68668cf 100644 --- a/src/reactmicp/solver/staggers_base/variables_base.hpp +++ b/src/reactmicp/solver/staggers_base/variables_base.hpp @@ -1,58 +1,60 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP #define SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP //! \file variables_base.hpp Base class for a reactive transport variables namespace specmicp { namespace reactmicp { namespace solver { //! \brief Variables base class //! //! This is just for polymorphism, implementations is left to the user. class VariablesBase { public: virtual ~VariablesBase() {} //! \brief Reset the variables to restart a computation in case of failure virtual void reset_main_variables() = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP diff --git a/src/reactmicp/solver/timestepper.cpp b/src/reactmicp/solver/timestepper.cpp index 63ed723..cc611ae 100644 --- a/src/reactmicp/solver/timestepper.cpp +++ b/src/reactmicp/solver/timestepper.cpp @@ -1,97 +1,99 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "timestepper.hpp" #include "reactive_transport_solver_structs.hpp" namespace specmicp { namespace reactmicp { namespace solver { scalar_t Timestepper::next_timestep( scalar_t dt_done, ReactiveTransportReturnCode return_code, index_t nb_iterations ) { if (return_code <= ReactiveTransportReturnCode::NotConvergedYet) { return get_options().decrease_failure*dt_done; } // previous timestep is correct m_total += dt_done; m_average.add_point(nb_iterations); scalar_t proposed_dt = dt_done; // If the error is minimized we increase the timestep if (return_code == ReactiveTransportReturnCode::ErrorMinimized) { proposed_dt *= get_options().increase_error_minimization; } else // Increase or decrease the timestep to reach the number of iteration target range { if (m_average.current_value() <= get_options().iteration_lower_target) { proposed_dt *= get_options().increase_factor; } else if (m_average.current_value() > get_options().iteration_upper_target) { proposed_dt *= get_options().decrease_factor; } } // Check that the total target is not exceeded if (m_total + proposed_dt > m_total_target) { proposed_dt = m_total_target - m_total; } // Check that the timestep is inside the bounds if (proposed_dt < get_options().lower_bound) { proposed_dt = get_options().lower_bound; } else if (proposed_dt > get_options().upper_bound) { proposed_dt = get_options().upper_bound; } return proposed_dt; } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/timestepper.hpp b/src/reactmicp/solver/timestepper.hpp index ec6a144..66d6739 100644 --- a/src/reactmicp/solver/timestepper.hpp +++ b/src/reactmicp/solver/timestepper.hpp @@ -1,119 +1,121 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP #define SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP #include "../../utils/moving_average.hpp" #include "../../utils/options_handler.hpp" namespace specmicp { namespace reactmicp { namespace solver { // forward declaration enum class ReactiveTransportReturnCode; //! \brief Options for the timestepper struct SPECMICP_DLL_PUBLIC TimestepperOptions { scalar_t lower_bound; //!< Lower bound for the timestep scalar_t upper_bound; //!< Upper bound for the timestep scalar_t restart_timestep; //!< Value used when restarting the problem scalar_t iteration_lower_target{1.01}; //!< Lower target for the number of iterations scalar_t iteration_upper_target{15.0}; //!< Upper target for the number of iterations scalar_t alpha_average{0.5}; //!< Parameter for the exponential moving average scalar_t decrease_failure{0.5}; //!< Reduction factor in case of failure scalar_t increase_error_minimization{1.3}; //!< Increase factor in case of error minimization scalar_t decrease_factor{0.75}; //!< Reduction factor to get the number of iterations inside the target scalar_t increase_factor{1.25}; //!< Increase factor to get the number of iterations inside the target TimestepperOptions(scalar_t dt_lower_bound, scalar_t dt_upper_bound): lower_bound(dt_lower_bound), upper_bound(dt_upper_bound), restart_timestep(dt_lower_bound) {} }; //! \brief Adaptative timestepper for the reactive transport solver class SPECMICP_DLL_PUBLIC Timestepper: public OptionsHandler { public: //! \brief Constructor //! //! \param dt_lower_bound lower_bound for the timestep //! \param dt_upper_bound upper_bound for the timestep //! \param total_target total target time //! \param init_iterations initial iterations Timestepper(scalar_t dt_lower_bound, scalar_t dt_upper_bound, scalar_t total_target, scalar_t init_iterations ): OptionsHandler(dt_lower_bound, dt_upper_bound), m_total(0), m_total_target(total_target), m_average(0.5, init_iterations) { m_average.set_alpha(get_options().alpha_average); } //! \brief Return the total time scalar_t get_total() const {return m_total;} //! \brief Return the total target time scalar_t get_total_target() const {return m_total_target;} //! \brief Set the total target time void set_total_target(scalar_t total_target) {m_total_target = total_target;} void set_average_parameter(scalar_t alpha) { get_options().alpha_average = alpha; m_average.set_alpha(alpha); } //! obtain the next timestep scalar_t next_timestep(scalar_t dt_done, ReactiveTransportReturnCode return_code, index_t nb_iterations); private: scalar_t m_total; scalar_t m_total_target; utils::ExponentialMovingAverage m_average; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP diff --git a/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.cpp b/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.cpp index f174374..aa7d375 100644 --- a/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.cpp @@ -1,143 +1,145 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "diffusive_upscaling_stagger.hpp" #include "../../solver/staggers_base/stagger_structs.hpp" #include "variables.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { void DiffusiveUpscalingStagger::initialize(VariablesBase * const var) { SaturatedVariables * const true_var = static_cast(var); true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } void DiffusiveUpscalingStagger::initialize_timestep( scalar_t dt, VariablesBase * const var ) { SaturatedVariables * const true_var = static_cast(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! This is the main function called during a timestep StaggerReturnCode DiffusiveUpscalingStagger::restart_timestep(VariablesBase * const var) { SaturatedVariables * const true_var = static_cast(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } if (not m_checker(true_var)) return StaggerReturnCode::UserTermination; return StaggerReturnCode::ResidualMinimized; // This is the value that should be returned if everything is ok } void DiffusiveUpscalingStagger::upscaling_one_node( index_t node, SaturatedVariables * const true_var ) { // AdimensionalSystemSolutionExtractor is the class to use to // extract information from a SpecMiCP solution // To obtain correct information the correct units must be used AdimensionalSystemSolutionExtractor extractor( true_var->equilibrium_solution(node), m_data, m_units_set ); // We can obtain the porosity very easily : scalar_t porosity = extractor.porosity(); true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = m_diffusion_law(node, true_var); } scalar_t PowerLaw::get_diffusion_coefficient( index_t node, SaturatedVariables * const true_var ) { scalar_t tmp_1 = true_var->porosity(node) - m_param.porosity_res; scalar_t tmp_2 = m_param.porosity_0 - m_param.porosity_res; scalar_t res = tmp_1/tmp_2; tmp_1 = std::pow(res, m_param.exponent); res = m_param.d_eff_0*tmp_1; return res; } diffusion_f PowerLaw::get_law() { return std::bind(std::mem_fn(&PowerLaw::get_diffusion_coefficient), this, std::placeholders::_1, std::placeholders::_2); } scalar_t CappedPowerLaw::get_diffusion_coefficient( index_t node, SaturatedVariables * const true_var ) { scalar_t tmp_1 = true_var->porosity(node) - m_param.porosity_res; scalar_t tmp_2 = m_param.porosity_0 - m_param.porosity_res; scalar_t res = tmp_1/tmp_2; tmp_1 = std::pow(res, m_param.exponent); res = m_param.d_eff_0*tmp_1; return std::min(m_param.cap, res); } diffusion_f CappedPowerLaw::get_law() { return std::bind(std::mem_fn(&CappedPowerLaw::get_diffusion_coefficient), this, std::placeholders::_1, std::placeholders::_2); } } //end namespace satdiff } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp b/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp index d8b1e69..22eda72 100644 --- a/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp @@ -1,168 +1,170 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SATDIFF_DIFFUSIVEUPSCALING_STAGGER #define SPECMICP_REACTMICP_SATDIFF_DIFFUSIVEUPSCALING_STAGGER //! \file diffusive_upscaling_stagger.hpp //! \brief A diffusive upscaling stagger for the saturated system #include "../../../database.hpp" #include "../../solver/staggers_base/decl.inl" #include "../../solver/staggers_base/variables_base.hpp" #include "../../solver/staggers_base/upscaling_stagger_base.hpp" #include "variablesfwd.hpp" #include "../../../physics/units.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using StaggerReturnCode = solver::StaggerReturnCode; using VariablesBase = solver::VariablesBase; //! \brief The type of a diffusion law using diffusion_f = std::function; //! \brief A function that return false if the computation must be stopped using check_f = std::function; inline bool dummy_check(SaturatedVariables * const _) {return true;} //! \brief A upscaling stagger for a diffusive case class SPECMICP_DLL_PUBLIC DiffusiveUpscalingStagger: public solver::UpscalingStaggerBase { public: // Initiation // This is not call automatically so can be adjusted by the user DiffusiveUpscalingStagger( const diffusion_f& diffusion_law, RawDatabasePtr& the_database, units::UnitsSet the_units): m_diffusion_law(diffusion_law), m_data(the_database), m_units_set(the_units), m_dt(HUGE_VAL) { } // Initialize the stagger at the beginning of the computation // The porosity and transport properties should be initialized here void initialize(VariablesBase * const var) override; // Initialize the stagger at the beginning of a timestep // Typically do nothing but erase the "dot" variable (velocity such as the vel_porosity) void initialize_timestep(scalar_t dt, VariablesBase * const var) override; //! This is the main function called during a timestep StaggerReturnCode restart_timestep(VariablesBase * const var) override; // Compute the upscaling for 'node' void upscaling_one_node(index_t node, SaturatedVariables * const true_var); void set_checker(const check_f& checker) {m_checker = checker;} private: diffusion_f m_diffusion_law; check_f m_checker {&dummy_check}; RawDatabasePtr m_data; units::UnitsSet m_units_set; scalar_t m_dt; }; //! \brief The parameters for a power law struct SPECMICP_DLL_PUBLIC PowerLawParameters { scalar_t exponent; scalar_t d_eff_0; scalar_t porosity_0; scalar_t porosity_res; }; //! \brief The power law class PowerLaw { public: PowerLaw(const PowerLawParameters& params): m_param(params) {} scalar_t get_diffusion_coefficient( index_t node, SaturatedVariables * const true_var ); diffusion_f get_law(); private: PowerLawParameters m_param; }; //! \brief The parameters for the capped power law struct SPECMICP_DLL_PUBLIC CappedPowerLawParameters { scalar_t exponent; scalar_t d_eff_0; scalar_t porosity_0; scalar_t porosity_res; scalar_t cap; }; //! \brief The capped power law class SPECMICP_DLL_PUBLIC CappedPowerLaw { public: CappedPowerLaw(const CappedPowerLawParameters& params): m_param(params) {} scalar_t get_diffusion_coefficient( index_t node, SaturatedVariables * const true_var ); diffusion_f get_law(); private: CappedPowerLawParameters m_param; }; } //end namespace satdiff } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_SATDIFF_DIFFUSIVEUPSCALING_STAGGER diff --git a/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp b/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp index 9ce5deb..5b42b77 100644 --- a/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp @@ -1,188 +1,190 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "equilibrium_stagger.hpp" #include "variables.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../../utils/log.hpp" #include "../../../reactmicp/solver/staggers_base/stagger_structs.hpp" #ifdef SPECMICP_USE_OPENMP #include #endif // SPECMICP_USE_OPENMP namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using TrueConstPtr = SaturatedVariables * const; inline TrueConstPtr cast_to_var(solver::VariablesBase * const var) { return static_cast(var); } // EquilibriumStagger:: //! \brief Initialize the stagger at the beginning of an iteration void EquilibriumStagger::initialize_timestep( scalar_t dt, VariablesBase * const var) { m_dt = dt; TrueConstPtr true_var = cast_to_var(var); // Initialize velocity using values from previous timestep for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; scalar_t alpha = 1.0; for (index_t component: true_var->get_database()->range_aqueous_component()) { alpha = std::max(alpha, 0.9*dt*true_var->solid_concentration(node, component, true_var->chemistry_rate()) /(true_var->solid_concentration(node, component, true_var->displacement())) ); } auto solid_velocity = true_var->velocity().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); auto solid_chemistry_rate = true_var->chemistry_rate().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); solid_velocity = 1/alpha * solid_chemistry_rate; } } //! \brief Solve the equation for the timestep solver::StaggerReturnCode EquilibriumStagger::restart_timestep(VariablesBase * const var) { TrueConstPtr true_var = cast_to_var(var); int failed_chemistry = 0; #ifdef SPECMICP_USE_OPENMP #pragma omp parallel default(none) shared(failed_chemistry) // node true_var being const is shared by default, can't be mentionned again { #pragma omp for schedule(dynamic, 5) for (index_t node=0; nodenb_nodes(); ++node) { // only solve if necessary if (true_var->is_fixed_composition(node) or failed_chemistry > 0) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; } } } #else { for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; break; } } } #endif // SPECMICP_USE_OPENMP if (failed_chemistry > 0) return solver::StaggerReturnCode::UnknownError; return solver::StaggerReturnCode::ResidualMinimized; } //! int EquilibriumStagger::solve_one_node( index_t node, SaturatedVariables * const true_var ) { AdimensionalSystemConstraints constraints(get_constraints(node)); constraints.total_concentrations = true_var->total_concentrations(node); AdimensionalSystemSolver adim_solver(true_var->get_database(), constraints, true_var->equilibrium_solution(node), m_options); Vector variables(true_var->equilibrium_solution(node).main_variables); micpsolver::MiCPPerformance perf = adim_solver.solve(variables); micpsolver::MiCPSolverReturnCode retcode = perf.return_code; if (retcode <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { ERROR << "Failed to solve chemistry problem at node " << node << ", return code = " << static_cast(retcode) << ", residual = " << perf.current_residual; ERROR << "Total concentration : \n" << constraints.total_concentrations; return 1; } true_var->equilibrium_solution(node) = adim_solver.get_raw_solution(variables); AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), true_var->get_database(), m_options.units_set); for (index_t component=0; componentnb_component(); ++component) { const scalar_t c_aq = extractor.density_water()*extractor.total_aqueous_concentration(component); true_var->aqueous_concentration(node, component, true_var->displacement()) = c_aq; const scalar_t c_aq_0 = true_var->aqueous_concentration(node, component, true_var->predictor()); const scalar_t vel_aq = (c_aq - c_aq_0)/m_dt; true_var->aqueous_concentration(node, component, true_var->velocity()) = vel_aq; const scalar_t c_sol = extractor.total_immobile_concentration(component); true_var->solid_concentration(node, component, true_var->displacement()) = c_sol; const scalar_t c_sol_0 = true_var->solid_concentration(node, component, true_var->predictor()); const scalar_t vel_sol = (c_sol - c_sol_0)/m_dt; true_var->solid_concentration(node, component, true_var->velocity()) = vel_sol; true_var->solid_concentration(node, component, true_var->chemistry_rate()) = vel_sol; } return 0; } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp b/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp index 840eed0..2cf2160 100644 --- a/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp @@ -1,112 +1,114 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP #include "../../solver/staggers_base/chemistry_stagger_base.hpp" #include "variablesfwd.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver_structs.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using VariablesBase = solver::VariablesBase; //! \brief Solve the equilibrium problem class SPECMICP_DLL_PUBLIC EquilibriumStagger: public solver::ChemistryStaggerBase { public: EquilibriumStagger(index_t nb_nodes, AdimensionalSystemConstraints constraints, AdimensionalSystemSolverOptions options): m_id_constraints(nb_nodes, 0), m_list_constraints({constraints,}), m_options(options) {} EquilibriumStagger( std::vector list_constraints, std::vector index_constraints, AdimensionalSystemSolverOptions options): m_id_constraints(index_constraints), m_list_constraints(list_constraints), m_options(options) {} //! \brief Initialize the stagger at the beginning of the computation virtual void initialize(VariablesBase * const var) override {} //! \brief Initialize the stagger at the beginning of the computation void initialize(std::shared_ptr& var) {} //! \brief Initialize the stagger at the beginning of an iteration virtual void initialize_timestep( scalar_t dt, VariablesBase * const var ) override; //! \brief Solve the equation for the timestep virtual solver::StaggerReturnCode restart_timestep( VariablesBase * const var ) override; //! \brief Solve the speciation problem at one node int solve_one_node(index_t node, SaturatedVariables * const var); //! \brief Return the constraints for 'node' //! //! \param node Index of the node AdimensionalSystemConstraints& get_constraints(index_t node) { return m_list_constraints[m_id_constraints[node]]; } private: scalar_t m_dt; std::vector m_id_constraints; std::vector m_list_constraints; AdimensionalSystemSolverOptions m_options; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP diff --git a/src/reactmicp/systems/saturated_react/init_variables.cpp b/src/reactmicp/systems/saturated_react/init_variables.cpp index df00804..fc66528 100644 --- a/src/reactmicp/systems/saturated_react/init_variables.cpp +++ b/src/reactmicp/systems/saturated_react/init_variables.cpp @@ -1,134 +1,136 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "init_variables.hpp" #include "variables.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //! \brief Initialise an instance of SaturatedVariables SaturatedVariablesPtr init_variables( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ) { SaturatedVariablesFactory factory(the_mesh, the_database, the_units, list_fixed_nodes, list_initial_states, index_initial_state); return factory.get_variable(); } // SaturatedVariablesFactory:: SaturatedVariablesFactory::SaturatedVariablesFactory( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ): m_variable(std::make_shared(the_mesh, the_database)), m_database(the_database), nb_component(the_database->nb_component()), nb_nodes(the_mesh->nb_nodes()) { init_size(); set_fixed_nodes(list_fixed_nodes); init_chemistry(the_units, index_initial_state, list_initial_states); } void SaturatedVariablesFactory::init_size() { index_t main_ndf = nb_nodes*2*nb_component; m_variable->displacement() = Vector::Zero(main_ndf); m_variable->chemistry_rate() = Vector::Zero(main_ndf); m_variable->transport_rate() = Vector::Zero(main_ndf); m_variable->predictor() = Vector::Zero(main_ndf); m_variable->velocity() = Vector::Zero(main_ndf); m_variable->m_upscaling = Vector::Zero(m_variable->ndf_upscaling()*nb_nodes); } void SaturatedVariablesFactory::set_fixed_nodes(const std::vector& list_fixed_nodes) { m_variable->m_is_fixed_composition = std::vector(nb_nodes, false); for (index_t node: list_fixed_nodes) { m_variable->m_is_fixed_composition[node] = true; } } void SaturatedVariablesFactory::init_chemistry( units::UnitsSet the_units, const std::vector& index_initial_state, const std::vector& list_initial_states) { m_variable->m_equilibrium_solutions.reserve(nb_nodes); for (index_t node=0; nodem_equilibrium_solutions.push_back(list_initial_states[index_initial_state[node]]); AdimensionalSystemSolutionExtractor extractor(m_variable->m_equilibrium_solutions[node], m_database, the_units); scalar_t rho_w = extractor.density_water(); for (index_t component: m_database->range_component()) { m_variable->aqueous_concentration(node, component, m_variable->displacement()) = rho_w*extractor.total_aqueous_concentration(component); m_variable->solid_concentration(node, component, m_variable->displacement()) = extractor.total_immobile_concentration(component); } } } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/init_variables.hpp b/src/reactmicp/systems/saturated_react/init_variables.hpp index 7327bf3..05d8c31 100644 --- a/src/reactmicp/systems/saturated_react/init_variables.hpp +++ b/src/reactmicp/systems/saturated_react/init_variables.hpp @@ -1,94 +1,96 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP #include "variablesfwd.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "../../../database.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //! \brief Initialize an instance of Saturated Variables class SaturatedVariablesFactory { public: SaturatedVariablesFactory( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ); //! \brief Initialize the main vectors void init_size(); //! \brief Initialize the BC void set_fixed_nodes(const std::vector& list_fixed_nodes); //! \brief Initialize the chemistry informations void init_chemistry( units::UnitsSet the_units, const std::vector& index_initial_state, const std::vector& list_initial_states); //! \brief Return the variables SaturatedVariablesPtr get_variable() {return m_variable;} private: SaturatedVariablesPtr m_variable; RawDatabasePtr m_database; index_t nb_component; index_t nb_nodes; }; //! \brief Initialise an instance of SaturatedVariables SaturatedVariablesPtr SPECMICP_DLL_PUBLIC init_variables( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ); } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP diff --git a/src/reactmicp/systems/saturated_react/kinetic_stagger.cpp b/src/reactmicp/systems/saturated_react/kinetic_stagger.cpp index 102cf8e..e588fdb 100644 --- a/src/reactmicp/systems/saturated_react/kinetic_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/kinetic_stagger.cpp @@ -1,205 +1,207 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "kinetic_stagger.hpp" #include "variables.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../../utils/log.hpp" #include "../../../reactmicp/solver/staggers_base/stagger_structs.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using TrueConstPtr = SaturatedVariables * const; inline TrueConstPtr cast_to_var(VariablesBase * const var) { return static_cast(var); } //! \brief Initialize the stagger at the beginning of an iteration void KineticStagger::initialize_timestep(scalar_t dt, VariablesBase * const var) { TrueConstPtr true_var = cast_to_var(var); m_dt = dt; // Initialize velocity using values from previous timestep for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; scalar_t alpha = 1.0; for (index_t component: true_var->get_database()->range_aqueous_component()) { alpha = std::max(alpha, 0.9*dt*true_var->solid_concentration(node, component, true_var->chemistry_rate()) /(true_var->solid_concentration(node, component, true_var->displacement())) ); } auto solid_velocity = true_var->velocity().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); auto solid_chemistry_rate = true_var->chemistry_rate().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); solid_velocity = 1/alpha * solid_chemistry_rate; } m_model->initialize_timestep(dt, true_var->kinetic_variables()); for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; m_model->restart_timestep(node, true_var->equilibrium_solution(node), true_var->kinetic_variables()); for (index_t component=0; componentnb_component(); ++component) { true_var->aqueous_concentration(node, component, true_var->chemistry_rate()) = - m_model->get_velocity_kinetic(node, component, true_var->kinetic_variables()); true_var->aqueous_concentration(node, component, true_var->velocity()) += ( //true_var->aqueous_concentration(node, component, true_var->transport_rate()) + true_var->aqueous_concentration(node, component, true_var->chemistry_rate()) //- true_var->solid_concentration(node, component, true_var->chemistry_rate()) ); true_var->aqueous_concentration(node, component, true_var->displacement()) = true_var->aqueous_concentration(node, component, true_var->predictor()) + m_dt*true_var->aqueous_concentration(node, component, true_var->velocity()); } } } //! \brief Solve the equation for the timestep solver::StaggerReturnCode KineticStagger::restart_timestep( VariablesBase * const var) { TrueConstPtr true_var = cast_to_var(var); int failed_chemistry = 0; #ifdef SPECMICP_USE_OPENMP #pragma omp parallel default(none) shared(failed_chemistry) // node true_var being const is shared by default, can't be mentionned again { #pragma omp for schedule(dynamic, 5) for (index_t node=0; nodenb_nodes(); ++node) { // only solve if necessary if (true_var->is_fixed_composition(node) or failed_chemistry > 0) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; } } } #else { for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; break; } } } #endif // SPECMICP_USE_OPENMP if (failed_chemistry > 0) return solver::StaggerReturnCode::UnknownError; return solver::StaggerReturnCode::ResidualMinimized; } //! int KineticStagger::solve_one_node( index_t node, SaturatedVariables * const true_var ) { AdimensionalSystemConstraints constraints(get_constraints(node)); constraints.total_concentrations = true_var->total_concentrations(node); constraints.set_inert_volume_fraction(m_model->get_volume_fraction_kinetic(node, true_var->kinetic_variables())); AdimensionalSystemSolver adim_solver(true_var->get_database(), constraints, true_var->equilibrium_solution(node), m_options); Vector variables(true_var->equilibrium_solution(node).main_variables); micpsolver::MiCPPerformance perf = adim_solver.solve(variables); micpsolver::MiCPSolverReturnCode retcode = perf.return_code; if (retcode <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { ERROR << "Failed to solve chemistry problem at node " << node << ", return code = " << static_cast(retcode) << ", residual = " << perf.current_residual; ERROR << "Total concentration : \n" << constraints.total_concentrations; return 1; } true_var->equilibrium_solution(node) = adim_solver.get_raw_solution(variables); AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), true_var->get_database(), m_options.units_set); for (index_t component=0; componentnb_component(); ++component) { const scalar_t c_aq = extractor.density_water()*extractor.total_aqueous_concentration(component); true_var->aqueous_concentration(node, component, true_var->displacement()) = c_aq; const scalar_t c_aq_0 = true_var->aqueous_concentration(node, component, true_var->predictor()); const scalar_t vel_aq = (c_aq - c_aq_0)/m_dt; true_var->aqueous_concentration(node, component, true_var->velocity()) = vel_aq; const scalar_t c_sol = extractor.total_immobile_concentration(component); true_var->solid_concentration(node, component, true_var->displacement()) = c_sol; const scalar_t c_sol_0 = true_var->solid_concentration(node, component, true_var->predictor()); const scalar_t vel_sol = (c_sol - c_sol_0)/m_dt; true_var->solid_concentration(node, component, true_var->velocity()) = vel_sol; true_var->solid_concentration(node, component, true_var->chemistry_rate()) = vel_sol; } return 0; } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/kinetic_stagger.hpp b/src/reactmicp/systems/saturated_react/kinetic_stagger.hpp index bbf7472..867ea9b 100644 --- a/src/reactmicp/systems/saturated_react/kinetic_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/kinetic_stagger.hpp @@ -1,151 +1,153 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SATDIFF_KINETICSTAGGER_HPP #define SPECMICP_REACTMICP_SATDIFF_KINETICSTAGGER_HPP //! \file saturated_react/kinetic_stagger.hpp //! \brief The kinetic stagger for the saturated reactive transport solver #include "../../solver/staggers_base/chemistry_stagger_base.hpp" #include "variablesfwd.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using VariablesBase = solver::VariablesBase; //! \brief The Kinetic model //! //! This is an abstract class. class SPECMICP_DLL_PUBLIC KineticModelBase { public: virtual ~KineticModelBase() {} //! \brief Initialize a timestep virtual void initialize_timestep( scalar_t dt, KineticSaturatedVariablesBasePtr kinetic_variables) = 0; //! \brief Restart a timestep virtual void restart_timestep( index_t node, const AdimensionalSystemSolution& eq_solution, KineticSaturatedVariablesBasePtr kinetic_variables) = 0; //! \brief Return the volume fraction of kinetic (or inert) phases virtual scalar_t get_volume_fraction_kinetic( index_t node, KineticSaturatedVariablesBasePtr kinetic_variables) = 0; //! \brief Return the velocity of the total immobile kinetic concentration for component virtual scalar_t get_velocity_kinetic( index_t node, index_t component, KineticSaturatedVariablesBasePtr kinetic_variables) = 0; }; using KineticModelBasePtr = std::shared_ptr; //! \brief Solve the kinetic and equilibrium problems class SPECMICP_DLL_PUBLIC KineticStagger: public solver::ChemistryStaggerBase { public: KineticStagger( index_t nb_nodes, KineticModelBasePtr the_model, AdimensionalSystemConstraints constraints, AdimensionalSystemSolverOptions options ): m_model(the_model), m_id_constraints(nb_nodes, 0), m_list_constraints({constraints,}), m_options(options) {} KineticStagger( KineticModelBasePtr the_model, std::vector list_constraints, std::vector index_constraints, AdimensionalSystemSolverOptions options ): m_model(the_model), m_id_constraints(index_constraints), m_list_constraints(list_constraints), m_options(options) {} //! \brief Initialize the stagger at the beginning of the computation virtual void initialize(VariablesBase * const var) override {} //! \brief Initializze the stagger at the beginning of the computation void initialize(std::shared_ptr& _) {} //! \brief Initialize the stagger at the beginning of an iteration virtual void initialize_timestep( scalar_t dt, VariablesBase * const var ) override; //! \brief Solve the equation for the timestep virtual solver::StaggerReturnCode restart_timestep( VariablesBase * const var) override; //! \brief Solve the speciation problem at one node int solve_one_node(index_t node, SaturatedVariables * const var); //! \brief Return the constraints for 'node' //! //! \param node Index of the node AdimensionalSystemConstraints& get_constraints(index_t node) { return m_list_constraints[m_id_constraints[node]]; } private: scalar_t m_dt {-1.0}; KineticModelBasePtr m_model; std::vector m_id_constraints; std::vector m_list_constraints; AdimensionalSystemSolverOptions m_options; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SATDIFF_KINETICSTAGGER_HPP diff --git a/src/reactmicp/systems/saturated_react/react_solver.cpp b/src/reactmicp/systems/saturated_react/react_solver.cpp index a0b7682..358c28a 100644 --- a/src/reactmicp/systems/saturated_react/react_solver.cpp +++ b/src/reactmicp/systems/saturated_react/react_solver.cpp @@ -1,43 +1,45 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "react_solver.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/react_solver.hpp b/src/reactmicp/systems/saturated_react/react_solver.hpp index 83c7ac6..2c3fe33 100644 --- a/src/reactmicp/systems/saturated_react/react_solver.hpp +++ b/src/reactmicp/systems/saturated_react/react_solver.hpp @@ -1,50 +1,52 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP diff --git a/src/reactmicp/systems/saturated_react/transport_program.cpp b/src/reactmicp/systems/saturated_react/transport_program.cpp index 0388697..0778976 100644 --- a/src/reactmicp/systems/saturated_react/transport_program.cpp +++ b/src/reactmicp/systems/saturated_react/transport_program.cpp @@ -1,359 +1,361 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "transport_program.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "variables.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //class SaturatedDiffusion:: SaturatedDiffusion::SaturatedDiffusion( SaturatedVariables* variables, std::vector list_fixed_nodes ): m_ndf(2*variables->nb_component()), m_tot_ndf(2*variables->nb_component()*variables->get_mesh()->nb_nodes()), m_mesh(variables->get_mesh()), m_variables(variables), m_is_in_residual_computation(false), m_fixed_components(variables->nb_component(), false) { number_equations(list_fixed_nodes, {}, {0, 1}); } SaturatedDiffusion::SaturatedDiffusion( SaturatedVariables* variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components ): m_ndf(2*variables->nb_component()), m_tot_ndf(2*variables->nb_component()*variables->get_mesh()->nb_nodes()), m_mesh(variables->get_mesh()), m_variables(variables), m_is_in_residual_computation(false), m_fixed_components(variables->nb_component(), false) { number_equations(list_fixed_nodes, list_slave_nodes, list_immobile_components); } void SaturatedDiffusion::number_equations( std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components ) { m_ideq.resizeLike(m_variables->displacement()); m_ideq.setZero(); // flag fixed nodes for (index_t node: list_fixed_nodes) { for (index_t component=2; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(node, component)) = no_equation; } } // flag slaves nodes // we flag them by making their ideq more negative than no_equation for (auto slave_pair: list_slave_nodes) { for (index_t component=2; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(slave_pair.first, component)) = no_equation-1; } } // set equation numbers index_t neq = 0; for (index_t node=0; nodenb_nodes(); ++node) { for (index_t component: list_immobile_components) { m_fixed_components[component] = true; if (component < 2) m_ideq(m_variables->dof_aqueous_concentration(node, component)) = no_equation; } for (index_t component=0; componentnb_component(); ++component) { const index_t dof = m_variables->dof_aqueous_concentration(node, component); if (m_ideq(dof) > no_equation) // attribute an equation number if it is NOT a slave nor a fixed node { m_ideq(dof) = neq; ++neq; } m_ideq(m_variables->dof_solid_concentration(node, component)) = no_equation; } } // slave nodes // attribute the correct equation number for (auto slave_pair: list_slave_nodes) { for (index_t component=2; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(slave_pair.first, component)) = m_ideq(m_variables->dof_aqueous_concentration(slave_pair.second, component)); } } m_neq = neq; } void SaturatedDiffusion::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual, bool use_chemistry_rate ) { residual = Vector::Zero(get_neq()); m_is_in_residual_computation = true; for (index_t element: m_mesh->range_elements()) { for (index_t component=2; componentnb_component(); ++component) { Eigen::Vector2d element_residual; element_residual.setZero(); residuals_element_component(element, component, displacement, velocity, element_residual, use_chemistry_rate); for (index_t en=0; en<2; ++en) { const index_t node = m_mesh->get_node(element, en); const index_t id = m_ideq(m_variables->dof_aqueous_concentration(node, component)); if (id != no_equation) {residual(id) += element_residual(en);} } } } m_is_in_residual_computation = false; } void SaturatedDiffusion::residuals_element_component( index_t element, index_t component, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); const index_t dof_0 = m_variables->dof_aqueous_concentration(node_0, component); const index_t dof_1 = m_variables->dof_aqueous_concentration(node_1, component); const scalar_t velocity_0 = mass_coeff_0*(velocity(dof_0)*m_variables->porosity(node_0) +m_variables->vel_porosity(node_0)*displacement(dof_0)); const scalar_t velocity_1 = mass_coeff_1*(velocity(dof_1)*m_variables->porosity(node_1) + m_variables->vel_porosity(node_1)*displacement(dof_1)); scalar_t transport_0 = 0.0; scalar_t transport_1 = 0.0; if (not m_fixed_components[component]) { // transport scalar_t diff_coeff = 1.0/(0.5/m_variables->diffusion_coefficient(node_0) + 0.5/m_variables->diffusion_coefficient(node_1)); scalar_t flux_coeff = -( m_mesh->get_face_area(element) / m_mesh->get_dx(element) * diff_coeff ); // diffusion scalar_t flux_diffusion = flux_coeff*(displacement(dof_0) - displacement(dof_1)); transport_0 = flux_diffusion; transport_1 = - flux_diffusion; // advection if (m_variables->fluid_velocity(element) != 0.0) { scalar_t flux_advection = (m_mesh->get_face_area(element)) *m_variables->fluid_velocity(element); if (m_variables->fluid_velocity(element) > 0) { flux_advection *= (displacement(dof_0) - displacement(dof_1)); transport_1 += flux_advection; } else { flux_advection *= (displacement(dof_1) - displacement(dof_0)); transport_0 -= flux_advection; } } if (m_is_in_residual_computation) { m_variables->aqueous_concentration(node_0, component, m_variables->transport_rate()) += transport_0; m_variables->aqueous_concentration(node_1, component, m_variables->transport_rate()) += transport_1; } } if (use_chemistry_rate) { const scalar_t chemistry_0 = mass_coeff_0*( - m_variables->solid_concentration(node_0, component, m_variables->chemistry_rate()) + m_variables->aqueous_concentration(node_0, component, m_variables->chemistry_rate()) ); const scalar_t chemistry_1 = mass_coeff_1*( - m_variables->solid_concentration(node_1, component, m_variables->chemistry_rate()) + m_variables->aqueous_concentration(node_1, component, m_variables->chemistry_rate()) ); element_residual(0) = + transport_0 + chemistry_0 - velocity_0; element_residual(1) = + transport_1 + chemistry_1 - velocity_1; } else { element_residual(0) = + transport_0 - velocity_0; element_residual(1) = + transport_1 - velocity_1; } } void SaturatedDiffusion::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { dfpm::list_triplet_t jacob; const index_t ncomp = m_variables->nb_component(); const index_t estimation = m_mesh->nb_nodes()*(ncomp*m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { jacobian_element(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); } void SaturatedDiffusion::jacobian_element( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt) { for (index_t component=2; componentnb_component(); ++component) { Eigen::Vector2d element_residual_orig(Eigen::Vector2d::Zero()); // note : jacobian computation do not need to use the chemistry rate residuals_element_component(element, component, displacement, velocity, element_residual_orig, NO_CHEMISTRY_RATE); for (index_t en=0; en<2; ++en) { Eigen::Vector2d element_residual; const index_t node = m_mesh->get_node(element, en); const index_t dof = m_variables->dof_aqueous_concentration(node, component); const index_t idc = m_ideq(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-4*eps_jacobian) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; element_residual.setZero(); residuals_element_component(element, component, displacement, velocity, element_residual, NO_CHEMISTRY_RATE); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr=0; enr<2; ++enr) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = m_ideq(m_variables->dof_aqueous_concentration(noder, component)); if (idr == no_equation) continue; jacobian.push_back(dfpm::triplet_t( idr, idc, (element_residual(enr) - element_residual_orig(enr))/h )); } } } } //! \brief Update the solutions void SaturatedDiffusion::update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity) { for (index_t node: m_mesh->range_nodes()) { for (index_t component=2; component< m_variables->nb_component(); ++component) { const index_t dof = m_variables->dof_aqueous_concentration(node, component); const index_t id = m_ideq(dof); if (id == no_equation) continue; velocity(dof) += lambda*update(id); //displacement(dof) = predictor(dof) + alpha_dt*velocity(dof); } } //displacement = m_variables->predictor() + alpha_dt*velocity; displacement = predictor + alpha_dt*velocity; } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/transport_program.hpp b/src/reactmicp/systems/saturated_react/transport_program.hpp index 3a00589..2012c70 100644 --- a/src/reactmicp/systems/saturated_react/transport_program.hpp +++ b/src/reactmicp/systems/saturated_react/transport_program.hpp @@ -1,182 +1,184 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP #include "../../../dfpmsolver/parabolic_program.hpp" #include "variablesfwd.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "../../../dfpm/types.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { class SaturatedDiffusion: public dfpmsolver::ParabolicProgram { public: static constexpr bool NO_CHEMISTRY_RATE {false}; static constexpr bool CHEMISTRY_RATE {true}; SaturatedDiffusion(SaturatedVariables* variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components); SaturatedDiffusion(SaturatedVariables* variables, std::vector list_fixed_nodes); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return m_ndf;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Method to update the variables void set_variables(SaturatedVariables* variables) {m_variables = variables;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_ideq(id_dof);} //! \brief Compute the residuals //! //! \param displacement variables //! \param velocity time derivatives of the variables //! \param residual vector containing the residuals //! \param use_chemistry_rate if true compute residuals with chemistry rate void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual, bool use_chemistry_rate ); //! \brief Compute the residualts //! //! \param displacement variables //! \param velocity time derivatives of the variables //! \param residual vector containing the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ) { compute_residuals(displacement, velocity, residual, CHEMISTRY_RATE); } //! \brief Compute the residuals inside 'element' for 'component' void residuals_element_component( index_t element, index_t component, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); //! \brief Compute the residuals inside 'element' for 'component' void residuals_element_component( index_t element, index_t component, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual ) { residuals_element_component(element, component, displacement, velocity, element_residual, CHEMISTRY_RATE); } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); //! \brief Compute the contribution of 'element' in the jacobian void jacobian_element( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} private: // number the equations void number_equations(std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components ); index_t m_neq; index_t m_ndf; index_t m_tot_ndf; Eigen::Matrix m_ideq; mesh::Mesh1DPtr m_mesh; SaturatedVariables* m_variables; // don't own it, reset every timestep bool m_is_in_residual_computation; std::vector m_fixed_components; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP diff --git a/src/reactmicp/systems/saturated_react/transport_stagger.cpp b/src/reactmicp/systems/saturated_react/transport_stagger.cpp index 1b8a6be..7f27a25 100644 --- a/src/reactmicp/systems/saturated_react/transport_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/transport_stagger.cpp @@ -1,259 +1,261 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "transport_stagger.hpp" #include "variables.hpp" #include "../../solver/staggers_base/stagger_structs.hpp" #include "transport_program.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" #include "../../../utils/compat.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { // Declaration of the implementation of the stagger struct SaturatedTransportStagger::SaturatedTransportStaggerImpl { scalar_t m_dt {-1}; scalar_t m_residual_0 {-1}; SaturatedDiffusion m_program; dfpmsolver::ParabolicDriver m_solver; SaturatedTransportStaggerImpl(SaturatedVariables* variables, std::vector& list_fixed_nodes): m_program(variables, list_fixed_nodes), m_solver(m_program) {} SaturatedTransportStaggerImpl( SaturatedVariables* variables, std::vector& list_fixed_nodes, std::map& list_slave_nodes, std::vector& list_immobile_components): m_program(variables, list_fixed_nodes, list_slave_nodes, list_immobile_components), m_solver(m_program) {} void initialize_timestep( scalar_t dt, SaturatedVariables * const variables ); solver::StaggerReturnCode restart_timestep( SaturatedVariables * const variables ); scalar_t get_residual( SaturatedVariables * const var ); scalar_t get_residual_0() {return m_residual_0;} dfpmsolver::ParabolicDriverOptions& get_options() { return m_solver.get_options(); } //! \brief Translate a ParabolicDriverReturnCode to a StaggerReturnCode static solver::StaggerReturnCode parabolic2StaggerReturnCode( dfpmsolver::ParabolicDriverReturnCode retcode); }; SaturatedTransportStagger::SaturatedTransportStagger( SaturatedVariablesPtr variables, std::vector list_fixed_nodes ): m_impl(make_unique( variables.get(), list_fixed_nodes) ) { } SaturatedTransportStagger::SaturatedTransportStagger( SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components): m_impl(make_unique( variables.get(), list_fixed_nodes, list_slave_nodes, list_immobile_components) ) { } SaturatedTransportStagger::~SaturatedTransportStagger() = default; using VarConstPtr = SaturatedVariables * const; //! \brief Initialize the stagger at the beginning of an iteration void SaturatedTransportStagger::initialize_timestep( scalar_t dt, VariablesBase * const var ) { VarConstPtr true_var = static_cast(var); m_impl->initialize_timestep(dt, true_var); } //! \brief Solve the equation for the timestep solver::StaggerReturnCode SaturatedTransportStagger::restart_timestep(VariablesBase* var) { SaturatedVariables* true_var = static_cast(var); return m_impl->restart_timestep(true_var); } scalar_t SaturatedTransportStagger::get_update(VariablesBase * const var) { return static_cast(var)->velocity().norm(); } //! \brief Compute the residuals norm scalar_t SaturatedTransportStagger::get_residual(VariablesBase * const var) { VarConstPtr true_var = static_cast(var); return m_impl->get_residual(true_var); } scalar_t SaturatedTransportStagger::get_residual_0(VariablesBase * const _) { return m_impl->get_residual_0(); } dfpmsolver::ParabolicDriverOptions& SaturatedTransportStagger::options_solver() { return m_impl->get_options(); } // ################ // // // // Implementation // // // // ############### // void SaturatedTransportStagger::SaturatedTransportStaggerImpl::initialize_timestep( scalar_t dt, SaturatedVariables * const var ) { m_dt = dt; // Set the predictor var->predictor() = var->displacement(); // Reset the values var->velocity().setZero(); var->transport_rate().setZero(); m_program.set_variables(var); // Initialize the DFPM solver m_solver.initialize_timestep(dt, var->displacement()); // Compute the initial residual without external rate : Eigen::VectorXd residuals; m_program.compute_residuals(var->displacement(), var->velocity(), residuals, m_program.NO_CHEMISTRY_RATE); m_residual_0 = residuals.norm(); } //! \brief Solve the equation for the timestep solver::StaggerReturnCode SaturatedTransportStagger::SaturatedTransportStaggerImpl::restart_timestep( SaturatedVariables * const var ) { m_solver.velocity() = var->velocity(); dfpmsolver::ParabolicDriverReturnCode retcode = m_solver.restart_timestep(var->displacement()); // copy variables if successful if (retcode > dfpmsolver::ParabolicDriverReturnCode::NotConvergedYet) { var->velocity() = m_solver.velocity(); } return parabolic2StaggerReturnCode(retcode); } scalar_t SaturatedTransportStagger::SaturatedTransportStaggerImpl::get_residual( SaturatedVariables * const var ) { Eigen::VectorXd residuals; m_program.compute_residuals(var->displacement(), var->velocity(), residuals); return residuals.norm(); } //! \brief Translate a ParabolicDriverReturnCode to a StaggerReturnCode solver::StaggerReturnCode SaturatedTransportStagger::SaturatedTransportStaggerImpl::parabolic2StaggerReturnCode( dfpmsolver::ParabolicDriverReturnCode retcode ) { using ParRC = dfpmsolver::ParabolicDriverReturnCode; using StaRC = solver::StaggerReturnCode; switch (retcode) { case ParRC::ResidualMinimized: return StaRC::ResidualMinimized; break; case ParRC::ErrorMinimized: return StaRC::ErrorMinimized; break; default: // error switch(retcode) { case ParRC::MaxIterations: return StaRC::MaximumIterationsReached; break; case ParRC::StationaryPoint: return StaRC::StationaryPoint; break; case ParRC::NotConvergedYet: return StaRC::NotConvergedYet; break; default: return StaRC::UnknownError; } } } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/transport_stagger.hpp b/src/reactmicp/systems/saturated_react/transport_stagger.hpp index 6a6c461..9140212 100644 --- a/src/reactmicp/systems/saturated_react/transport_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/transport_stagger.hpp @@ -1,93 +1,95 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP #include "variablesfwd.hpp" #include "../../solver/staggers_base/transport_stagger_base.hpp" #include "../../../dfpmsolver/parabolic_structs.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using VariablesBase = solver::VariablesBase; class SPECMICP_DLL_PUBLIC SaturatedTransportStagger: public solver::TransportStaggerBase { public: SaturatedTransportStagger(SaturatedVariablesPtr variables, std::vector list_fixed_nodes); SaturatedTransportStagger(SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components); ~SaturatedTransportStagger(); SaturatedTransportStagger& operator= (const SaturatedTransportStagger& other) = delete; SaturatedTransportStagger(const SaturatedTransportStagger& other) = delete; //! \brief Return the options of the solver dfpmsolver::ParabolicDriverOptions& options_solver(); //! \brief Initialize the stagger at the beginning of an iteration void initialize_timestep(scalar_t dt, VariablesBase * const var) override; //! \brief Solve the equation for the timestep solver::StaggerReturnCode restart_timestep(VariablesBase * const var) override; //! \brief Compute the residuals norm scalar_t get_residual(VariablesBase * const var) override; //! \brief Compute the residuals norm scalar_t get_residual_0(VariablesBase * const var) override; //! \brief Obtain the update scalar_t get_update(VariablesBase * const var) override; private: struct SaturatedTransportStaggerImpl; std::unique_ptr m_impl; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP diff --git a/src/reactmicp/systems/saturated_react/variables.cpp b/src/reactmicp/systems/saturated_react/variables.cpp index d849e8f..d5bef09 100644 --- a/src/reactmicp/systems/saturated_react/variables.cpp +++ b/src/reactmicp/systems/saturated_react/variables.cpp @@ -1,67 +1,69 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "variables.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { SaturatedVariables::SaturatedVariables(mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database): m_mesh(the_mesh), m_database(the_database) { reset_main_variables(); } Vector SaturatedVariables::total_concentrations(index_t node) { Vector total_conc = porosity(node)*displacement().segment(offset_aqueous_concentration(node), nb_component()) + displacement().segment(offset_solid_concentration(node), nb_component()); return total_conc; } void SaturatedVariables::reset_main_variables() { displacement() = predictor(); velocity().setZero(); transport_rate().setZero(); chemistry_rate().setZero(); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/variables.hpp b/src/reactmicp/systems/saturated_react/variables.hpp index 4c0772a..c0059a1 100644 --- a/src/reactmicp/systems/saturated_react/variables.hpp +++ b/src/reactmicp/systems/saturated_react/variables.hpp @@ -1,288 +1,290 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP #include "../../../types.hpp" #include "../../../database.hpp" #include "../../solver/staggers_base/variables_base.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution.hpp" #include // forward declaration // =================== #include "../../../dfpm/meshes/mesh1dfwd.hpp" namespace specmicp { namespace reactmicp { namespace solver { using VariablesBasePtr = std::shared_ptr; } namespace systems { namespace satdiff { class SaturatedVariablesFactory; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp // Class declaration // ================= namespace specmicp { namespace reactmicp { //! \namespace specmicp::reactmicp::systems //! \brief The ReactMiCP systems //! //! Define the different built-in systems that can be use with ReactMiCP namespace systems { //! \namespace specmicp::reactmicp::systems::satdiff //! \brief Saturated diffusion/advection ReactMiCP system //! //! This system define the staggers needed to solve saturated reactive transport problem namespace satdiff { //! \brief Base class for the kinetic variables class KineticSaturatedVariablesBase { }; //! \brief The kinetic variables are using KineticSaturatedVariablesBasePtr = std::shared_ptr; class DummyKineticSaturatedVariables: public KineticSaturatedVariablesBase {}; //! \brief Variables for the saturated reactive transport system //! //! Contain all the variables that need to be shared between the staggers class SPECMICP_DLL_PUBLIC SaturatedVariables: public solver::VariablesBase { // SaturatedVariablesFactory should be the class to use to inialize // the variables correctly friend class SaturatedVariablesFactory; public: SaturatedVariables(mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database); //! \brief Return the mesh mesh::Mesh1DPtr get_mesh() {return m_mesh;} //! \brief Return the database RawDatabasePtr& get_database() {return m_database;} //! \brief Return the number of components index_t nb_component() {return m_database->nb_component();} //! \brief Return the number of nodes index_t nb_nodes() {return m_is_fixed_composition.size();} //! \brief Return true if 'node' has a fixed composition index_t is_fixed_composition(index_t node) {return m_is_fixed_composition[node];} // Main variables // ============== //! \brief Return the main variable vector Vector& displacement() {return m_displacement;} //! \brief Return the main variable vector at the beginning of the timestep Vector& predictor() {return m_predictor;} //! \brief Return the velocity of the main variables Vector& velocity() {return m_velocity;} //! \brief Return the rate of change of the main variables due to the transport operator Vector& transport_rate() {return m_transport_rate;} //! \brief Return the rate of change of the main variables due to the chemistry operator Vector& chemistry_rate() {return m_chemistry_rate;} // Access to main variables // ======================== //! \brief Return the number of degree of freedom (per node) in the main variables vector index_t ndf() {return 2*m_database->nb_component();} //! \brief Return the offset of 'node' in the main variables vector index_t offset_node(index_t node) {return node*ndf();} //! \brief Return the offset of the aqueous concentration variables in the main variables vector index_t offset_aqueous_concentration() {return 0;} //! \brief Return the offset of the aqueous concentrations variables in the main variables vector index_t offset_aqueous_concentration(index_t node) { return offset_aqueous_concentration()+offset_node(node);} //! \brief Return the offset of the solid concentration variables in the main variables vector index_t offset_solid_concentration() {return m_database->nb_component();} //! \brief Return the offset of the solid concentrations variables in the main variables vector index_t offset_solid_concentration(index_t node) { return offset_solid_concentration()+offset_node(node);} //! \brief Return the degree of freedom number for the aqueous concentration of 'component' at 'node' index_t dof_aqueous_concentration(index_t node, index_t component) { return (component + offset_aqueous_concentration(node)); } //! \brief Return the degree of freedom number for the solid concentration of 'component' at 'node' index_t dof_solid_concentration(index_t node, index_t component) { return (component + offset_solid_concentration(node)); } //! \brief Return the aqueous concentration of 'component' at 'node' in 'var' //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& aqueous_concentration(index_t node, index_t component, Vector& var) { return var(dof_aqueous_concentration(node, component)); } //! \brief Return the aqueous concentration of 'component' at 'node' in main variables //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& aqueous_concentration(index_t node, index_t component) { return m_displacement(dof_aqueous_concentration(node, component)); } //! \brief Return the solid concentration of 'component' at 'node' in 'var' //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& solid_concentration(index_t node, index_t component, Vector& var){ return var(dof_solid_concentration(node, component)); } //! \brief Return the solid concentration of 'component' at 'node' in main variables //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& solid_concentration(index_t node, index_t component){ return m_displacement(dof_solid_concentration(node, component)); } //! \brief Return a vector containing the total concentrations computed from the main variables //! //! This is to be used to restart the chemistry computation Vector total_concentrations(index_t node); // Equilibrium // =========== //! \brief Return the solution of the speciation solver at 'node' AdimensionalSystemSolution& equilibrium_solution(index_t node) { return m_equilibrium_solutions[node]; } //! \brief Return a reference to the equilibrium solutions solution const std::vector& equilibrium_solutions() { return m_equilibrium_solutions; } // Upscaling // ========= //! \brief Return the offset for 'node' in the upscaling variables vector index_t offset_node_upscaling(index_t node) {return ndf_upscaling()*node;} //! \brief Return the number fo degree of freedom (per node) for the upscaling vector index_t ndf_upscaling() {return 5;} //! \brief Return the degree of freedom for the porosity at 'node' index_t dof_porosity(index_t node) {return 0 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the porosity velocity at 'node' index_t dof_vel_porosity(index_t node) {return 1 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the diffusion coefficient at 'node' index_t dof_diffusion_coefficient(index_t node) {return 2 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the permeability at 'node' index_t dof_permeability(index_t node) {return 3 + offset_node_upscaling(node);} //! \brief Return the fluid velocity index_t dof_fluid_velocity(index_t node) {return 4 + offset_node_upscaling(node);} //! \brief Return the porosity at 'node' scalar_t& porosity(index_t node) {return m_upscaling(dof_porosity(node));} //! \brief Return the rate of change of the porosity at 'node' scalar_t& vel_porosity(index_t node) {return m_upscaling(dof_vel_porosity(node));} //! \brief Return the diffusion coefficient at 'node' scalar_t& diffusion_coefficient(index_t node) {return m_upscaling(dof_diffusion_coefficient(node));} //! \brief Return the permeability at 'node' scalar_t& permeability(index_t node) {return m_upscaling(dof_permeability(node));} //! \brief Return the fluid velocity at 'node' scalar_t& fluid_velocity(index_t node) {return m_upscaling(dof_fluid_velocity(node));} //! \brief Return the vector of upscaling variables Vector& upscaling_variables() {return m_upscaling;} KineticSaturatedVariablesBasePtr& kinetic_variables() {return m_kinetic_variables;} //! \brief Reset the main variables void reset_main_variables() override; private: // ############ // // Attributes // // ############ // mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; std::vector m_is_fixed_composition; // Main variables // ============== Vector m_displacement; Vector m_predictor; Vector m_velocity; Vector m_transport_rate; Vector m_chemistry_rate; // Equilibrium // =========== std::vector m_equilibrium_solutions; // Kinetic // ======= KineticSaturatedVariablesBasePtr m_kinetic_variables; // Upscaling // ========= Vector m_upscaling; }; //! \brief typedef of a shared pointer of a SaturatedVariables using SaturatedVariablesPtr = std::shared_ptr; // Casting function // ================= //! \brief Static cast to a SaturatedVariablesPtr inline SaturatedVariablesPtr cast_var_from_base(solver::VariablesBasePtr var) { return std::static_pointer_cast(var); } //! \brief Static cast from a SaturatedVariablesPtr inline solver::VariablesBasePtr cast_var_to_base(SaturatedVariablesPtr var) { return std::static_pointer_cast(var); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP diff --git a/src/reactmicp/systems/saturated_react/variablesfwd.hpp b/src/reactmicp/systems/saturated_react/variablesfwd.hpp index be33d62..316489d 100644 --- a/src/reactmicp/systems/saturated_react/variablesfwd.hpp +++ b/src/reactmicp/systems/saturated_react/variablesfwd.hpp @@ -1,57 +1,59 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { class SaturatedVariables; using SaturatedVariablesPtr = std::shared_ptr; //! \brief Base class for the kinetic variables class KineticSaturatedVariablesBase; //! \brief The kinetic variables are using KineticSaturatedVariablesBasePtr = std::shared_ptr; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP diff --git a/src/reactmicp/systems/unsaturated/aqueous_equation.cpp b/src/reactmicp/systems/unsaturated/aqueous_equation.cpp index 589dab9..a75f707 100644 --- a/src/reactmicp/systems/unsaturated/aqueous_equation.cpp +++ b/src/reactmicp/systems/unsaturated/aqueous_equation.cpp @@ -1,308 +1,310 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "aqueous_equation.hpp" #include "variables_box.hpp" #include "transport_constraints.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../utils/compat.hpp" #include "../../../physics/constants.hpp" #include "../../../physics/maths.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace dfpmsolver { // explicit template instanciation template class ParabolicDriver; } //end namespace dfpmsolver namespace reactmicp { namespace systems { namespace unsaturated { static constexpr index_t no_equation {-1}; static constexpr index_t no_eq_no_var {-2}; static constexpr index_t not_initialized {-5}; struct SPECMICP_DLL_LOCAL AqueousTransportEquation::AqueousTransportEquationImpl { mesh::Mesh1DPtr m_mesh; LiquidAqueousComponentVariableBox m_vars; std::vector m_ideq; mesh::Mesh1D* mesh() {return m_mesh.get();} LiquidAqueousComponentVariableBox& vars() {return m_vars;} bool node_has_equation(index_t node) { return m_ideq[node] > no_equation; } bool node_can_flux(index_t node) { return m_ideq[node] > no_eq_no_var; } index_t id_equation(index_t node) { return m_ideq[node]; } void fix_node(index_t node) { m_ideq[node] = no_equation; } void gas_node(index_t node) { m_ideq[node] = no_eq_no_var; } AqueousTransportEquationImpl( mesh::Mesh1DPtr the_mesh, LiquidAqueousComponentVariableBox the_vars ): m_mesh(the_mesh), m_vars(the_vars), m_ideq(the_mesh->nb_nodes(), not_initialized) {} void compute_transport_rate(scalar_t dt, const Vector& displacment); }; AqueousTransportEquation::AqueousTransportEquation( mesh::Mesh1DPtr the_mesh, LiquidAqueousComponentVariableBox& variables, const TransportConstraints& constraints): base(the_mesh->nb_nodes()), m_impl(make_unique(the_mesh, variables)) { number_equations(constraints); } AqueousTransportEquation::~AqueousTransportEquation() = default; index_t AqueousTransportEquation::id_equation_impl(index_t id_dof) { const auto id_eq = m_impl->id_equation(id_dof); return (id_eq>no_equation)?id_eq:no_equation; } mesh::Mesh1D* AqueousTransportEquation::get_mesh_impl() { return m_impl->mesh(); } void AqueousTransportEquation::pre_nodal_residual_hook_impl( index_t node, const Vector& displacement) {} void AqueousTransportEquation::pre_residual_hook_impl(const Vector& displacement) {} void AqueousTransportEquation::post_residual_hook_impl(const Vector& displacement) {} //! \brief Compute the residuals inside 'element' void AqueousTransportEquation::residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { element_residual.setZero(); mesh::Mesh1D* m_mesh = m_impl->mesh(); LiquidAqueousComponentVariableBox& vars = m_impl->m_vars; const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); scalar_t flux_0 = 0.0; scalar_t flux_1 = 0.0; if (m_impl->node_can_flux(node_0) and m_impl->node_can_flux(node_1)) { // Diffusion Cw const scalar_t coeff_diff_0 = vars.liquid_diffusivity(node_0) * vars.relative_liquid_diffusivity(node_0); const scalar_t coeff_diff_1 = vars.liquid_diffusivity(node_1) * vars.relative_liquid_diffusivity(node_1); const scalar_t coeff_diff = average( coeff_diff_0, coeff_diff_1); const scalar_t diff_aq = (displacement(node_1) - displacement(node_0) ); const scalar_t diff_flux = coeff_diff * diff_aq/ m_mesh->get_dx(element); // advection if (vars.advection_flux(element) < 0) { flux_0 = -vars.advection_flux(element)*diff_aq; } else if (vars.advection_flux(element) > 0) { flux_1 = -vars.advection_flux(element)*diff_aq; } flux_0 += diff_flux; flux_0 *= m_mesh->get_face_area(element); flux_1 -= diff_flux; flux_1 *= m_mesh->get_face_area(element); } // transient if (m_impl->node_has_equation(node_0)) { const scalar_t porosity_0 = vars.porosity(node_0); const scalar_t aq_tot_conc_0 = displacement(node_0); const scalar_t saturation_0 = vars.saturation(node_0); const scalar_t transient_0 = porosity_0 * aq_tot_conc_0 * vars.saturation.velocity(node_0) + saturation_0 * aq_tot_conc_0 * vars.porosity.velocity(node_0) + porosity_0 * saturation_0 * velocity(node_0); scalar_t res = mass_coeff_0*transient_0 - flux_0; if (use_chemistry_rate) { const scalar_t chemistry_0 = vars.aqueous_concentration.chemistry_rate(node_0) + vars.solid_concentration.chemistry_rate(node_0) + vars.partial_pressure.chemistry_rate(node_0); res -= mass_coeff_0*chemistry_0; } element_residual(0) = res/get_scaling(); } if (m_impl->node_has_equation(node_1)) { const scalar_t porosity_1 = vars.porosity(node_1); const scalar_t aq_tot_conc_1 = displacement(node_1); const scalar_t saturation_1 = vars.saturation(node_1); const scalar_t transient_1 = porosity_1 * aq_tot_conc_1 * vars.saturation.velocity(node_1) + saturation_1 * aq_tot_conc_1 * vars.porosity.velocity(node_1) + porosity_1 * saturation_1 * velocity(node_1); scalar_t res = mass_coeff_1*transient_1 - flux_1; if (use_chemistry_rate) { const scalar_t chemistry_1 = vars.aqueous_concentration.chemistry_rate(node_1) + vars.solid_concentration.chemistry_rate(node_1) + vars.partial_pressure.chemistry_rate(node_1); res -= mass_coeff_1*chemistry_1; } element_residual(1) = res/get_scaling(); } } void AqueousTransportEquation::number_equations(const TransportConstraints& constraints) { for (int fixed_node: constraints.fixed_nodes()) { m_impl->fix_node(fixed_node); } for (int gas_node: constraints.gas_nodes()) { m_impl->gas_node(gas_node); } index_t neq = 0; for (index_t node: m_impl->mesh()->range_nodes()) { if (m_impl->m_ideq[node] == not_initialized) { m_impl->m_ideq[node] = neq; ++neq; } } register_number_equations(neq); } void AqueousTransportEquation::compute_transport_rate( scalar_t dt, const Vector& displacement ) { m_impl->compute_transport_rate(dt, displacement); } void AqueousTransportEquation::AqueousTransportEquationImpl::compute_transport_rate( scalar_t dt, const Vector& displacement) { MainVariable& aqueous_concentration = m_vars.aqueous_concentration; const MainVariable& saturation = m_vars.saturation; const MainVariable& solid_conc = m_vars.solid_concentration; const MainVariable& pressure = m_vars.partial_pressure; const SecondaryTransientVariable& porosity = m_vars.porosity; for (index_t node: m_mesh->range_nodes()) { if (! node_has_equation(node)) continue; const scalar_t transient = ( ( porosity(node) * saturation(node) * displacement(node)) - ( porosity.predictor(node) * aqueous_concentration.predictor(node) * saturation.predictor(node)) ) / dt; const scalar_t chem_rates = ( saturation.chemistry_rate(node) + solid_conc.chemistry_rate(node) + pressure.chemistry_rate(node) ); aqueous_concentration.transport_fluxes(node) = transient - chem_rates; } } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/aqueous_equation.hpp b/src/reactmicp/systems/unsaturated/aqueous_equation.hpp index 0b01fc5..d584db7 100644 --- a/src/reactmicp/systems/unsaturated/aqueous_equation.hpp +++ b/src/reactmicp/systems/unsaturated/aqueous_equation.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_AQUEOUSEQUATION_HPP #define SPECMICP_REACTMICP_UNSATURATED_AQUEOUSEQUATION_HPP //! \file unsaturated/aqueous_equation.hpp //! \brief The equation for the liquid transport of aqueous component #include "../../../types.hpp" #include "fv_1dof_equation.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "variables.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class TransportConstraints; //! \brief Equation for liquid transport of aqueous component class SPECMICP_DLL_LOCAL AqueousTransportEquation: public FV1DOFEquation { using base = FV1DOFEquation; using base::get_scaling; using base::register_number_equations; public: AqueousTransportEquation( mesh::Mesh1DPtr the_mesh, LiquidAqueousComponentVariableBox& variables, const TransportConstraints& constraints); ~AqueousTransportEquation(); //! \brief Compute the residuals inside 'element' void residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); index_t id_equation_impl(index_t id_dof); mesh::Mesh1D* get_mesh_impl(); void pre_nodal_residual_hook_impl(index_t node, const Vector& displacement); void pre_residual_hook_impl(const Vector& displacement); void post_residual_hook_impl(const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); private: void number_equations(const TransportConstraints& constraints); struct AqueousTransportEquationImpl; std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_AQUEOUSEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.cpp b/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.cpp index eab6764..f4f3a41 100644 --- a/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.cpp +++ b/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.cpp @@ -1,323 +1,325 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "aqueous_pressure_equation.hpp" #include "variables_box.hpp" #include "transport_constraints.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../utils/compat.hpp" #include "../../../physics/constants.hpp" #include "../../../physics/maths.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace dfpmsolver { // explicit template instanciation template class ParabolicDriver; } //end namespace dfpmsolver namespace reactmicp { namespace systems { namespace unsaturated { static constexpr index_t no_equation {-1}; static constexpr index_t no_eq_no_var {-2}; static constexpr index_t not_initialized {-5}; struct SPECMICP_DLL_LOCAL AqueousGasTransportEquation::AqueousGasTransportEquationImpl { mesh::Mesh1DPtr m_mesh; LiquidGasAqueousVariableBox m_vars; std::vector m_ideq; mesh::Mesh1D* mesh() {return m_mesh.get();} LiquidAqueousComponentVariableBox& vars() {return m_vars;} bool node_has_equation(index_t node) { return m_ideq[node] > no_equation; } bool node_can_flux(index_t node) { return m_ideq[node] > no_eq_no_var; } index_t id_equation(index_t node) { return m_ideq[node]; } void fix_node(index_t node) { m_ideq[node] = no_equation; } void gas_node(index_t node) { m_ideq[node] = no_eq_no_var; } AqueousGasTransportEquationImpl( mesh::Mesh1DPtr the_mesh, LiquidGasAqueousVariableBox the_vars ): m_mesh(the_mesh), m_vars(the_vars), m_ideq(the_mesh->nb_nodes(), not_initialized) {} void compute_transport_rate(scalar_t dt, const Vector& displacment); }; AqueousGasTransportEquation::AqueousGasTransportEquation(mesh::Mesh1DPtr the_mesh, LiquidGasAqueousVariableBox& variables, const TransportConstraints& constraints): base(the_mesh->nb_nodes()), m_impl(make_unique(the_mesh, variables)) { number_equations(constraints); } AqueousGasTransportEquation::~AqueousGasTransportEquation() = default; index_t AqueousGasTransportEquation::id_equation_impl(index_t id_dof) { const auto id_eq = m_impl->id_equation(id_dof); return (id_eq>no_equation)?id_eq:no_equation; } mesh::Mesh1D* AqueousGasTransportEquation::get_mesh_impl() { return m_impl->mesh(); } void AqueousGasTransportEquation::pre_nodal_residual_hook_impl( index_t node, const Vector& displacement) {} void AqueousGasTransportEquation::pre_residual_hook_impl(const Vector& displacement) {} void AqueousGasTransportEquation::post_residual_hook_impl(const Vector& displacement) {} //! \brief Compute the residuals inside 'element' void AqueousGasTransportEquation::residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { element_residual.setZero(); mesh::Mesh1D* m_mesh = m_impl->mesh(); LiquidGasAqueousVariableBox& vars = m_impl->m_vars; const scalar_t& rt = vars.constants.rt; const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); scalar_t flux_0 = 0.0; scalar_t flux_1 = 0.0; if (m_impl->node_can_flux(node_0) and m_impl->node_can_flux(node_1)) { // Diffusion Cw const scalar_t coeff_diff_0 = vars.liquid_diffusivity(node_0) * vars.relative_liquid_diffusivity(node_0); const scalar_t coeff_diff_1 = vars.liquid_diffusivity(node_1) * vars.relative_liquid_diffusivity(node_1); const scalar_t coeff_diff = average( coeff_diff_0, coeff_diff_1); const scalar_t diff_aq = (displacement(node_1) - displacement(node_0) ); const scalar_t diff_flux = coeff_diff * diff_aq/ m_mesh->get_dx(element); // advection if (vars.advection_flux(element) < 0) { flux_0 = -vars.advection_flux(element)*diff_aq; } else if (vars.advection_flux(element) > 0) { flux_1 = -vars.advection_flux(element)*diff_aq; } flux_0 += diff_flux; flux_1 -= diff_flux; } const scalar_t coeff_diff_gas_0 = vars.resistance_gas_diffusivity(node_0) * vars.relative_gas_diffusivity(node_0); const scalar_t coeff_diff_gas_1 = vars.resistance_gas_diffusivity(node_1) * vars.relative_gas_diffusivity(node_1); const scalar_t coeff_diff_gas = vars.binary_diffusion_coefficient * average(coeff_diff_gas_0, coeff_diff_gas_1); const scalar_t diff_flux_gas = coeff_diff_gas*( vars.partial_pressure(node_1) - vars.partial_pressure(node_0)) / m_mesh->get_dx(element) / rt; flux_0 += diff_flux_gas; flux_0 *= m_mesh->get_face_area(element); flux_1 -= diff_flux_gas; flux_1 *= m_mesh->get_face_area(element); // transient if (m_impl->node_has_equation(node_0)) { const scalar_t porosity_0 = vars.porosity(node_0); const scalar_t aq_tot_conc_0 = displacement(node_0); const scalar_t saturation_0 = vars.saturation(node_0); const scalar_t transient_0 = porosity_0 * aq_tot_conc_0 * vars.saturation.velocity(node_0) + saturation_0 * aq_tot_conc_0 * vars.porosity.velocity(node_0) + porosity_0 * saturation_0 * velocity(node_0); scalar_t res = mass_coeff_0*transient_0 - flux_0; if (use_chemistry_rate) { const scalar_t chemistry_0 = vars.aqueous_concentration.chemistry_rate(node_0) + vars.solid_concentration.chemistry_rate(node_0) + vars.partial_pressure.chemistry_rate(node_0); res -= mass_coeff_0*chemistry_0; } element_residual(0) = res/get_scaling(); } if (m_impl->node_has_equation(node_1)) { const scalar_t porosity_1 = vars.porosity(node_1); const scalar_t aq_tot_conc_1 = displacement(node_1); const scalar_t saturation_1 = vars.saturation(node_1); const scalar_t transient_1 = porosity_1 * aq_tot_conc_1 * vars.saturation.velocity(node_1) + saturation_1 * aq_tot_conc_1 * vars.porosity.velocity(node_1) + porosity_1 * saturation_1 * velocity(node_1); scalar_t res = mass_coeff_1*transient_1 - flux_1; if (use_chemistry_rate) { const scalar_t chemistry_1 = vars.aqueous_concentration.chemistry_rate(node_1) + vars.solid_concentration.chemistry_rate(node_1) + vars.partial_pressure.chemistry_rate(node_1); res -= mass_coeff_1*chemistry_1; } element_residual(1) = res/get_scaling(); } } void AqueousGasTransportEquation::number_equations(const TransportConstraints& constraints) { for (int fixed_node: constraints.fixed_nodes()) { m_impl->fix_node(fixed_node); } for (int gas_node: constraints.gas_nodes()) { m_impl->gas_node(gas_node); } index_t neq = 0; for (index_t node: m_impl->mesh()->range_nodes()) { if (m_impl->m_ideq[node] == not_initialized) { m_impl->m_ideq[node] = neq; ++neq; } } register_number_equations(neq); } void AqueousGasTransportEquation::compute_transport_rate( scalar_t dt, const Vector& displacement ) { m_impl->compute_transport_rate(dt, displacement); } void AqueousGasTransportEquation::AqueousGasTransportEquationImpl::compute_transport_rate( scalar_t dt, const Vector& displacement) { MainVariable& aqueous_concentration = m_vars.aqueous_concentration; const MainVariable& saturation = m_vars.saturation; const MainVariable& solid_conc = m_vars.solid_concentration; const MainVariable& pressure = m_vars.partial_pressure; const SecondaryTransientVariable& porosity = m_vars.porosity; for (index_t node: m_mesh->range_nodes()) { if (! node_has_equation(node)) continue; const scalar_t transient = ( ( porosity(node) * saturation(node) * displacement(node)) - ( porosity.predictor(node) * aqueous_concentration.predictor(node) * saturation.predictor(node)) ) / dt; const scalar_t chem_rates = ( saturation.chemistry_rate(node) + solid_conc.chemistry_rate(node) + pressure.chemistry_rate(node) ); aqueous_concentration.transport_fluxes(node) = transient - chem_rates; } } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.hpp b/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.hpp index f653ca4..6977eb6 100644 --- a/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.hpp +++ b/src/reactmicp/systems/unsaturated/aqueous_pressure_equation.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_AQUEOUSPRESSUREEQUATION_HPP #define SPECMICP_REACTMICP_UNSATURATED_AQUEOUSPRESSUREEQUATION_HPP //! \file unsaturated/aqueous_pressure_equation.hpp //! \brief The equation for the liquid and gas transport of aqueous component #include "../../../types.hpp" #include "fv_1dof_equation.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "variables.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class TransportConstraints; //! \brief Equation for liquid transport of aqueous component class SPECMICP_DLL_LOCAL AqueousGasTransportEquation: public FV1DOFEquation { using base = FV1DOFEquation; using base::get_scaling; using base::register_number_equations; public: AqueousGasTransportEquation( mesh::Mesh1DPtr the_mesh, LiquidGasAqueousVariableBox& variables, const TransportConstraints& constraints); ~AqueousGasTransportEquation(); //! \brief Compute the residuals inside 'element' void residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); index_t id_equation_impl(index_t id_dof); mesh::Mesh1D* get_mesh_impl(); void pre_nodal_residual_hook_impl(index_t node, const Vector& displacement); void pre_residual_hook_impl(const Vector& displacement); void post_residual_hook_impl(const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); private: void number_equations(const TransportConstraints& constraints); struct AqueousGasTransportEquationImpl; std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_AQUEOUSPRESSUREEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/equilibrium_constraints.cpp b/src/reactmicp/systems/unsaturated/equilibrium_constraints.cpp index b4aebf3..1aff632 100644 --- a/src/reactmicp/systems/unsaturated/equilibrium_constraints.cpp +++ b/src/reactmicp/systems/unsaturated/equilibrium_constraints.cpp @@ -1,216 +1,218 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "equilibrium_constraints.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "../../../utils/compat.hpp" #include "../../../utils/log.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { struct EquilibriumConstraints::EquilibriumConstraintsImpl { EquilibriumConstraintsImpl(index_t nb_nodes): m_node_constraints(nb_nodes, no_equation), m_is_fixed_node(nb_nodes, false) { m_constraints.reserve(3); } EquilibriumConstraintsImpl(index_t nb_nodes, const AdimensionalSystemSolverOptions& opts): m_node_constraints(nb_nodes, no_equation), m_is_fixed_node(nb_nodes, false), m_options(opts) { m_constraints.reserve(3); } size_t last() {return m_constraints.size() - 1;} AdimensionalSystemSolverOptions& get_options() {return m_options;} std::vector m_constraints; std::vector m_node_constraints; std::vector m_is_fixed_node; void set_fixed_node(index_t node) { m_is_fixed_node[node] = true; } bool is_fixed_node(index_t node) { return m_is_fixed_node[node]; } index_t nb_nodes() {return m_is_fixed_node.size();} AdimensionalSystemSolverOptions m_options; }; EquilibriumConstraints::EquilibriumConstraints(index_t nb_nodes): m_impl(make_unique(nb_nodes)) {} EquilibriumConstraints::EquilibriumConstraints( index_t nb_nodes, const AdimensionalSystemSolverOptions& opts): m_impl(make_unique(nb_nodes, opts)) {} EquilibriumConstraints::~EquilibriumConstraints() = default; std::size_t EquilibriumConstraints::add_constraints( const AdimensionalSystemConstraints& constraints) { m_impl->m_constraints.push_back(constraints); return m_impl->last(); } std::size_t EquilibriumConstraints::new_constraints() { m_impl->m_constraints.emplace_back(); return m_impl->last(); } AdimensionalSystemConstraints& EquilibriumConstraints::operator[] (std::size_t index_constraint) { return m_impl->m_constraints[index_constraint]; } void EquilibriumConstraints::set_constraints( std::size_t id_constraint, const std::vector& nodes ) { specmicp_assert(id_constraint <= m_impl->last()); for (auto node: nodes) { m_impl->m_node_constraints[node] = id_constraint; } } void EquilibriumConstraints::set_constraints( const std::vector& constraints_for_each_node) { uindex_t nb_nodes = m_impl->m_node_constraints.size(); specmicp_assert(constraints_for_each_node.size() == nb_nodes); for (uindex_t node=0; node m_impl->last()) { ERROR << "Node " << node << " : " << "constraints #" << id << " does not exist."; throw std::runtime_error("Invalid constraint request"); } m_impl->m_node_constraints[node] = constraints_for_each_node[node]; } } void EquilibriumConstraints::set_constraint_for_all(std::size_t id_constraint) { if (id_constraint > m_impl->last()) { ERROR << "Constraints #" << id_constraint << " does not exist."; throw std::runtime_error("Invalid constraint request"); } for (uindex_t node=0; node < m_impl->m_node_constraints.size(); ++node) { m_impl->m_node_constraints[node] = id_constraint; } } AdimensionalSystemConstraints& EquilibriumConstraints::get_constraints(index_t node) { auto id = m_impl->m_node_constraints[node]; if (id == no_equation) { // check that the node has been initialized before doing anything ERROR << "Node " << node << " : " << "request for a non initialized constraints !"; throw std::runtime_error("Invalid constraint request."); } return m_impl->m_constraints[id]; } //! \brief Set the options AdimensionalSystemSolverOptions& EquilibriumConstraints::get_options() { return m_impl->get_options(); } //! \brief Add a fixed node void EquilibriumConstraints::add_fixed_node(index_t node) { specmicp_assert(node < m_impl->nb_nodes()); m_impl->set_fixed_node(node); } //! \brief Add a list of fixed nodes void EquilibriumConstraints::add_fixed_nodes(std::vector fixed_nodes) { for (auto node: fixed_nodes) { specmicp_assert(node < m_impl->nb_nodes()); m_impl->set_fixed_node(node); } } //! \brief Return true if the node is fixed bool EquilibriumConstraints::is_fixed_node(index_t node) { return m_impl->is_fixed_node(node); } std::shared_ptr equilibrium_constraints( mesh::Mesh1DPtr the_mesh ) { index_t nb_nodes = the_mesh->nb_nodes(); return std::make_shared(nb_nodes); } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/equilibrium_constraints.hpp b/src/reactmicp/systems/unsaturated/equilibrium_constraints.hpp index 27f74e2..b324a23 100644 --- a/src/reactmicp/systems/unsaturated/equilibrium_constraints.hpp +++ b/src/reactmicp/systems/unsaturated/equilibrium_constraints.hpp @@ -1,142 +1,144 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRUMCONSTRAINTS_HPP #define SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRUMCONSTRAINTS_HPP #include "../../../types.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include namespace specmicp { struct AdimensionalSystemConstraints; struct AdimensionalSystemSolverOptions; namespace reactmicp { namespace systems { namespace unsaturated { //! \brief Constraints for the equilibrium stagger class SPECMICP_DLL_PUBLIC EquilibriumConstraints { public: //! \brief Build a new set of constraints EquilibriumConstraints(index_t nb_nodes); //! \brief Build a new set of constraints EquilibriumConstraints(index_t nb_nodes, const AdimensionalSystemSolverOptions& opts); ~EquilibriumConstraints(); //! \brief Add a new constraints to the set of constraints //! //! \param constraints A set of constraints //! \return the index of the set of constraints //! //! \sa new_constraints std::size_t add_constraints( const AdimensionalSystemConstraints& constraints); //! \brief Add a new default constraint to the system //! //! \return the index of the set of constraints //! //! The constraints can be obtained through operator[] //! //! Ex : //! //! EquilibriumConstraints constraints(10); //! auto id = constraints.new_constraints(); //! auto& constraint_to_modify = constraints[]; //! // to stuff to constraint_to_modify //! std::size_t new_constraints(); //! \brief Return the constraint with index 'index_constraint' //! //! \param index_constraint is the index return by add_constraints, //! or new_constraints AdimensionalSystemConstraints& operator[] (std::size_t index_constraint); //! \brief Set the constraint to be 'id_constraint' for each node in 'nodes' void set_constraints( std::size_t id_constraint, const std::vector& nodes ); //! \brief Set constraints for each node //! //! \param constraints_for_each_node Vector containing the index of the //! constraint for each node void set_constraints( const std::vector& constraints_for_each_node); //! \brief Set the constraint for all node void set_constraint_for_all(std::size_t id_constraint); //! \brief Return the constraint for node (node) AdimensionalSystemConstraints& get_constraints(index_t node); //! \brief Add a fixed node void add_fixed_node(index_t node); //! \brief Add a list of fixed nodes void add_fixed_nodes(std::vector fixed_nodes); //! \brief Return true if the node is fixed bool is_fixed_node(index_t node); //! \brief Set the options AdimensionalSystemSolverOptions& get_options(); private: struct EquilibriumConstraintsImpl; std::unique_ptr m_impl; }; //! \brief Return a constraint container for the EquilibriumStagger std::shared_ptr equilibrium_constraints( mesh::Mesh1DPtr the_mesh ); } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRUMCONSTRAINTS_HPP diff --git a/src/reactmicp/systems/unsaturated/equilibrium_stagger.cpp b/src/reactmicp/systems/unsaturated/equilibrium_stagger.cpp index fda1604..c168a19 100644 --- a/src/reactmicp/systems/unsaturated/equilibrium_stagger.cpp +++ b/src/reactmicp/systems/unsaturated/equilibrium_stagger.cpp @@ -1,476 +1,478 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "equilibrium_stagger.hpp" #include "variables.hpp" #include "equilibrium_constraints.hpp" #include "../../solver/staggers_base/stagger_structs.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../database/data_container.hpp" #include "../../../utils/compat.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../../specmicp/adimensional/adimensional_system_solver.hpp" #include "../../../utils/log.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { // ============================================ // // Declaration of implementation details // // ============================================ struct EquilibriumStagger::EquilibriumStaggerImpl { scalar_t m_dt {-1}; mesh::Mesh1DPtr m_mesh; database::RawDatabasePtr m_database; std::shared_ptr m_constraints; EquilibriumStaggerImpl( std::shared_ptr variables, std::shared_ptr constraints ): m_mesh(variables->get_mesh()), m_database(variables->get_database()), m_constraints(constraints) {} scalar_t dt() {return m_dt;} int compute_one_node(index_t node, UnsaturatedVariables * const vars); void compute_total_concentrations( index_t node, Vector& total_concentrations, UnsaturatedVariables * const vars ); void analyse_solution( index_t node, AdimensionalSystemSolution& solution, UnsaturatedVariables * const vars ); void initialize_timestep_one_node(index_t node, UnsaturatedVariables* vars); void initialize(UnsaturatedVariables* vars); void initialize_timestep(scalar_t dt, UnsaturatedVariables* vars); StaggerReturnCode restart_timestep(UnsaturatedVariables* vars); units::UnitsSet& get_units() { return m_constraints->get_options().units_set; } }; using TrueConstPtr = UnsaturatedVariables * const; inline TrueConstPtr cast_to_var(solver::VariablesBase * const var) { return static_cast(var); } // ============================================ // // Implementation // // ============================================ EquilibriumStagger::EquilibriumStagger( std::shared_ptr variables, std::shared_ptr constraints ): m_impl(utils::make_pimpl(variables, constraints)) { } EquilibriumStagger::~EquilibriumStagger() = default; //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables void EquilibriumStagger::initialize(VariablesBase * const var) { TrueConstPtr true_vars = cast_to_var(var); m_impl->initialize(true_vars); } //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables void EquilibriumStagger::initialize_timestep( scalar_t dt, VariablesBase * const var ) { TrueConstPtr true_vars = cast_to_var(var); m_impl->initialize_timestep(dt, true_vars); } //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables EquilibriumStagger::StaggerReturnCode EquilibriumStagger::restart_timestep(VariablesBase * const var) { TrueConstPtr true_vars = cast_to_var(var); return m_impl->restart_timestep(true_vars); } int EquilibriumStagger::EquilibriumStaggerImpl::compute_one_node( index_t node, UnsaturatedVariables * const vars ) { AdimensionalSystemConstraints constraints = m_constraints->get_constraints(node); compute_total_concentrations(node, constraints.total_concentrations, vars); // set partial pressure model { user_model_saturation_f callable = vars->get_vapor_pressure_model(); water_partial_pressure_f pv_model = [callable, node](scalar_t sat){ return callable(node, sat); }; constraints.set_water_partial_pressure_model(pv_model); } // We use the current value of the saturation to avoid converging // to the previous solution // This is necessary because the update to the saturation is very small const AdimensionalSystemSolution& previous_solution = vars->get_adim_solution(node); Vector x; AdimensionalSystemSolver the_solver; if (likely(previous_solution.is_valid)) // should always be true { const auto porosity = vars->get_porosity()(node); const auto saturation = vars->get_liquid_saturation()(node); the_solver = AdimensionalSystemSolver( vars->get_database(), constraints, previous_solution, m_constraints->get_options() ); x = previous_solution.main_variables; // we use the new value of the saturation to avoid a change // to small to be detected by the speciaion solver x(0) = porosity*saturation; // x(0) = volume fraction water } else { const auto porosity = vars->get_porosity()(node); const auto saturation = vars->get_liquid_saturation()(node); the_solver = AdimensionalSystemSolver( vars->get_database(), constraints, m_constraints->get_options() ); the_solver.initialise_variables(x, porosity*saturation, -3); } // micpsolver::MiCPPerformance perf = the_solver.solve(x); if (perf.return_code < micpsolver::MiCPSolverReturnCode::Success) { ERROR << "Failed to solve equilibrium at node " << node << ". \n" << "Return code : " << (int) perf.return_code; return -1; } AdimensionalSystemSolution solution = the_solver.get_raw_solution(x); analyse_solution(node, solution, vars); vars->set_adim_solution(node, solution); return 0; } void EquilibriumStagger::EquilibriumStaggerImpl::compute_total_concentrations( index_t node, Vector& total_concentrations, UnsaturatedVariables * const vars ) { total_concentrations.resize(m_database->nb_component()); const scalar_t saturation = vars->get_liquid_saturation()(node); const scalar_t porosity = vars->get_porosity()(node); const scalar_t rt = vars->get_rt(); // water { const scalar_t ctilde_w = vars->get_water_aqueous_concentration()(node); const scalar_t cbar_w = vars->get_solid_concentration(0)(node); scalar_t c_w = saturation*porosity*ctilde_w + cbar_w; if (vars->component_has_gas(0)) { const scalar_t pv_w = vars->get_pressure_main_variables(0)(node); c_w += (1.0-saturation)*porosity*pv_w/rt; } total_concentrations(0) = c_w; } total_concentrations(1) = 0.0; // aqueous components for (index_t component: m_database->range_aqueous_component()) { const scalar_t ctilde_i = vars->get_aqueous_concentration(component)(node); const scalar_t cbar_i = vars->get_solid_concentration(component)(node); scalar_t c_i = saturation*porosity*ctilde_i + cbar_i; if (vars->component_has_gas(component)) { const scalar_t pv_i = vars->get_pressure_main_variables(component)(node); c_i += (1.0-saturation)*porosity*pv_i/rt; } total_concentrations(component) = c_i; } } void EquilibriumStagger::EquilibriumStaggerImpl::analyse_solution( index_t node, AdimensionalSystemSolution& solution, UnsaturatedVariables * const vars ) { AdimensionalSystemSolutionExtractor extr(solution, m_database, get_units()); const scalar_t saturation = extr.saturation_water(); const scalar_t sat_g = 1-saturation; const scalar_t rho_l = extr.density_water(); const scalar_t porosity = extr.porosity(); const scalar_t rt = vars->get_rt(); // porosity SecondaryTransientVariable& porosity_vars = vars->get_porosity(); const scalar_t porosity_0 = porosity_vars.predictor(node); const scalar_t porosity_vel = (porosity - porosity_0)/m_dt; porosity_vars.variable(node) = porosity; porosity_vars.velocity(node) = porosity_vel; // water // saturation MainVariable& satvars = vars->get_liquid_saturation(); const scalar_t saturation_0 = satvars.predictor(node); const scalar_t sat_vel = (saturation - saturation_0)/m_dt; satvars.variable(node) = saturation; satvars.velocity(node) = sat_vel; { // total aqueous concentration SecondaryTransientVariable& cwtilde_vars = vars->get_water_aqueous_concentration(); const scalar_t cwtilde = rho_l*extr.total_aqueous_concentration(0); const scalar_t cwtilde_0 = cwtilde_vars.predictor(node); const scalar_t cwtilde_vel = (cwtilde - cwtilde_0)/m_dt; cwtilde_vars.variable(node) = cwtilde; cwtilde_vars.velocity(node) = cwtilde_vel; // total solid concentration MainVariable& solid_vars = vars->get_solid_concentration(0); const scalar_t cwbar = extr.total_solid_concentration(0); const scalar_t cwbar_0 = solid_vars.predictor(node); const scalar_t cwbar_vel = (cwbar - cwbar_0)/m_dt; solid_vars.variable(node) = cwbar; solid_vars.velocity(node) = cwbar_vel; solid_vars.chemistry_rate(node) = - cwbar_vel; // vapor pressure if (vars->component_has_gas(0)) { MainVariable& pres_vars = vars->get_pressure_main_variables(0); const scalar_t pv = vars->get_vapor_pressure_model()(node, saturation); const scalar_t pv_0 = pres_vars.predictor(node); const scalar_t pv_vel = (pv - pv_0)/m_dt; pres_vars.variable(node) = pv; pres_vars.velocity(node) = pv_vel; const scalar_t transient = ( (pv*porosity*sat_g) - (pv_0*porosity_0*(1-saturation_0)) )/ (rt*m_dt); const scalar_t pv_chem_rate = - transient + pres_vars.transport_fluxes(node); pres_vars.chemistry_rate(node) = pv_chem_rate; } } // aqueous components for (index_t component: m_database->range_aqueous_component()) { // total aqueous concentration MainVariable& aqconc = vars->get_aqueous_concentration(component); const scalar_t ctildei = rho_l*extr.total_aqueous_concentration(component); const scalar_t ctildei_0 = aqconc.predictor(node); const scalar_t ctildei_vel = (ctildei - ctildei_0) / m_dt; aqconc.variable(node) = ctildei; aqconc.velocity(node) = ctildei_vel; // total solid concentration MainVariable& solconc = vars->get_solid_concentration(component); const scalar_t cbari = extr.total_solid_concentration(component); const scalar_t cbari_0 = solconc.predictor(node); const scalar_t cbari_vel = (cbari - cbari_0) / m_dt; solconc.variable(node) = cbari; solconc.velocity(node) = cbari_vel; solconc.chemistry_rate(node) = - cbari_vel; // partial pressure if (vars->component_has_gas(component)) { MainVariable& pres_vars = vars->get_pressure_main_variables(component); index_t id_g = vars->get_id_gas(component); const scalar_t pi = extr.fugacity_gas(id_g)*vars->get_total_pressure(); const scalar_t pi_0 = pres_vars.predictor(node); const scalar_t pi_vel = (pi - pi_0) / m_dt; pres_vars.variable(node) = pi; pres_vars.velocity(node) = pi_vel; const scalar_t transient = ( (pi*porosity*sat_g) - (pi_0*porosity_0*(1.0-saturation_0)) ) / (rt * m_dt); const scalar_t pi_chem_rate = - transient + pres_vars.transport_fluxes(node); pres_vars.chemistry_rate(node) = pi_chem_rate; } } } void EquilibriumStagger::EquilibriumStaggerImpl::initialize_timestep_one_node( index_t node, UnsaturatedVariables * const vars ) { SecondaryTransientVariable& porosity = vars->get_porosity(); porosity.predictor = porosity.variable; porosity.velocity.setZero(); } EquilibriumStagger::StaggerReturnCode EquilibriumStagger::EquilibriumStaggerImpl::restart_timestep( UnsaturatedVariables* vars ) { int sum_retcode = 0; #if SPECMICP_USE_OPENMP #pragma omp parallel for \ reduction(+: sum_retcode) #endif for (index_t node=0; nodenb_nodes(); ++node) { if (m_constraints->is_fixed_node(node)) continue; sum_retcode += compute_one_node(node, vars); } if (sum_retcode != 0) { return StaggerReturnCode::UnknownError; } return StaggerReturnCode::ResidualMinimized; } void EquilibriumStagger::EquilibriumStaggerImpl::initialize_timestep( scalar_t dt, UnsaturatedVariables* vars ) { m_dt = dt; // initialize //water { MainVariable& cbar_w = vars->get_solid_concentration(0); cbar_w.predictor = cbar_w.variable; cbar_w.velocity.setZero(); } // aqueous component for (index_t component: m_database->range_aqueous_component()) { MainVariable& cbar_i = vars->get_solid_concentration(component); cbar_i.predictor = cbar_i.variable; cbar_i.velocity.setZero(); } for (auto node: m_mesh->range_nodes()) { initialize_timestep_one_node(node, vars); } } void EquilibriumStagger::EquilibriumStaggerImpl::initialize( UnsaturatedVariables * const vars ) { // do nothing by default } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/equilibrium_stagger.hpp b/src/reactmicp/systems/unsaturated/equilibrium_stagger.hpp index 8251bb1..58e57c7 100644 --- a/src/reactmicp/systems/unsaturated/equilibrium_stagger.hpp +++ b/src/reactmicp/systems/unsaturated/equilibrium_stagger.hpp @@ -1,99 +1,101 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRIUMSTAGGER_HPP #define SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRIUMSTAGGER_HPP #include "../../solver/staggers_base/chemistry_stagger_base.hpp" #include "../../../utils/pimpl_ptr.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class EquilibriumConstraints; class UnsaturatedVariables; class SPECMICP_DLL_PUBLIC EquilibriumStagger: public solver::ChemistryStaggerBase { public: using StaggerReturnCode = solver::StaggerReturnCode; using VariablesBase = solver::VariablesBase; EquilibriumStagger( std::shared_ptr variables, std::shared_ptr constraints ); ~EquilibriumStagger(); //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables void initialize(VariablesBase * const var); //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables void initialize_timestep(scalar_t dt, VariablesBase * const var); //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables StaggerReturnCode restart_timestep(VariablesBase * const var); private: struct SPECMICP_DLL_LOCAL EquilibriumStaggerImpl; utils::pimpl_ptr m_impl; }; //! \brief Return an equilibrium stagger inline std::shared_ptr equilibrium_stagger( std::shared_ptr variables, std::shared_ptr constraints ) { return std::make_shared(variables, constraints); } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_EQUILIBRIUMSTAGGER_HPP diff --git a/src/reactmicp/systems/unsaturated/fv_1dof_equation.hpp b/src/reactmicp/systems/unsaturated/fv_1dof_equation.hpp index cd82920..0daf5d2 100644 --- a/src/reactmicp/systems/unsaturated/fv_1dof_equation.hpp +++ b/src/reactmicp/systems/unsaturated/fv_1dof_equation.hpp @@ -1,164 +1,166 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_FV1DDOFEQUATION_HPP #define SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_FV1DDOFEQUATION_HPP //! \file unsaturated/fv_1dof_equation.hpp //! \brief 1D finite volume equation, with 1 dof per node #include "../../../types.hpp" #include "../../../dfpmsolver/parabolic_program.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { //! \brief 1D finite volume equation, with 1DOF per node //! //! This is to be subclassed by the other equations template class FV1DOFEquation: public dfpmsolver::ParabolicProgram> { public: FV1DOFEquation(index_t nb_nodes): m_tot_ndf(nb_nodes) {} Derived* derived() {return static_cast(this);} //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return 1;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Return the id of equation dof index_t id_equation(index_t node) { return derived()->id_equation_impl(node); } mesh::Mesh1D* get_mesh() { return derived()->get_mesh_impl(); } void pre_nodal_residual_hook(index_t node, const Vector& displacement) { return derived()->pre_nodal_residual_hook_impl(node, displacement); } void pre_residual_hook(const Vector& displacement) { return derived()->pre_residual_hook_impl(displacement); } void post_residual_hook(const Vector& displacement) { return derived()->post_residual_hook_impl(displacement); } void residuals_element( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { derived()->residuals_element_impl( element, displacement, velocity, element_residual, use_chemistry_rate); } void residuals_element( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual ) { residuals_element( element, displacement, velocity, element_residual, true); } //! \brief Compute the residuals void compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residuals, bool use_chemistry_rate ); //! \brief Compute the residuals void compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residuals ) { compute_residuals(displacement, velocity, residuals, true); } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); //! \brief Update the solution void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); void set_scaling(scalar_t scaling_factor) {m_scaling = scaling_factor;} scalar_t get_scaling() {return m_scaling;} void register_number_equations(scalar_t neq) {m_neq = neq;} protected: scalar_t m_neq; scalar_t m_tot_ndf; scalar_t m_scaling {1.0}; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #include "fv_1dof_equation.inl" #endif // SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_FV1DDOFEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/fv_1dof_equation.inl b/src/reactmicp/systems/unsaturated/fv_1dof_equation.inl index 5c870b1..dfa310b 100644 --- a/src/reactmicp/systems/unsaturated/fv_1dof_equation.inl +++ b/src/reactmicp/systems/unsaturated/fv_1dof_equation.inl @@ -1,167 +1,169 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ //! \file unsaturated/fv_1dof_equation.inl //! \brief Implementation of 1dof equation for unsaturated system #include "fv_1dof_equation.hpp" // for syntaxing coloring parsing #include "../../../dfpm/types.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { template void FV1DOFEquation::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { mesh::Mesh1D* m_mesh = get_mesh(); dfpm::list_triplet_t jacob; const index_t estimation = 3*get_neq(); jacob.reserve(estimation); // assume relative variables are set for (index_t element: m_mesh->range_elements()) { Eigen::Vector2d element_residual_orig; residuals_element(element, displacement, velocity, element_residual_orig, false); for (index_t enodec=0; enodec<2; ++enodec) { const index_t nodec = m_mesh->get_node(element, enodec); if (not (id_equation(nodec) > no_equation)) continue; const scalar_t tmp_d = displacement(nodec); const scalar_t tmp_v = velocity(nodec); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h<1e-4*eps_jacobian) h = eps_jacobian; velocity(nodec) = tmp_v + h; h = velocity(nodec) - tmp_v; displacement(nodec) = tmp_d + alphadt*h; pre_nodal_residual_hook(nodec, displacement); Eigen::Vector2d element_residual; residuals_element(element, displacement, velocity, element_residual, false); displacement(nodec) = tmp_d; velocity(nodec) = tmp_v; pre_nodal_residual_hook(nodec, displacement); for (index_t enoder=0; enoder<2; ++enoder) { const index_t noder = m_mesh->get_node(element, enoder); if (not (id_equation(noder) > no_equation)) continue; jacob.push_back(dfpm::triplet_t( id_equation(noder), id_equation(nodec), (element_residual(enoder) - element_residual_orig(enoder))/h )); } } } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); } template void FV1DOFEquation::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residuals, bool use_chemistry_rate ) { mesh::Mesh1D* m_mesh = get_mesh(); residuals.setZero(get_neq()); pre_residual_hook(displacement); Eigen::Vector2d element_residual; for(index_t element: m_mesh->range_elements()) { residuals_element(element, displacement, velocity, element_residual, use_chemistry_rate); const index_t node_0 = m_mesh->get_node(element, 0); if (id_equation(node_0) > no_equation) { residuals(id_equation(node_0)) += element_residual(0); } const index_t node_1 = m_mesh->get_node(element, 1); if (id_equation(node_1) > no_equation) { residuals(id_equation(node_1)) += element_residual(1); } } post_residual_hook(displacement); } template void FV1DOFEquation::update_solution( const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity ) { for (index_t node: get_mesh()->range_nodes()) { if (id_equation(node) > no_equation) { velocity(node) += lambda*update(id_equation(node)); } } displacement = predictor + alpha_dt*velocity; derived()->compute_transport_rate(alpha_dt, displacement); } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/pressure_equation.cpp b/src/reactmicp/systems/unsaturated/pressure_equation.cpp index 64d36e4..79bea49 100644 --- a/src/reactmicp/systems/unsaturated/pressure_equation.cpp +++ b/src/reactmicp/systems/unsaturated/pressure_equation.cpp @@ -1,268 +1,270 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "pressure_equation.hpp" #include "transport_constraints.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../utils/compat.hpp" #include "variables_box.hpp" #include "../../../physics/constants.hpp" #include "../../../physics/maths.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" #include namespace specmicp { namespace dfpmsolver { // explicit template instanciation template class ParabolicDriver; } //end namespace dfpmsolver namespace reactmicp { namespace systems { namespace unsaturated { struct SPECMICP_DLL_LOCAL PressureEquation::PressureEquationImpl { PressureVariableBox m_vars; std::vector m_ideq; mesh::Mesh1DPtr m_mesh; mesh::Mesh1D* mesh() {return m_mesh.get();} PressureVariableBox& vars() {return m_vars;} bool node_has_equation(index_t node) { return m_ideq[node] != no_equation; } index_t id_equation(index_t node) { return m_ideq[node]; } void fix_node(index_t node) { m_ideq[node] = no_equation; } PressureEquationImpl( mesh::Mesh1DPtr the_mesh, PressureVariableBox& the_vars ): m_vars(the_vars), m_ideq(the_mesh->nb_nodes(), -5), m_mesh(the_mesh) {} void compute_transport_rate(scalar_t dt, const Vector& displacement); }; PressureEquation::PressureEquation( mesh::Mesh1DPtr the_mesh, PressureVariableBox& variables, const TransportConstraints& constraints ): base(the_mesh->nb_nodes()), m_impl(make_unique(the_mesh, variables)) { number_equations(constraints); } PressureEquation::~PressureEquation() = default; index_t PressureEquation::id_equation_impl(index_t id_dof) { return m_impl->id_equation(id_dof); } mesh::Mesh1D* PressureEquation::get_mesh_impl() { return m_impl->mesh(); } void PressureEquation::pre_nodal_residual_hook_impl( index_t node, const Vector& displacement) {} void PressureEquation::pre_residual_hook_impl(const Vector& displacement) { } void PressureEquation::post_residual_hook_impl(const Vector& displacement) { } //! \brief Compute the residuals inside 'element' void PressureEquation::residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { element_residual.setZero(); mesh::Mesh1D* m_mesh = m_impl->mesh(); PressureVariableBox& vars = m_impl->m_vars; const scalar_t& rt = vars.constants.rt; const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); // Diffusion Cw const scalar_t coeff_diff_0 = vars.resistance_gas_diffusivity(node_0) * vars.relative_gas_diffusivity(node_0); const scalar_t coeff_diff_1 = vars.resistance_gas_diffusivity(node_1) * vars.relative_gas_diffusivity(node_1); const scalar_t coeff_diff = vars.binary_diffusion_coefficient * average(coeff_diff_0, coeff_diff_1); const scalar_t diff_flux = coeff_diff*( displacement(node_1) - displacement(node_0)) / m_mesh->get_dx(element) / rt; // Tot flux const scalar_t tot_flux = m_mesh->get_face_area(element)*(diff_flux); const scalar_t flux_0 = tot_flux; const scalar_t flux_1 = -tot_flux; // transient if (m_impl->node_has_equation(node_0)) { const scalar_t porosity_0 = vars.porosity(node_0); const scalar_t pressure_0 = displacement(node_0); const scalar_t saturation_0 = 1.0 - vars.liquid_saturation(node_0); const scalar_t transient_0 = mass_coeff_0/rt * ( porosity_0 * saturation_0 * velocity(node_0) + saturation_0 * pressure_0 * vars.porosity.velocity(node_0) - porosity_0 * pressure_0 * vars.liquid_saturation.velocity(node_0) ); auto res = transient_0 - flux_0; if (use_chemistry_rate) { res += mass_coeff_0*vars.partial_pressure.chemistry_rate(node_0); } element_residual(0) = res/get_scaling(); } if (m_impl->node_has_equation(node_1)) { const scalar_t porosity_1 = vars.porosity(node_1); const scalar_t pressure_1 = displacement(node_1); const scalar_t saturation_1 = 1.0 - vars.liquid_saturation(node_1); const scalar_t transient_1 = mass_coeff_1/rt * ( porosity_1 * saturation_1 * velocity(node_1) + saturation_1 * pressure_1 * vars.porosity.velocity(node_1) - porosity_1 * pressure_1 * vars.liquid_saturation.velocity(node_1) ); auto res = transient_1 - flux_1; if (use_chemistry_rate) { res += mass_coeff_1*vars.partial_pressure.chemistry_rate(node_1); } element_residual(1) = res/get_scaling(); } } void PressureEquation::number_equations(const TransportConstraints& constraints) { for (int fixed: constraints.fixed_nodes()) { m_impl->fix_node(fixed); } index_t neq = 0; for (index_t node: m_impl->mesh()->range_nodes()) { if (m_impl->m_ideq[node] == -5) { m_impl->m_ideq[node] = neq; ++neq; } } register_number_equations(neq); } void PressureEquation::compute_transport_rate( scalar_t dt, const Vector& displacement) { m_impl->compute_transport_rate(dt, displacement); } void PressureEquation::PressureEquationImpl::compute_transport_rate( scalar_t dt, const Vector& displacement) { const scalar_t& rt = m_vars.constants.rt; const MainVariable& saturation = m_vars.liquid_saturation; MainVariable& pressure = m_vars.partial_pressure; const SecondaryTransientVariable& porosity = m_vars.porosity; for (index_t node: m_mesh->range_nodes()) { if (! node_has_equation(node)) continue; const scalar_t transient = ( (porosity(node)*(1.0-saturation(node))*displacement(node)) - (porosity.predictor(node)*(1.0-saturation.predictor(node))*pressure.predictor(node)) ) / (rt*dt); const scalar_t chem_rates = ( - pressure.chemistry_rate(node) ); pressure.transport_fluxes(node) = transient - chem_rates; } } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/pressure_equation.hpp b/src/reactmicp/systems/unsaturated/pressure_equation.hpp index 749e12a..857d161 100644 --- a/src/reactmicp/systems/unsaturated/pressure_equation.hpp +++ b/src/reactmicp/systems/unsaturated/pressure_equation.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_PRESSUREEQUATION_HPP #define SPECMICP_REACTMICP_UNSATURATED_PRESSUREEQUATION_HPP //! \file unsaturated/pressure_equation.hpp //! \brief The pressure diffusion equation #include "../../../types.hpp" #include "../../../dfpmsolver/parabolic_program.hpp" #include "fv_1dof_equation.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "variables.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class TransportConstraints; //! \brief Pressure diffusion equation - valid for water and aqueous components //! /*! \f[ \frac{1}{R T} \frac{\partial \phi S_g p_i}{\partial t} = \nabla \cdot \left(\frac{D_l}{R T} \nabla p_i \right) - \dot{R}^{g \rightarrow l}_i\f] */ class SPECMICP_DLL_LOCAL PressureEquation: public FV1DOFEquation { using base = FV1DOFEquation; using base::get_scaling; using base::register_number_equations; public: PressureEquation( mesh::Mesh1DPtr the_mesh, PressureVariableBox& variables, const TransportConstraints& constraints); ~PressureEquation(); index_t id_equation_impl(index_t id_dof); mesh::Mesh1D* get_mesh_impl(); void pre_nodal_residual_hook_impl(index_t node, const Vector& displacement); void pre_residual_hook_impl(const Vector& displacement); void post_residual_hook_impl(const Vector& displacement); //! \brief Compute the residuals inside 'element' void residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); void compute_transport_rate(scalar_t dt, const Vector& displacement); private: void number_equations(const TransportConstraints& constraints); struct PressureEquationImpl; std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_PRESSUREEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/saturation_equation.cpp b/src/reactmicp/systems/unsaturated/saturation_equation.cpp index 25151c0..b70dbdd 100644 --- a/src/reactmicp/systems/unsaturated/saturation_equation.cpp +++ b/src/reactmicp/systems/unsaturated/saturation_equation.cpp @@ -1,355 +1,357 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "saturation_equation.hpp" #include "variables_box.hpp" #include "transport_constraints.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" #include "../../../utils/compat.hpp" #include "../../../physics/maths.hpp" #include #include namespace specmicp { namespace dfpmsolver { // explicit template instanciation template class dfpmsolver::ParabolicDriver; } //end namespace dfpmsolver } //end namespace specmicp namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { static constexpr index_t no_equation {-1}; static constexpr index_t no_eq_no_var {-2}; static constexpr index_t not_initialized {-5}; struct SPECMICP_DLL_LOCAL SaturationEquation::SaturationEquationImpl { mesh::Mesh1DPtr m_mesh; SaturationVariableBox m_vars; std::vector m_ideq; bool m_store_residual_info; SaturationEquationImpl( mesh::Mesh1DPtr the_mesh, SaturationVariableBox vars): m_mesh(the_mesh), m_vars(vars), m_ideq(the_mesh->nb_nodes(), not_initialized) {} index_t& id_equation(index_t node) {return m_ideq[node];} bool node_can_flux(index_t node) {return m_ideq[node] != no_eq_no_var;} bool node_has_eq(index_t node) {return m_ideq[node] > no_equation;} void set_store_residual_info() { m_store_residual_info = true; } void reset_store_residual_info() { m_store_residual_info = false; } bool store_residual_info() { return m_store_residual_info; } //! \brief Return a pointer to the mesh mesh::Mesh1D* mesh() {return m_mesh.get();} range_t range_nodes() {return m_mesh->range_nodes();} void set_relative_variables(const Vector& displacement); void set_relative_variables(index_t node, const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); }; SaturationEquation::~SaturationEquation() = default; SaturationEquation::SaturationEquation(mesh::Mesh1DPtr the_mesh, SaturationVariableBox &variables, const TransportConstraints& constraints ): base(the_mesh->nb_nodes()), m_impl(make_unique(the_mesh, variables)) { number_equations(constraints); } void SaturationEquation::number_equations(const TransportConstraints& constraints) { for (index_t node: constraints.fixed_nodes()) { m_impl->id_equation(node) = no_equation; } for (index_t node: constraints.gas_nodes()) { m_impl->id_equation(node) = no_eq_no_var; } index_t neq = 0; for (index_t node: m_impl->range_nodes()) { if (m_impl->id_equation(node) == not_initialized) { m_impl->id_equation(node) = neq; ++neq; } } register_number_equations(neq); } mesh::Mesh1D* SaturationEquation::get_mesh_impl() { return m_impl->mesh(); } index_t SaturationEquation::id_equation_impl(index_t id_dof) { return m_impl->id_equation(id_dof)<0?no_equation:m_impl->id_equation(id_dof); } void SaturationEquation::pre_nodal_residual_hook_impl( index_t node, const Vector& displacement) { m_impl->set_relative_variables(node, displacement); } void SaturationEquation::pre_residual_hook_impl(const Vector& displacement) { m_impl->set_relative_variables(displacement); m_impl->set_store_residual_info(); } void SaturationEquation::post_residual_hook_impl(const Vector& displacement) { m_impl->reset_store_residual_info(); } // Residuals // ========= void SaturationEquation::residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { element_residual.setZero(); mesh::Mesh1D* m_mesh = m_impl->mesh(); SaturationVariableBox& vars = m_impl->m_vars; const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); scalar_t flux_0 = 0.0; scalar_t flux_1 = 0.0; if (m_impl->node_can_flux(node_0) and m_impl->node_can_flux(node_1)) { // Cap pressure gradient const scalar_t perm_0 = vars.liquid_permeability(node_0) * vars.relative_liquid_permeability(node_0); const scalar_t perm_1 = vars.liquid_permeability(node_1) * vars.relative_liquid_permeability(node_1); const scalar_t perm = average(perm_0, perm_1); const scalar_t aq_coefficient = average( vars.aqueous_concentration(node_0), vars.aqueous_concentration(node_1) ); const scalar_t cap_pressure_gradient = ( vars.capillary_pressure(node_1) - vars.capillary_pressure(node_0) ) / m_mesh->get_dx(element); const scalar_t advection_flux = (perm/vars.constants.viscosity_liquid_water)*cap_pressure_gradient; const scalar_t cappres_flux = -aq_coefficient*advection_flux; // Diffusion Cw const scalar_t coeff_diff_0 = vars.liquid_diffusivity(node_0) * vars.relative_liquid_diffusivity(node_0); const scalar_t coeff_diff_1 = vars.liquid_diffusivity(node_1) * vars.relative_liquid_diffusivity(node_1); const scalar_t coeff_diff = average( coeff_diff_0, coeff_diff_1); const scalar_t aq_flux = coeff_diff*(vars.aqueous_concentration(node_1) - vars.aqueous_concentration(node_0) ) / m_mesh->get_dx(element); // Tot flux const scalar_t tot_flux = m_mesh->get_face_area(element)*(cappres_flux + aq_flux); flux_0 = tot_flux; flux_1 = -tot_flux; // Storage if (m_impl->store_residual_info()) { // advective flux stored by element vars.advection_flux(element) = advection_flux; // fluxes to compute exchange term vars.liquid_saturation.transport_fluxes(node_0) += flux_0; vars.liquid_saturation.transport_fluxes(node_1) += flux_1; } } // transient if (m_impl->node_has_eq(node_0)) { const scalar_t porosity_0 = vars.porosity(node_0); const scalar_t aq_tot_conc_0 = vars.aqueous_concentration(node_0); const scalar_t saturation_0 = displacement(node_0); scalar_t transient_0 = ( porosity_0 * aq_tot_conc_0 * velocity(node_0) + saturation_0 * aq_tot_conc_0 * vars.porosity.velocity(node_0) + porosity_0 * saturation_0 * vars.aqueous_concentration.velocity(node_0) ); auto res = mass_coeff_0*transient_0 - flux_0; if (use_chemistry_rate) { const scalar_t chemistry_0 = vars.liquid_saturation.chemistry_rate(node_0) + vars.solid_concentration.chemistry_rate(node_0) + vars.vapor_pressure.chemistry_rate(node_0) ; res -= mass_coeff_0*chemistry_0; } element_residual(0) = res / get_scaling(); } if (m_impl->node_has_eq(node_1)) { const scalar_t porosity_1 = vars.porosity(node_1); const scalar_t aq_tot_conc_1 = vars.aqueous_concentration(node_1); const scalar_t saturation_1 = displacement(node_1); scalar_t transient_1 = ( porosity_1 * aq_tot_conc_1 * velocity(node_1) + saturation_1 * aq_tot_conc_1 * vars.porosity.velocity(node_1) + porosity_1 * saturation_1 * vars.aqueous_concentration.velocity(node_1) ); auto res = mass_coeff_1*transient_1 - flux_1; if (use_chemistry_rate) { const scalar_t chemistry_1 = vars.liquid_saturation.chemistry_rate(node_1) + vars.solid_concentration.chemistry_rate(node_1) + vars.vapor_pressure.chemistry_rate(node_1) ; res -= mass_coeff_1*chemistry_1; } element_residual(1) = res / get_scaling(); } } void SaturationEquation::set_relative_variables(const Vector& displacement) { return m_impl->set_relative_variables(displacement); } void SaturationEquation::SaturationEquationImpl::set_relative_variables( index_t node, const Vector& displacement ) { if (not node_can_flux(node)) return; const scalar_t saturation = displacement(node); m_vars.relative_liquid_diffusivity(node) = m_vars.relative_liquid_diffusivity_f(node, saturation); m_vars.relative_liquid_permeability(node) = m_vars.relative_liquid_permeability_f(node, saturation); m_vars.capillary_pressure(node) = m_vars.capillary_pressure_f(node, saturation); } void SaturationEquation::SaturationEquationImpl::set_relative_variables(const Vector& displacement) { for (index_t node: m_mesh->range_nodes()) { set_relative_variables(node, displacement); } } void SaturationEquation::compute_transport_rate(scalar_t dt, const Vector& displacement) { m_impl->compute_transport_rate(dt, displacement); } void SaturationEquation::SaturationEquationImpl::compute_transport_rate( scalar_t dt, const Vector& displacement) { MainVariable& saturation = m_vars.liquid_saturation; const MainVariable& solid_conc = m_vars.solid_concentration; const MainVariable& pressure = m_vars.vapor_pressure; const SecondaryTransientVariable& porosity = m_vars.porosity; const SecondaryTransientVariable& aqueous_concentration = m_vars.aqueous_concentration; for (index_t node: m_mesh->range_nodes()) { if (! node_has_eq(node)) continue; const scalar_t transient = ( (porosity(node)*aqueous_concentration(node)*displacement(node)) - (porosity.predictor(node)*aqueous_concentration.predictor(node)*saturation.predictor(node)) ) / dt; const scalar_t chem_rates = ( saturation.chemistry_rate(node) + solid_conc.chemistry_rate(node) + pressure.chemistry_rate(node) ); saturation.transport_fluxes(node) = transient - chem_rates; } } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/saturation_equation.hpp b/src/reactmicp/systems/unsaturated/saturation_equation.hpp index d51549a..381c8dc 100644 --- a/src/reactmicp/systems/unsaturated/saturation_equation.hpp +++ b/src/reactmicp/systems/unsaturated/saturation_equation.hpp @@ -1,108 +1,110 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_SATURATIONEQUATION_HPP #define SPECMICP_REACTMICP_UNSATURATED_SATURATIONEQUATION_HPP //! \file unsaturated/saturation_equation.hpp //! \brief The saturation equation for the unsaturated system #include "../../../types.hpp" #include "fv_1dof_equation.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "variables.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class TransportConstraints; //! \brief The saturation equation //! //! Solve the transport of liquid water class SPECMICP_DLL_LOCAL SaturationEquation: public FV1DOFEquation { using base = FV1DOFEquation; using base::get_scaling; using base::register_number_equations; public: SaturationEquation( mesh::Mesh1DPtr the_mesh, SaturationVariableBox& variables, const TransportConstraints& constraints); ~SaturationEquation(); //! \brief Return the id of equation dof index_t id_equation_impl(index_t id_dof); mesh::Mesh1D* get_mesh_impl(); void pre_nodal_residual_hook_impl(index_t node, const Vector& displacement); void pre_residual_hook_impl(const Vector& displacement); void post_residual_hook_impl(const Vector& displacement); //! \brief Compute the residuals inside 'element' for 'component' void residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); //! \brief Set the relative variables void set_relative_variables(const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); private: void number_equations(const TransportConstraints& constraints); struct SaturationEquationImpl; std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_SATURATIONEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/saturation_pressure_equation.cpp b/src/reactmicp/systems/unsaturated/saturation_pressure_equation.cpp index c78517d..293c850 100644 --- a/src/reactmicp/systems/unsaturated/saturation_pressure_equation.cpp +++ b/src/reactmicp/systems/unsaturated/saturation_pressure_equation.cpp @@ -1,391 +1,393 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "saturation_pressure_equation.hpp" #include "variables_box.hpp" #include "transport_constraints.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" #include "../../../utils/compat.hpp" #include "../../../physics/maths.hpp" #include #include namespace specmicp { namespace dfpmsolver { // explicit template instanciation template class ParabolicDriver; } //end namespace dfpmsolver } //end namespace specmicp namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { static constexpr index_t no_equation {-1}; static constexpr index_t no_eq_no_var {-2}; static constexpr index_t not_initialized {-5}; struct SPECMICP_DLL_LOCAL SaturationPressureEquation::SaturationPressureEquationImpl { mesh::Mesh1DPtr m_mesh; SaturationPressureVariableBox m_vars; std::vector m_ideq; bool m_store_residual_info; SaturationPressureEquationImpl( mesh::Mesh1DPtr the_mesh, SaturationPressureVariableBox vars): m_mesh(the_mesh), m_vars(vars), m_ideq(the_mesh->nb_nodes(), not_initialized) {} index_t& id_equation(index_t node) {return m_ideq[node];} bool node_can_flux(index_t node) {return m_ideq[node] != no_eq_no_var;} bool node_has_eq(index_t node) {return m_ideq[node] > no_equation;} void set_store_residual_info() { m_store_residual_info = true; } void reset_store_residual_info() { m_store_residual_info = false; } bool store_residual_info() { return m_store_residual_info; } //! \brief Return a pointer to the mesh mesh::Mesh1D* mesh() {return m_mesh.get();} range_t range_nodes() {return m_mesh->range_nodes();} void set_relative_variables(const Vector& displacement); void set_relative_variables(index_t node, const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); }; SaturationPressureEquation::~SaturationPressureEquation() = default; SaturationPressureEquation::SaturationPressureEquation(mesh::Mesh1DPtr the_mesh, SaturationPressureVariableBox &variables, const TransportConstraints& constraints ): base(the_mesh->nb_nodes()), m_impl(make_unique(the_mesh, variables)) { number_equations(constraints); } void SaturationPressureEquation::number_equations(const TransportConstraints& constraints) { for (index_t node: constraints.fixed_nodes()) { m_impl->id_equation(node) = no_equation; } for (index_t node: constraints.gas_nodes()) { m_impl->id_equation(node) = no_eq_no_var; } index_t neq = 0; for (index_t node: m_impl->range_nodes()) { if (m_impl->id_equation(node) == not_initialized) { m_impl->id_equation(node) = neq; ++neq; } } register_number_equations(neq); } mesh::Mesh1D* SaturationPressureEquation::get_mesh_impl() { return m_impl->mesh(); } index_t SaturationPressureEquation::id_equation_impl(index_t id_dof) { return m_impl->id_equation(id_dof)<0?no_equation:m_impl->id_equation(id_dof); } void SaturationPressureEquation::pre_nodal_residual_hook_impl( index_t node, const Vector& displacement ) { m_impl->set_relative_variables(node, displacement); } void SaturationPressureEquation::pre_residual_hook_impl( const Vector& displacement ) { m_impl->set_relative_variables(displacement); m_impl->set_store_residual_info(); } void SaturationPressureEquation::post_residual_hook_impl( const Vector& displacement ) { m_impl->reset_store_residual_info(); } // Residuals // ========= void SaturationPressureEquation::residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ) { element_residual.setZero(); mesh::Mesh1D* m_mesh = m_impl->mesh(); SaturationPressureVariableBox& vars = m_impl->m_vars; const scalar_t& rt = vars.constants.rt; const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); scalar_t flux_0 = 0.0; scalar_t flux_1 = 0.0; scalar_t tot_flux = 0.0; scalar_t advection_flux = 0.0; if (m_impl->node_can_flux(node_0) and m_impl->node_can_flux(node_1)) { // Cap pressure gradient const scalar_t perm_0 = vars.liquid_permeability(node_0) * vars.relative_liquid_permeability(node_0); const scalar_t perm_1 = vars.liquid_permeability(node_1) * vars.relative_liquid_permeability(node_1); const scalar_t perm = average(perm_0, perm_1); const scalar_t aq_coefficient = average( vars.aqueous_concentration(node_0), vars.aqueous_concentration(node_1) ); const scalar_t cap_pressure_gradient = ( vars.capillary_pressure(node_1) - vars.capillary_pressure(node_0) ) / m_mesh->get_dx(element); advection_flux = (perm/vars.constants.viscosity_liquid_water)*cap_pressure_gradient; const scalar_t cappres_flux = -aq_coefficient*advection_flux; // Diffusion Cw const scalar_t coeff_diff_0 = vars.liquid_diffusivity(node_0) * vars.relative_liquid_diffusivity(node_0); const scalar_t coeff_diff_1 = vars.liquid_diffusivity(node_1) * vars.relative_liquid_diffusivity(node_1); const scalar_t coeff_diff = average( coeff_diff_0, coeff_diff_1); const scalar_t aq_flux = coeff_diff*(vars.aqueous_concentration(node_1) - vars.aqueous_concentration(node_0) ) / m_mesh->get_dx(element); tot_flux = (cappres_flux + aq_flux); } // Diffusion pressure pv const scalar_t coeff_diff_gas_0 = vars.resistance_gas_diffusivity(node_0) * vars.relative_gas_diffusivity(node_0); const scalar_t coeff_diff_gas_1 = vars.resistance_gas_diffusivity(node_1) * vars.relative_gas_diffusivity(node_1); const scalar_t coeff_diff_gas = vars.binary_diffusion_coefficient * average(coeff_diff_gas_0, coeff_diff_gas_1); const scalar_t diff_flux_gas = coeff_diff_gas*( vars.partial_pressure(node_1) - vars.partial_pressure(node_0)) / m_mesh->get_dx(element) / rt; // Tot flux tot_flux += diff_flux_gas; tot_flux *= m_mesh->get_face_area(element); flux_0 = tot_flux; flux_1 = -tot_flux; // Storage if (m_impl->store_residual_info()) { // advective flux stored by element vars.advection_flux(element) = advection_flux; // fluxes to compute exchange term vars.liquid_saturation.transport_fluxes(node_0) += flux_0; vars.liquid_saturation.transport_fluxes(node_1) += flux_1; } // transient if (m_impl->node_has_eq(node_0)) { const scalar_t porosity_0 = vars.porosity(node_0); const scalar_t aq_tot_conc_0 = vars.aqueous_concentration(node_0); const scalar_t saturation_0 = displacement(node_0); scalar_t transient_0 = ( porosity_0 * aq_tot_conc_0 * velocity(node_0) + saturation_0 * aq_tot_conc_0 * vars.porosity.velocity(node_0) + porosity_0 * saturation_0 * vars.aqueous_concentration.velocity(node_0) ); auto res = mass_coeff_0*transient_0 - flux_0; if (use_chemistry_rate) { const scalar_t chemistry_0 = vars.liquid_saturation.chemistry_rate(node_0) + vars.solid_concentration.chemistry_rate(node_0) + vars.partial_pressure.chemistry_rate(node_0) ; res -= mass_coeff_0*chemistry_0; } element_residual(0) = res / get_scaling(); } if (m_impl->node_has_eq(node_1)) { const scalar_t porosity_1 = vars.porosity(node_1); const scalar_t aq_tot_conc_1 = vars.aqueous_concentration(node_1); const scalar_t saturation_1 = displacement(node_1); scalar_t transient_1 = ( porosity_1 * aq_tot_conc_1 * velocity(node_1) + saturation_1 * aq_tot_conc_1 * vars.porosity.velocity(node_1) + porosity_1 * saturation_1 * vars.aqueous_concentration.velocity(node_1) ); auto res = mass_coeff_1*transient_1 - flux_1; if (use_chemistry_rate) { const scalar_t chemistry_1 = vars.liquid_saturation.chemistry_rate(node_1) + vars.solid_concentration.chemistry_rate(node_1) + vars.partial_pressure.chemistry_rate(node_1) ; res -= mass_coeff_1*chemistry_1; } element_residual(1) = res / get_scaling(); } } void SaturationPressureEquation::set_relative_variables(const Vector& displacement) { return m_impl->set_relative_variables(displacement); } void SaturationPressureEquation::SaturationPressureEquationImpl::set_relative_variables( index_t node, const Vector& displacement ) { if (not node_can_flux(node)) return; const scalar_t saturation = displacement(node); m_vars.relative_liquid_diffusivity(node) = m_vars.relative_liquid_diffusivity_f(node, saturation); m_vars.relative_liquid_permeability(node) = m_vars.relative_liquid_permeability_f(node, saturation); m_vars.capillary_pressure(node) = m_vars.capillary_pressure_f(node, saturation); //m_vars.partial_pressure(node) = m_vars.partial_pressure_f(node, saturation); } void SaturationPressureEquation::SaturationPressureEquationImpl::set_relative_variables( const Vector& displacement ) { for (index_t node: m_mesh->range_nodes()) { set_relative_variables(node, displacement); } } void SaturationPressureEquation::compute_transport_rate( scalar_t dt, const Vector& displacement ) { m_impl->compute_transport_rate(dt, displacement); } void SaturationPressureEquation::SaturationPressureEquationImpl::compute_transport_rate( scalar_t dt, const Vector& displacement) { MainVariable& saturation = m_vars.liquid_saturation; const MainVariable& solid_conc = m_vars.solid_concentration; const MainVariable& pressure = m_vars.partial_pressure; const SecondaryTransientVariable& porosity = m_vars.porosity; const SecondaryTransientVariable& aqueous_concentration = m_vars.aqueous_concentration; for (index_t node: m_mesh->range_nodes()) { if (! node_has_eq(node)) continue; const scalar_t transient = ( (porosity(node)*aqueous_concentration(node)*displacement(node)) - (porosity.predictor(node)*aqueous_concentration.predictor(node)*saturation.predictor(node)) ) / dt; const scalar_t chem_rates = ( saturation.chemistry_rate(node) + solid_conc.chemistry_rate(node) + pressure.chemistry_rate(node) ); saturation.transport_fluxes(node) = transient - chem_rates; } } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/saturation_pressure_equation.hpp b/src/reactmicp/systems/unsaturated/saturation_pressure_equation.hpp index a179115..6b0697e 100644 --- a/src/reactmicp/systems/unsaturated/saturation_pressure_equation.hpp +++ b/src/reactmicp/systems/unsaturated/saturation_pressure_equation.hpp @@ -1,108 +1,110 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_SATURATIONPRESSUREEQUATION_HPP #define SPECMICP_REACTMICP_UNSATURATED_SATURATIONPRESSUREEQUATION_HPP //! \file unsaturated/saturation_pressure_equation.hpp //! \brief The saturation and pressure equation for the unsaturated system #include "../../../types.hpp" #include "fv_1dof_equation.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "variables.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { class TransportConstraints; //! \brief The saturation equation //! //! Solve the transport of liquid water class SPECMICP_DLL_LOCAL SaturationPressureEquation: public FV1DOFEquation { using base = FV1DOFEquation; using base::get_scaling; using base::register_number_equations; public: SaturationPressureEquation( mesh::Mesh1DPtr the_mesh, SaturationPressureVariableBox& variables, const TransportConstraints& constraints); ~SaturationPressureEquation(); //! \brief Return the id of equation dof index_t id_equation_impl(index_t id_dof); mesh::Mesh1D* get_mesh_impl(); void pre_nodal_residual_hook_impl(index_t node, const Vector& displacement); void pre_residual_hook_impl(const Vector& displacement); void post_residual_hook_impl(const Vector& displacement); //! \brief Compute the residuals inside 'element' for 'component' void residuals_element_impl( index_t element, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual, bool use_chemistry_rate ); //! \brief Set the relative variables void set_relative_variables(const Vector& displacement); void compute_transport_rate(scalar_t dt, const Vector& displacement); private: void number_equations(const TransportConstraints& constraints); struct SaturationPressureEquationImpl; std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_SATURATIONPRESSUREEQUATION_HPP diff --git a/src/reactmicp/systems/unsaturated/transport_constraints.hpp b/src/reactmicp/systems/unsaturated/transport_constraints.hpp index 2e534ef..2e2ed12 100644 --- a/src/reactmicp/systems/unsaturated/transport_constraints.hpp +++ b/src/reactmicp/systems/unsaturated/transport_constraints.hpp @@ -1,96 +1,98 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_TRANSPORTCONSTRAINTS_HPP #define SPECMICP_REACTMICP_TRANSPORTCONSTRAINTS_HPP //! \file unsaturated/transport_constraints.hpp //! \brief Constraints for the transport equations #include "../../../types.hpp" #include #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { //! \brief Constraints for the transport equations class SPECMICP_DLL_PUBLIC TransportConstraints { public: TransportConstraints() {} //! \brief Set the fixed nodes void set_fixed_nodes(const std::vector& fixed_nodes) { m_fixed_nodes = fixed_nodes; } //! \brief Set the gas nodes void set_gas_nodes(const std::vector& gas_nodes) { m_gas_nodes = gas_nodes; } //! \brief Add a fixed node void add_fixed_node(index_t node) { m_fixed_nodes.push_back(node); } //! \brief Add a gas node //! //! A gas node is a node with S_l = 0 void add_gas_node(index_t node) { m_gas_nodes.push_back(node); } //! \brief Return the list of fixed nodes const std::vector& fixed_nodes() const { return m_fixed_nodes; } //! \brief Return the list of gas nodes const std::vector& gas_nodes() const { return m_gas_nodes; } private: std::vector m_fixed_nodes; std::vector m_gas_nodes; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_TRANSPORTCONSTRAINTS_HPP diff --git a/src/reactmicp/systems/unsaturated/transport_stagger.cpp b/src/reactmicp/systems/unsaturated/transport_stagger.cpp index a217995..5dd4d44 100644 --- a/src/reactmicp/systems/unsaturated/transport_stagger.cpp +++ b/src/reactmicp/systems/unsaturated/transport_stagger.cpp @@ -1,1084 +1,1086 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "transport_stagger.hpp" #include "../../solver/staggers_base/stagger_structs.hpp" #include "variables.hpp" #include "variables_box.hpp" #include "saturation_equation.hpp" #include "saturation_pressure_equation.hpp" #include "pressure_equation.hpp" #include "aqueous_equation.hpp" #include "aqueous_pressure_equation.hpp" #include "../../../database/database_holder.hpp" #include "../../../dfpmsolver/parabolic_driver.hpp" #include "../../../utils/log.hpp" #include namespace specmicp { namespace dfpmsolver { extern template class ParabolicDriver; extern template class ParabolicDriver; extern template class ParabolicDriver; extern template class ParabolicDriver; extern template class ParabolicDriver; } //end namespace dfpmsolver namespace reactmicp { namespace systems { namespace unsaturated { //! \brief Type of the equation //! \internal enum class EquationType { Saturation, LiquidAqueous, Pressure }; //! \brief Format type to a string (for message error) //! \internal static std::string to_string(EquationType eq_type); //! \brief Format DFPM solver retcode to a string static std::string to_string(dfpmsolver::ParabolicDriverReturnCode retcode); // forward declaration of wrapper classes // They are defined at the bootom of this file class TaskBase; class SaturationTask; using VariablesBase = solver::VariablesBase; // =================================== // // // // Declaration of the implementation // // // // =================================== // //! \brief Implementation class for the Unsaturated transport stagger //! \internal //! //! This class does all the work //! It was designed to be OpenMP compatible class UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl { public: // Constructor // ----------- UnsaturatedTransportStaggerImpl( UnsaturatedVariablesPtr variables, const TransportConstraints& constraints, bool merge_saturation_pressure, bool merge_aqueous_pressure ); // Main functions // -------------- //! \brief Return the residual scalar_t get_residual(UnsaturatedVariables * const vars); //! \brief Return the first residual (start of timestep) scalar_t get_residual_0(UnsaturatedVariables * const vars); //! \brief Return the update (norm of velocity vector) scalar_t get_update(UnsaturatedVariables * const vars); //! \brief Initialize timestep void initialize_timestep( scalar_t dt, UnsaturatedVariables * const vars); //! \brief Restart the timestep solver::StaggerReturnCode restart_timestep(UnsaturatedVariables* vars); // Timestep management // ------------------- //! \brief Save the timestep void save_dt(scalar_t dt) {m_dt = dt;} //! \brief Return the timestep scalar_t get_dt() {return m_dt;} // Task index // ---------- index_t& id_aqueous_task(index_t component) { return m_aq_equation_task[static_cast(component)]; } index_t id_aqueous_task(index_t component) const { return m_aq_equation_task[static_cast(component)]; } index_t& id_gas_task(index_t component) { return m_aq_equation_task[static_cast(component)]; } index_t id_gas_tasj(index_t component) const { return m_aq_equation_task[static_cast(component)]; } //! \brief Return the options of the saturation equation dfpmsolver::ParabolicDriverOptions* get_saturation_options(); //! \brief Return the options of aqueous equation of component dfpmsolver::ParabolicDriverOptions* get_aqueous_options(index_t component); //! \brief Return the options of gas equation of component dfpmsolver::ParabolicDriverOptions* get_gas_options(index_t component); private: scalar_t m_norm_0 {1.0}; // timestep management scalar_t m_dt {-1.0}; //! \brief The saturation equations std::unique_ptr m_saturation_equation; // Equation and solver std::vector> m_equation_list; std::vector m_aq_equation_task; std::vector m_gas_equation_task; std::vector m_merged_gas; }; // Main functions // =============== // call of the implementation UnsaturatedTransportStagger::UnsaturatedTransportStagger( std::shared_ptr variables, const TransportConstraints& constraints, bool merge_saturation_pressure, bool merge_aqueous_pressure ): m_impl(utils::make_pimpl( variables, constraints, merge_saturation_pressure, merge_aqueous_pressure )) { } UnsaturatedTransportStagger::~UnsaturatedTransportStagger() = default; static UnsaturatedVariables * const get_var(VariablesBase * const var) { return static_cast(var); } void UnsaturatedTransportStagger::initialize_timestep( scalar_t dt, VariablesBase* var ) { m_impl->initialize_timestep(dt, get_var(var)); } solver::StaggerReturnCode UnsaturatedTransportStagger::restart_timestep(VariablesBase * const var) { return m_impl->restart_timestep(get_var(var)); } scalar_t UnsaturatedTransportStagger::get_residual(VariablesBase * const var) { return m_impl->get_residual(get_var(var)); } scalar_t UnsaturatedTransportStagger::get_residual_0(VariablesBase * const var) { return m_impl->get_residual_0(get_var(var)); } scalar_t UnsaturatedTransportStagger::get_update(VariablesBase * const var) { return m_impl->get_update(get_var(var)); } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::get_saturation_options() { return m_impl->get_saturation_options(); } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::get_aqueous_options(index_t component) { return m_impl->get_aqueous_options(component); } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::get_gas_options(index_t component) { return m_impl->get_gas_options(component); } // =============================== // // =============================== // // // // Implementation details // // ---------------------- // // // // =============================== // // =============================== // // 2 main sections // - Solver wrappers : wrapper around 1 couple equation/solver // - UnsaturatedTransportStaggerImpl : call the wrappers // =============================== // // // // Solver wrappers // // // // =============================== // // This wrappers are used to abstract the residual computation // and the methods to solve every equations //! \brief Base class for a task //! //! A task is how we solve governing equations, //! and obtain residuals and update //! //! \internal class SPECMICP_DLL_LOCAL TaskBase { public: TaskBase(index_t component, EquationType eq_type): m_type(eq_type), m_component(component) {} //! \brief Compute the squared residuals virtual scalar_t compute_squared_residual( UnsaturatedVariables * const vars ) = 0; //! \brief Compute the squared residuals at the beginning of the timestep virtual scalar_t compute_squared_residual_0( UnsaturatedVariables * const vars ) = 0; //! \brief Compute the squared update of the variables virtual scalar_t compute_squared_update( UnsaturatedVariables * const vars ) = 0; //! \brief Initialize the timestep virtual void initialize_timestep( scalar_t dt, UnsaturatedVariables * const vars ) = 0; //! \brief Solve the governing equation virtual dfpmsolver::ParabolicDriverReturnCode restart_timestep( UnsaturatedVariables * const vars ) = 0; //! \brief Return the component index (in the db) index_t component() {return m_component;} //! \brief The equation type EquationType equation_type() {return m_type;} private: EquationType m_type; index_t m_component; }; //! \brief Base class for a equation solver //! //! \internal template class SPECMICP_DLL_LOCAL EquationTask: public TaskBase { public: using EqT = typename traits::EqT; using SolverT = typename traits::SolverT; EquationTask( index_t component, mesh::Mesh1DPtr the_mesh, typename traits::VariableBoxT& variables, const TransportConstraints& constraints ): TaskBase(component, traits::equation_type), m_equation(the_mesh, variables, constraints), m_solver(m_equation) {} EquationTask( index_t component, mesh::Mesh1DPtr the_mesh, typename traits::VariableBoxT& variables, const TransportConstraints& constraints, scalar_t scaling ): TaskBase(component, traits::equation_type), m_equation(the_mesh, variables, constraints), m_solver(m_equation) { m_equation.set_scaling(scaling); } Derived* derived() {return static_cast(this);} // This function must be implemented by subclass MainVariable& get_var(UnsaturatedVariables * const vars) { return derived()->get_var(vars); } scalar_t compute_squared_residual( UnsaturatedVariables * const vars ) override { Vector residuals; const MainVariable& main = get_var(vars); m_equation.compute_residuals(main.variable, main.velocity, residuals, true); return residuals.squaredNorm()/m_norm_square_0; } scalar_t compute_squared_residual_0( UnsaturatedVariables * const vars ) override { Vector residuals; const MainVariable& main = get_var(vars); m_equation.compute_residuals(main.variable, main.velocity, residuals, false); m_norm_square_0 = residuals.squaredNorm(); if (m_norm_square_0 < 1e-8) m_norm_square_0 = 1.0; return 1.0; } scalar_t compute_squared_update( UnsaturatedVariables * const vars ) override { const MainVariable& main = get_var(vars); return main.velocity.squaredNorm(); } void initialize_timestep( scalar_t dt, UnsaturatedVariables * const vars ) override { m_dt = dt; MainVariable& main = get_var(vars); main.predictor = main.variable; main.transport_fluxes.setZero(); main.velocity.setZero(); m_solver.initialize_timestep(dt, get_var(vars).variable); } dfpmsolver::ParabolicDriverReturnCode restart_timestep( UnsaturatedVariables * const vars ) override { MainVariable& main = get_var(vars); m_solver.velocity() = main.velocity; auto retcode = m_solver.restart_timestep(main.variable); if (retcode > dfpmsolver::ParabolicDriverReturnCode::NotConvergedYet) { main.velocity = m_solver.velocity(); } return retcode; } dfpmsolver::ParabolicDriverOptions& get_options() { return m_solver.get_options(); } const dfpmsolver::ParabolicDriverOptions& get_options() const { return m_solver.get_options(); } scalar_t get_dt() {return m_dt;} protected: scalar_t m_norm_square_0 {-1}; scalar_t m_dt {-1}; EqT m_equation; SolverT m_solver; }; //! \brief Traits struct for the SaturationTask class //! //! \internal struct SPECMICP_DLL_LOCAL SaturationTaskTraits { using EqT = SaturationEquation; using SolverT = dfpmsolver::ParabolicDriver; using VariableBoxT = SaturationVariableBox; static constexpr EquationType equation_type {EquationType::Saturation}; }; //! \brief Wrapper for the saturation equation solver //! //! \internal class SPECMICP_DLL_LOCAL SaturationTask: public EquationTask { using base = EquationTask; public: SaturationTask( index_t component, mesh::Mesh1DPtr the_mesh, SaturationTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints ): EquationTask( component, the_mesh, variables, constraints) {} SaturationTask( index_t component, mesh::Mesh1DPtr the_mesh, SaturationTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints, scalar_t scaling ): EquationTask( component, the_mesh, variables, constraints, scaling) {} MainVariable& get_var(UnsaturatedVariables * const vars) { return vars->get_liquid_saturation(); } // Also take into account the solid total concentration scalar_t compute_squared_update( UnsaturatedVariables * const vars ) override { scalar_t solid_update = vars->get_solid_concentration(component()).velocity.squaredNorm(); return solid_update + base::compute_squared_update(vars); } }; //! \brief Traits struct for the SaturationPressureTask class //! //! \internal struct SPECMICP_DLL_LOCAL SaturationPressureTaskTraits { using EqT = SaturationPressureEquation; using SolverT = dfpmsolver::ParabolicDriver; using VariableBoxT = SaturationPressureVariableBox; static constexpr EquationType equation_type {EquationType::Saturation}; }; //! \brief Wrapper for the saturation equation solver //! //! \internal class SPECMICP_DLL_LOCAL SaturationPressureTask: public EquationTask { using base = EquationTask; public: SaturationPressureTask( index_t component, mesh::Mesh1DPtr the_mesh, SaturationPressureTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints ): EquationTask( component, the_mesh, variables, constraints) {} SaturationPressureTask( index_t component, mesh::Mesh1DPtr the_mesh, SaturationPressureTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints, scalar_t scaling ): EquationTask( component, the_mesh, variables, constraints, scaling) {} MainVariable& get_var(UnsaturatedVariables * const vars) { return vars->get_liquid_saturation(); } // Also take into account the solid total concentration scalar_t compute_squared_update( UnsaturatedVariables * const vars ) override { scalar_t solid_update = vars->get_solid_concentration(component()).velocity.squaredNorm(); return solid_update + base::compute_squared_update(vars); } }; //! \brief Traits struct for the LiquidAqueousTask class //! //! \internal struct SPECMICP_DLL_LOCAL LiquidAqueousTaskTraits { using EqT = AqueousTransportEquation; using SolverT = dfpmsolver::ParabolicDriver; using VariableBoxT = LiquidAqueousComponentVariableBox; static constexpr EquationType equation_type {EquationType::LiquidAqueous}; }; //! \brief Wrapper for the liquid transport of aqueous component equation //! //! \internal class SPECMICP_DLL_LOCAL LiquidAqueousTask: public EquationTask { using base = EquationTask; public: LiquidAqueousTask( index_t component, mesh::Mesh1DPtr the_mesh, LiquidAqueousTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints ): EquationTask( component, the_mesh, variables, constraints) {} LiquidAqueousTask( index_t component, mesh::Mesh1DPtr the_mesh, LiquidAqueousTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints, scalar_t scaling ): EquationTask( component, the_mesh, variables, constraints, scaling) {} MainVariable& get_var(UnsaturatedVariables * const vars) { return vars->get_aqueous_concentration(component()); } // Also take into account the solid total concentration scalar_t compute_squared_update( UnsaturatedVariables * const vars ) override { scalar_t solid_update = vars->get_solid_concentration(component()).velocity.squaredNorm(); return solid_update + base::compute_squared_update(vars); } }; //! \brief Traits struct for the LiquidGasAqueousTask class //! //! \internal struct SPECMICP_DLL_LOCAL LiquidGasAqueousTaskTraits { using EqT = AqueousGasTransportEquation; using SolverT = dfpmsolver::ParabolicDriver; using VariableBoxT = LiquidGasAqueousVariableBox; static constexpr EquationType equation_type {EquationType::LiquidAqueous}; }; //! \brief Wrapper for the liquid transport of aqueous component equation //! //! \internal class SPECMICP_DLL_LOCAL LiquidGasAqueousTask: public EquationTask { using base = EquationTask; public: LiquidGasAqueousTask( index_t component, mesh::Mesh1DPtr the_mesh, LiquidGasAqueousTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints ): base(component, the_mesh, variables, constraints) {} LiquidGasAqueousTask( index_t component, mesh::Mesh1DPtr the_mesh, LiquidGasAqueousTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints, scalar_t scaling ): base(component, the_mesh, variables, constraints, scaling) {} MainVariable& get_var(UnsaturatedVariables * const vars) { return vars->get_aqueous_concentration(component()); } // Also take into account the solid total concentration scalar_t compute_squared_update( UnsaturatedVariables * const vars ) override { scalar_t solid_update = vars->get_solid_concentration(component()).velocity.squaredNorm(); return solid_update + base::compute_squared_update(vars); } }; //! \brief Traits struct for the Pressure Task traits //! //! \internal struct SPECMICP_DLL_LOCAL PressureTaskTraits { using EqT = PressureEquation; using SolverT = dfpmsolver::ParabolicDriver; using VariableBoxT = PressureVariableBox; static constexpr EquationType equation_type {EquationType::Pressure}; }; //! \brief Wrapper for the pressure equation solver //! //! \internal class SPECMICP_DLL_LOCAL PressureTask: public EquationTask { using base = EquationTask; public: PressureTask( index_t component, mesh::Mesh1DPtr the_mesh, PressureTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints ): EquationTask( component, the_mesh, variables, constraints) {} PressureTask( index_t component, mesh::Mesh1DPtr the_mesh, PressureTaskTraits::VariableBoxT&& variables, const TransportConstraints& constraints, scalar_t scaling ): EquationTask( component, the_mesh, variables, constraints, scaling) {} MainVariable& get_var(UnsaturatedVariables * const vars) { return vars->get_pressure_main_variables(component()); } }; // ================================== // // // // UnsaturatedTransportStaggerImpl // // // // ================================== // // constructor // =========== UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::UnsaturatedTransportStaggerImpl( UnsaturatedVariablesPtr variables, const TransportConstraints& constraints, bool merge_saturation_pressure, bool merge_aqueous_pressure ): m_merged_gas(variables->get_database()->nb_component(), false) { database::RawDatabasePtr raw_db = variables->get_database(); mesh::Mesh1DPtr the_mesh = variables->get_mesh(); m_aq_equation_task = std::vector( raw_db->nb_component(), no_equation); m_gas_equation_task = std::vector( raw_db->nb_component(), no_equation); dfpmsolver::ParabolicDriverOptions* opts = nullptr; // Saturation equations // ==================== // // There is 2 choices for the saturation equation // Either SaturationPressureEquation or SaturationPressure if (merge_saturation_pressure and variables->component_has_gas(0)) { m_saturation_equation = make_unique( 0, the_mesh, variables->get_saturation_pressure_variables(), constraints, variables->get_aqueous_scaling(0) ); m_merged_gas[0] = true; opts = &(static_cast( m_saturation_equation.get())->get_options()); } else { m_saturation_equation = make_unique( 0, the_mesh, variables->get_saturation_variables(), constraints, variables->get_aqueous_scaling(0) ); opts = &(static_cast( m_saturation_equation.get())->get_options()); } opts->residuals_tolerance = 1e-8; opts->absolute_tolerance = 1e-12; opts->step_tolerance = 1e-12; opts->threshold_stationary_point = 1e-12; opts->maximum_iterations = 500; opts->sparse_solver = sparse_solvers::SparseSolver::SparseLU; opts->quasi_newton = 3; opts->maximum_step_length = 0.1; opts->max_iterations_at_max_length = 5000; const index_t size = raw_db->nb_aqueous_components() + variables->nb_gas(); m_equation_list.reserve(size); // Liquid aqueous diffusion-advection // ================================== for (index_t id: raw_db->range_aqueous_component()) { if (merge_aqueous_pressure and variables->component_has_gas(id)) { m_equation_list.emplace_back( make_unique( id, the_mesh, variables->get_liquid_gas_aqueous_variables(id), constraints, variables->get_aqueous_scaling(id)) ); m_merged_gas[id] = true; } else { m_equation_list.emplace_back( make_unique( id, the_mesh, variables->get_liquid_aqueous_component_variables(id), constraints, variables->get_aqueous_scaling(id)) ); } id_aqueous_task(id) = m_equation_list.size()-1; dfpmsolver::ParabolicDriverOptions& opts = *get_aqueous_options(id); opts.maximum_iterations = 500; opts.residuals_tolerance = 1e-8; opts.absolute_tolerance = 1e-12; opts.step_tolerance = 1e-12; opts.threshold_stationary_point = 1e-12; opts.sparse_solver = sparse_solvers::SparseSolver::SparseLU; opts.maximum_step_length= 1e6; } // Water partial pressure // ====================== // // Depending on the saturation equation chosen we may or may not include // this equations if (variables->component_has_gas(0) and (not m_merged_gas[0])) { m_equation_list.emplace_back( make_unique(0, the_mesh, variables->get_pressure_variables(0), constraints, variables->get_gaseous_scaling(0) )); id_gas_task(0) = m_equation_list.size()-1; dfpmsolver::ParabolicDriverOptions& opts = *get_gas_options(0); opts.maximum_iterations = 500; opts.residuals_tolerance = 1e-8; opts.absolute_tolerance = 1e-12; opts.step_tolerance = 1e-12; opts.threshold_stationary_point = 1e-12; opts.sparse_solver = sparse_solvers::SparseSolver::SparseLU; opts.maximum_step_length= 1e6; } // Gaseous diffusion for (index_t id: raw_db->range_aqueous_component()) { if (variables->component_has_gas(id) and (not m_merged_gas[id])) { m_equation_list.emplace_back( make_unique(id, the_mesh, variables->get_pressure_variables(id), constraints, variables->get_gaseous_scaling(id) )); id_gas_task(id) = m_equation_list.size()-1; dfpmsolver::ParabolicDriverOptions& opts = *get_gas_options(id); opts.maximum_iterations = 500; opts.residuals_tolerance = 1e-8; opts.absolute_tolerance = 1e-12; opts.step_tolerance = 1e-12; opts.threshold_stationary_point = 1e-12; opts.sparse_solver = sparse_solvers::SparseSolver::SparseLU; opts.maximum_step_length= 1e6; } } } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_saturation_options() { dfpmsolver::ParabolicDriverOptions* opts = nullptr; if (m_merged_gas[0]) { opts = &static_cast( m_saturation_equation.get())->get_options(); } else { opts = &static_cast( m_saturation_equation.get())->get_options(); } return opts; } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_aqueous_options( index_t component) { dfpmsolver::ParabolicDriverOptions* opts = nullptr; auto id = id_aqueous_task(component); if (id != no_equation) { if (m_merged_gas[component]) { opts = &static_cast( m_equation_list[id].get())->get_options(); } else { opts = &static_cast( m_equation_list[id].get())->get_options(); } } return opts; } dfpmsolver::ParabolicDriverOptions* UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_gas_options( index_t component) { dfpmsolver::ParabolicDriverOptions* opts = nullptr; auto id = id_gas_task(component); if (id != no_equation) { opts = &static_cast( m_equation_list[id].get())->get_options(); } return opts; } // Residuals // ========= scalar_t UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_residual( UnsaturatedVariables * const vars ) { auto sum = m_saturation_equation->compute_squared_residual(vars); #if SPECMICP_USE_OPENMP #pragma omp parallel for \ reduction(+: sum) #endif for (std::size_t ideq=0; ideqcompute_squared_residual(vars); } auto norm = std::sqrt(sum); //std::cout << "; " << norm << std::endl; return norm; } scalar_t UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_residual_0( UnsaturatedVariables * const vars ) { return m_norm_0; } scalar_t UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::get_update( UnsaturatedVariables * const vars ) { scalar_t sum = m_saturation_equation->compute_squared_update(vars); #if SPECMICP_USE_OPENMP #pragma omp parallel for \ reduction(+: sum) #endif for (std::size_t ideq=0; ideqcompute_squared_update(vars); } return std::sqrt(sum); } // Solving the equations // ===================== void UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::initialize_timestep( scalar_t dt, UnsaturatedVariables * const vars ) { save_dt(dt); vars->get_advection_flux().set_zero(); m_saturation_equation->initialize_timestep(dt, vars); scalar_t sum = m_saturation_equation->compute_squared_residual_0(vars); #if SPECMICP_USE_OPENMP #pragma omp parallel for \ reduction(+: sum) #endif for (std::size_t ideq=0; ideqinitialize_timestep(dt, vars); sum += task->compute_squared_residual_0(vars); } m_norm_0 = 1.0;//std::sqrt(sum); } solver::StaggerReturnCode UnsaturatedTransportStagger::UnsaturatedTransportStaggerImpl::restart_timestep( UnsaturatedVariables * const vars ) { dfpmsolver::ParabolicDriverReturnCode retcode; bool flag_fail = false; bool flag_error_minimized = false; // Saturation equation retcode = m_saturation_equation->restart_timestep(vars); if (dfpmsolver::has_failed(retcode)) { WARNING << "Failed to solve saturation equation, return code :" << to_string(retcode); flag_fail = true; } if (retcode == dfpmsolver::ParabolicDriverReturnCode::ErrorMinimized) flag_error_minimized = true; // Other equation if (not flag_fail) { vars->set_relative_variables(); #if SPECMICP_USE_OPENMP #pragma omp parallel for \ reduction(or: flag_fail) \ reduction(and: flag_error_minimized) #endif for (std::size_t ideq=0; ideqrestart_timestep(vars); if (dfpmsolver::has_failed(retcode)) { WARNING << "Equation of type '" << to_string(task->equation_type()) << "' for component " << task->component() << " has failed with return code : " << to_string(retcode); flag_fail = true; } flag_error_minimized = flag_error_minimized and (retcode == dfpmsolver::ParabolicDriverReturnCode::ErrorMinimized); } } // Return code solver::StaggerReturnCode return_code = solver::StaggerReturnCode::ResidualMinimized; if (flag_error_minimized) { return_code = solver::StaggerReturnCode::ErrorMinimized; } if (flag_fail) return_code = solver::StaggerReturnCode::UnknownError; return return_code; } // ================================ // // // // Helper functions // // // // ================================ // static std::string to_string(EquationType eq_type) { std::string str; switch (eq_type) { case EquationType::LiquidAqueous: str = "Liquid advection-diffusion"; break; case EquationType::Pressure: str = "Gaseous diffusion"; break; case EquationType::Saturation: str = "Saturation equation"; break; default: str = "Unknown equation"; break; } return str; } std::string to_string(dfpmsolver::ParabolicDriverReturnCode retcode) { using RetCode = dfpmsolver::ParabolicDriverReturnCode; std::string str; switch (retcode) { case RetCode::ResidualMinimized: str = "ResidualMinimized"; break; case RetCode::ErrorMinimized: str = "ErrorMinimized"; break; case RetCode::NotConvergedYet: str = "NotConvergedYet"; break; case RetCode::StationaryPoint: str = "StationaryPoint"; break; case RetCode::ErrorLinearSystem: str = "ErrorLinearSystem"; break; case RetCode::MaxStepTakenTooManyTimes: str = "MaxStepTakenTooManyTimes"; break; case RetCode::MaxIterations: str = "MaxIterations"; break; case RetCode::LinesearchFailed: str = "LinesearchFailed"; default: str = "Unknown return code"; break; } return str; } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/transport_stagger.hpp b/src/reactmicp/systems/unsaturated/transport_stagger.hpp index 5e23f75..7c9fd0a 100644 --- a/src/reactmicp/systems/unsaturated/transport_stagger.hpp +++ b/src/reactmicp/systems/unsaturated/transport_stagger.hpp @@ -1,146 +1,148 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_TRANSPORTSTAGGER_HPP #define SPECMICP_REACTMICP_UNSATURATED_TRANSPORTSTAGGER_HPP //! \file unsaturated/transport_stagger.hpp //! \brief The unsaturated transport stagger #include "../../solver/staggers_base/transport_stagger_base.hpp" #include "../../../utils/pimpl_ptr.hpp" namespace specmicp { namespace dfpmsolver { struct ParabolicDriverOptions; } //end namespace dfpmsolver namespace reactmicp { namespace systems { namespace unsaturated { class UnsaturatedVariables; class TransportConstraints; class SPECMICP_DLL_PUBLIC UnsaturatedTransportStagger: public solver::TransportStaggerBase { using VariablesBase = solver::VariablesBase; using StaggerReturnCode = solver::StaggerReturnCode; public: UnsaturatedTransportStagger( std::shared_ptr variables, const TransportConstraints& constraints, bool merge_saturation_pressure=false, bool merge_aqueous_pressure=false ); ~UnsaturatedTransportStagger(); //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the first residual may be computed, the predictor saved, ... //! \param dt the duration of the timestep //! \param var shared_ptr to the variables void initialize_timestep(scalar_t dt, VariablesBase * const var) override; //! \brief Solve the equation for the timetep //! //! \param var shared_ptr to the variables StaggerReturnCode restart_timestep(VariablesBase * const var) override; //! \brief Compute the residuals norm //! //! \param var shared_ptr to the variables scalar_t get_residual(VariablesBase * const var) override; //! \brief Compute the residuals norm //! //! \param var shared_ptr to the variables scalar_t get_residual_0(VariablesBase * const var) override; //! \brief Obtain the norm of the step size //! //! This is used to check if the algorithm has reach a stationary points. //! It should look like : return main_variables.norm() //! //! \param var shared_ptr to the variables scalar_t get_update(VariablesBase * const var) override; //! Return options of saturation equation //! //! \return the options or nullptr if the equation does not exist dfpmsolver::ParabolicDriverOptions* get_saturation_options(); //! return options of aqueous transport equation //! //! \return the options or nullptr if the equation does not exist dfpmsolver::ParabolicDriverOptions* get_aqueous_options(index_t component); //! return options of gas transport equation //! //! \return the options or nullptr if the equation does not exist dfpmsolver::ParabolicDriverOptions* get_gas_options(index_t component); private: // The implementation details class UnsaturatedTransportStaggerImpl; utils::pimpl_ptr m_impl; }; //! \brief Return a shared pointer to the transport stagger //! //! \param variables shared_pointer to the unsaturated variables //! \param constraints The transport constraints //! \param merge_saturation_pressure true if the saturation //! and water vapor pressure equations must be merged inline std::shared_ptr unsaturated_transport_stagger( std::shared_ptr variables, const TransportConstraints& constraints, bool merge_saturation_pressure = false, bool merge_aqueous_pressure = false ) { return std::make_shared( variables, constraints, merge_saturation_pressure, merge_aqueous_pressure ); } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_TRANSPORTSTAGGER_HPP diff --git a/src/reactmicp/systems/unsaturated/types_fwd.hpp b/src/reactmicp/systems/unsaturated/types_fwd.hpp index 6b83b1f..33f7cc0 100644 --- a/src/reactmicp/systems/unsaturated/types_fwd.hpp +++ b/src/reactmicp/systems/unsaturated/types_fwd.hpp @@ -1,68 +1,70 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_TYPESFWD_HPP #define SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_TYPESFWD_HPP //! \file types_fwd.hpp //! \brief Types and forward declarations common to the unsaturated //! system interface #include "../../../types.hpp" #include #include namespace specmicp { namespace reactmicp { // forward declaration namespace solver { class VariablesBase; using VariablesBasePtr = std::shared_ptr; } //end namespace solver namespace systems { namespace unsaturated { //! The main set of variables class UnsaturatedVariables; using UnsaturatedVariablesPtr = std::shared_ptr; //! \brief A function dependent on the saturation using user_model_saturation_f = std::function; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_UNSATURATED_TYPESFWD_HPP diff --git a/src/reactmicp/systems/unsaturated/variables.cpp b/src/reactmicp/systems/unsaturated/variables.cpp index 9f33614..c5a1512 100644 --- a/src/reactmicp/systems/unsaturated/variables.cpp +++ b/src/reactmicp/systems/unsaturated/variables.cpp @@ -1,398 +1,400 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "variables.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "variables_box.hpp" #include "../../../utils/log.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { // =================== // List main variables // =================== ListMainVariable::ListMainVariable(index_t nb_vars, index_t nb_nodes) { variables.reserve(nb_vars); variables.emplace_back(make_unique(nb_nodes)); variables.emplace_back(nullptr); for (index_t i=2; i(nb_nodes)); } } ListMainVariable::ListMainVariable( index_t nb_vars, index_t nb_nodes, std::vector to_init ) { variables.reserve(nb_vars); for (const auto& is_present: to_init) { if (is_present) { variables.emplace_back(make_unique(nb_nodes)); } else { variables.emplace_back(nullptr); } } } //! \brief Reset the variables void ListMainVariable::reset() { //if (variables[0] != nullptr) // variables[0]->reset(); for (vector_type::size_type i=0; ireset(); } } void ListMainVariable::hard_reset(index_t component, index_t nb_nodes) { specmicp_assert(component >= 0 and (unsigned) component < variables.size()); if (nb_nodes == 0) variables[component].reset(nullptr); else variables[component].reset(new MainVariable(nb_nodes)); } // ============== // Variables box // ============== SaturationVariableBox::SaturationVariableBox(UnsaturatedVariables& vars): liquid_saturation(vars.m_liquid_var.water()), solid_concentration(vars.m_solid_var.water()), vapor_pressure(vars.m_gas_var.water()), aqueous_concentration(vars.m_water_aq_concentration), porosity(vars.m_porosity), liquid_permeability(vars.m_liquid_permeability), liquid_diffusivity(vars.m_liquid_diffusivity), relative_liquid_permeability(vars.m_relative_liquid_permeability), relative_liquid_diffusivity(vars.m_relative_liquid_diffusivity), capillary_pressure(vars.m_capillary_pressure), advection_flux(vars.m_advection_flux), constants(vars.m_constants), capillary_pressure_f(vars.m_capillary_pressure_f), relative_liquid_permeability_f(vars.m_relative_liquid_permeability_f), relative_liquid_diffusivity_f(vars.m_relative_liquid_diffusivity_f) {} SaturationPressureVariableBox::SaturationPressureVariableBox( UnsaturatedVariables& vars): binary_diffusion_coefficient(vars.get_binary_gas_diffusivity(0)), liquid_saturation(vars.m_liquid_var.water()), partial_pressure(vars.get_pressure_main_variables(0)), solid_concentration(vars.m_solid_var.water()), aqueous_concentration(vars.m_water_aq_concentration), porosity(vars.m_porosity), liquid_permeability(vars.m_liquid_permeability), liquid_diffusivity(vars.m_liquid_diffusivity), relative_liquid_permeability(vars.m_relative_liquid_permeability), relative_liquid_diffusivity(vars.m_relative_liquid_diffusivity), capillary_pressure(vars.m_capillary_pressure), resistance_gas_diffusivity(vars.m_resistance_gas_diffusivity), relative_gas_diffusivity(vars.m_relative_gas_diffusivity), advection_flux(vars.m_advection_flux), constants(vars.m_constants), capillary_pressure_f(vars.m_capillary_pressure_f), relative_liquid_permeability_f(vars.m_relative_liquid_permeability_f), relative_liquid_diffusivity_f(vars.m_relative_liquid_diffusivity_f), relative_gas_diffusivity_f(vars.m_relative_gas_diffusivity_f), partial_pressure_f(vars.m_vapor_pressure_f) {} LiquidAqueousComponentVariableBox::LiquidAqueousComponentVariableBox( UnsaturatedVariables& vars, index_t component ): aqueous_concentration(vars.m_liquid_var.aqueous_component(component)), solid_concentration(vars.m_solid_var.aqueous_component(component)), partial_pressure(vars.get_pressure_main_variables(component)), saturation(vars.m_liquid_var.water()), porosity(vars.m_porosity), liquid_diffusivity(vars.m_liquid_diffusivity), relative_liquid_diffusivity(vars.m_relative_liquid_diffusivity), advection_flux(vars.m_advection_flux), constants(vars.m_constants) {} LiquidGasAqueousVariableBox::LiquidGasAqueousVariableBox( UnsaturatedVariables& vars, index_t component ): LiquidAqueousComponentVariableBox(vars, component), binary_diffusion_coefficient(vars.get_binary_gas_diffusivity(component)), resistance_gas_diffusivity(vars.m_resistance_gas_diffusivity), relative_gas_diffusivity(vars.m_relative_gas_diffusivity) {} PressureVariableBox::PressureVariableBox( UnsaturatedVariables& vars, index_t component ): binary_diffusion_coefficient(vars.get_binary_gas_diffusivity(component)), partial_pressure(vars.get_pressure_main_variables(component)), liquid_saturation(vars.m_liquid_var.water()), porosity(vars.m_porosity), resistance_gas_diffusivity(vars.m_resistance_gas_diffusivity), relative_gas_diffusivity(vars.m_relative_gas_diffusivity), constants(vars.m_constants) {} void ConstantBox::scale(units::LengthUnit length_unit) { scalar_t scaling_factor = units::scaling_factor(length_unit); //viscosity_liquid_water *= 1.0/scaling_factor; rt /= std::pow(scaling_factor, 3); //total_pressure *= 1.0/scaling_factor; } // ====================== // Unsaturated variables // ====================== namespace internal { //! \brief Find the correspond gas id for a component with gas static index_t get_id_gas(database::RawDatabasePtr the_database, index_t component) { index_t id = no_species; for (auto gas: the_database->range_gas()) { const scalar_t nu = the_database->nu_gas(gas, component); if (nu == 0.0) continue; if (nu != 1.0) { ERROR << "Database not in the good format" << "; expect : gas <=> component \n" << "component : " << the_database->get_label_component(component) << " \n" << "gas : " << the_database->get_label_gas(gas) << "."; throw std::runtime_error("Badly formatted database"); } else { id = gas; } } if (id == no_species) { ERROR << "No corresponding gas in the database for component : " << the_database->get_label_component(component); throw std::runtime_error("Badly formatted database"); } return id; } } //end namespace internal UnsaturatedVariables::UnsaturatedVariables( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, std::vector has_gas ): database::DatabaseHolder(the_database), m_mesh(the_mesh), m_has_gas(has_gas), m_id_gas(the_database->nb_component(), no_species), // main var m_liquid_var(the_database->nb_component(),the_mesh->nb_nodes()), m_gas_var(the_database->nb_component(),the_mesh->nb_nodes(), has_gas), m_solid_var(the_database->nb_component(),the_mesh->nb_nodes()), // chem sol m_chem_sol(the_mesh->nb_nodes()), // secondary vars m_porosity(the_mesh->nb_nodes()), m_water_aq_concentration(the_mesh->nb_nodes()), m_liquid_permeability(the_mesh->nb_nodes()), m_relative_liquid_permeability(the_mesh->nb_nodes()), m_liquid_diffusivity(the_mesh->nb_nodes()), m_relative_liquid_diffusivity(the_mesh->nb_nodes()), m_binary_gas_diffusivity(Vector::Zero(the_database->nb_component())), m_resistance_gas_diffusivity(the_mesh->nb_nodes()), m_relative_gas_diffusivity(the_mesh->nb_nodes()), m_capillary_pressure(the_mesh->nb_nodes()), m_advection_flux(the_mesh->nb_nodes()), m_aqueous_scaling(Vector::Ones(the_database->nb_component())), m_gaseous_scaling(Vector::Ones(the_database->nb_component())) { specmicp_assert(has_gas.size() == (unsigned) the_database->nb_component()); // // trick to avoid more branching in equations : m_gas_var.hard_reset(1, the_mesh->nb_nodes()); for (auto component: the_database->range_aqueous_component()) { if (has_gas[component]) { m_id_gas[component] = internal::get_id_gas(the_database, component); } } } UnsaturatedVariables::UnsaturatedVariables( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, std::vector has_gas, units::LengthUnit length_unit): UnsaturatedVariables(the_mesh, the_database, has_gas) { m_constants.scale(length_unit); } void UnsaturatedVariables::reset_main_variables() { m_liquid_var.reset(); m_gas_var.reset(); m_solid_var.reset(); m_porosity.variable = m_porosity.predictor; m_porosity.velocity.setZero(); } SaturationVariableBox UnsaturatedVariables::get_saturation_variables() { return SaturationVariableBox(*this); } SaturationPressureVariableBox UnsaturatedVariables::get_saturation_pressure_variables() { return SaturationPressureVariableBox(*this); } PressureVariableBox UnsaturatedVariables::get_vapor_pressure_variables() { return PressureVariableBox(*this, 0); } LiquidAqueousComponentVariableBox UnsaturatedVariables::get_liquid_aqueous_component_variables( index_t component ) { return LiquidAqueousComponentVariableBox(*this, component); } LiquidGasAqueousVariableBox UnsaturatedVariables::get_liquid_gas_aqueous_variables( index_t component ) { return LiquidGasAqueousVariableBox(*this, component); } PressureVariableBox UnsaturatedVariables::get_pressure_variables( index_t component ) { return PressureVariableBox(*this, component); } MainVariable& UnsaturatedVariables::get_pressure_main_variables(index_t component) { if (component_has_gas(component)) { specmicp_assert(m_gas_var(component) != nullptr); return *m_gas_var(component); } else return *m_gas_var(1); // a zero var..., this is a trick to always get a valid info } index_t UnsaturatedVariables::nb_gas() { return std::count(m_has_gas.begin(), m_has_gas.end(), true); } void UnsaturatedVariables::set_relative_variables( index_t node ) { const scalar_t saturation = m_liquid_var.water().variable(node); m_relative_liquid_diffusivity(node) = m_relative_liquid_diffusivity_f(node, saturation); m_relative_gas_diffusivity(node) = m_relative_gas_diffusivity_f(node, saturation); m_relative_liquid_permeability(node) = m_relative_liquid_permeability_f(node, saturation); m_capillary_pressure(node) = m_capillary_pressure_f(node, saturation); } void UnsaturatedVariables::set_relative_variables() { for (index_t node: m_mesh->range_nodes()) { set_relative_variables(node); } } void UnsaturatedVariables::set_vapor_pressure(index_t node) { if (component_has_gas(0)) { const scalar_t saturation = m_liquid_var.water().variable(node); m_gas_var(0)->variable(node) = m_vapor_pressure_f(node, saturation); } } } //end namespace unsatura } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/variables.hpp b/src/reactmicp/systems/unsaturated/variables.hpp index 0a31b8c..e48d263 100644 --- a/src/reactmicp/systems/unsaturated/variables.hpp +++ b/src/reactmicp/systems/unsaturated/variables.hpp @@ -1,418 +1,420 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_VARIABLES_HPP #define SPECMICP_REACTMICP_UNSATURATED_VARIABLES_HPP //! \file unsaturated/variables.hpp //! \name Variables for the unsaturated system #include "types_fwd.hpp" #include "../../../dfpm/meshes/mesh1d.hpp" #include "../../../database/database_holder.hpp" #include "variables_sub.hpp" #include "../../solver/staggers_base/variables_base.hpp" #include namespace specmicp { namespace reactmicp { namespace systems { //! \namespace unsaturated //! \brief The unsaturated system //! //! The system solve the transport reactive in unsaturated porous medium namespace unsaturated { // forward declarations // declared in variables_box.hpp struct SaturationVariableBox; struct SaturationPressureVariableBox; struct PressureVariableBox; struct LiquidAqueousComponentVariableBox; struct LiquidGasAqueousVariableBox; //! \brief The unsaturated variables //! //! This class contains all the variables for the unsaturated system //! //! Note : it should be initialized using the ::VariablesInterface class. class SPECMICP_DLL_PUBLIC UnsaturatedVariables: public database::DatabaseHolder, public solver::VariablesBase { public: //! \brief Constructor //! \internal UnsaturatedVariables( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, std::vector has_gas); //! \brief Constructor //! \internal UnsaturatedVariables( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, std::vector has_gas, units::LengthUnit length_unit); //! \brief Reset the main variables in case of failure void reset_main_variables() override; //! \brief Return the number of governing equations //! //! The governing equations are the transport equations index_t nb_governing_equations() { return get_database()->nb_aqueous_components()+1; } //! \brief Return the number of nodes index_t nb_nodes() { return m_mesh->nb_nodes(); } //! \brief Return the mesh mesh::Mesh1DPtr get_mesh() { return m_mesh; } //! \brief Return true if a component has a gas equation //! \param component water or aqueous component bool component_has_gas(index_t component) { specmicp_assert_component_bounds(component, get_database()); return m_has_gas[component]; } //! \brief Return the number of gas in the system index_t nb_gas(); // Variables Box // ============= //! \name VariableBox //! \brief This set of variables are passed to the equations //! //! They contain all the variables a governing equation should need //! @{ //! \brief Return the variables for the saturation equation SaturationVariableBox get_saturation_variables(); //! \brief Return the variables for the saturation-pressure equation SaturationPressureVariableBox get_saturation_pressure_variables(); //! \brief Return the variables for the vapor pressure equation PressureVariableBox get_vapor_pressure_variables(); //! \brief Return the variables for the liquid transport of an //! aqueous component LiquidAqueousComponentVariableBox get_liquid_aqueous_component_variables( index_t component); //! \brief Return the variables for the liquid and gas transport of an //! aqueous component LiquidGasAqueousVariableBox get_liquid_gas_aqueous_variables( index_t component); //! \brief Return the variables for the pressure diffusion equation //! //! Valid for water vapor or the gas corresponding to an aqueous component PressureVariableBox get_pressure_variables(index_t component); //! @} // User model // ========== //! \name User models //! \brief Models given by the user to compute saturated-dependant variables //! //! A model is a function taking a node and the saturation as the argument //! @{ //! \brief Set the capillary pressure model void set_capillary_pressure_model(user_model_saturation_f func) { m_capillary_pressure_f = func; } //! \brief Return the capillary pressure model user_model_saturation_f get_capillary_pressure_model() { return m_capillary_pressure_f; } //! \brief Set the vapor pressure model void set_vapor_pressure_model(user_model_saturation_f func) { m_vapor_pressure_f = func; } //! \brief Return the vapor pressure model user_model_saturation_f get_vapor_pressure_model() { return m_vapor_pressure_f; } //! \brief Set the relative liquid permeability model void set_relative_liquid_permeability_model(user_model_saturation_f func) { m_relative_liquid_permeability_f = func; } //! \brief Set the relative liquid diffusivity model void set_relative_liquid_diffusivity_model(user_model_saturation_f func) { m_relative_liquid_diffusivity_f = func; } //! \brief Set the relative gas diffusivity model void set_relative_gas_diffusivity_model(user_model_saturation_f func) { m_relative_gas_diffusivity_f = func; } //! \brief Set the relative variables at 'node' void set_relative_variables(index_t node); //! \brief Set the relative variables void set_relative_variables(); //! \brief Set the partial pressure at 'node' void set_vapor_pressure(index_t node); //! @} // Variables Getter // ================ //! \name Variables Getter //! \brief Return the variables //! @{ //! \brief Return a reference to the porosity variables SecondaryTransientVariable& get_porosity() { return m_porosity;} //! \brief Return a reference to the water aq. concentration variables SecondaryTransientVariable& get_water_aqueous_concentration() { return m_water_aq_concentration;} //! \brief Return a reference to the liquid permeability SecondaryVariable& get_liquid_permeability() { return m_liquid_permeability; } //! \brief Return a reference to the capillary pressure SecondaryVariable& get_capillary_pressure() { return m_capillary_pressure; } //! \brief Return a reference to the relative liquid permeability SecondaryVariable& get_relative_liquid_permeability() { return m_relative_liquid_permeability; } //! \brief Return a reference to the liquid diffusivity SecondaryVariable& get_liquid_diffusivity() { return m_liquid_diffusivity; } //! \brief Return a reference to the relative liquid diffusivity SecondaryVariable& get_relative_liquid_diffusivity() { return m_relative_liquid_diffusivity; } scalar_t & get_binary_gas_diffusivity(index_t component) { return m_binary_gas_diffusivity(component); } //! \brief Return a reference to the gas diffusivity resistance factor SecondaryVariable& get_resistance_gas_diffusivity() { return m_resistance_gas_diffusivity; } //! \brief Return a reference to the relative gas diffusivity SecondaryVariable& get_relative_gas_diffusivity() { return m_relative_gas_diffusivity; } SecondaryVariable& get_advection_flux() { return m_advection_flux; } //! \brief Return the liquid saturation MainVariable& get_liquid_saturation() { return m_liquid_var.water(); } //! \brief Return the variables corresponding to the pressure //! \param component water or aqueous component MainVariable& get_pressure_main_variables(index_t component); //! \brief Return the aqueous concentration of an aqueous component MainVariable& get_aqueous_concentration(index_t aq_component) { specmicp_assert(aq_component >= 2 and aq_component < get_database()->nb_component()); return m_liquid_var.aqueous_component(aq_component); } //! \brief Return the solid variables MainVariable& get_solid_concentration(index_t component) { specmicp_assert_component_bounds(component, get_database()); return m_solid_var.component(component); } //! \brief Return the R*T product //! //! R : ideal gas constant //! T : temperature scalar_t get_rt() {return m_constants.rt;} //! \brief return the total pressure scalar_t get_total_pressure() {return m_constants.total_pressure;} //! \brief return the id of a gas scalar_t get_id_gas(index_t component) { specmicp_assert_component_bounds(component, get_database()); return m_id_gas[component]; } AdimensionalSystemSolution& get_adim_solution(index_t node) { return m_chem_sol.solution(node); } void set_adim_solution(index_t node, const AdimensionalSystemSolution& new_solution ) { m_chem_sol.update_solution(node, new_solution); } //! @} //! \name Scaling //! \brief Scaling of equations //! //! @{ //! \brief Return the scaling factor for aqueous equation of 'component' scalar_t get_aqueous_scaling(index_t component) { return m_aqueous_scaling(component); } //! \brief set the scaling factor for aqueous equation of 'component' void set_aqueous_scaling(index_t component, scalar_t value) { m_aqueous_scaling(component) = value; } //! \brief Return the scaling factor for aqueous equation of 'component' scalar_t get_gaseous_scaling(index_t component) { return m_gaseous_scaling(component); } //! \brief set the scaling factor for aqueous equation of 'component' void set_gaseous_scaling(index_t component, scalar_t value) { m_gaseous_scaling(component) = value; } //! @} private: mesh::Mesh1DPtr m_mesh; std::vector m_has_gas; std::vector m_id_gas; // main variables // -------------- ListMainVariable m_liquid_var; ListMainVariable m_gas_var; ListMainVariable m_solid_var; // chemistry // --------- ChemistrySolutions m_chem_sol; // secondary variables // ------------------- SecondaryTransientVariable m_porosity; SecondaryTransientVariable m_water_aq_concentration; SecondaryVariable m_liquid_permeability; SecondaryVariable m_relative_liquid_permeability; SecondaryVariable m_liquid_diffusivity; SecondaryVariable m_relative_liquid_diffusivity; Vector m_binary_gas_diffusivity; SecondaryVariable m_resistance_gas_diffusivity; SecondaryVariable m_relative_gas_diffusivity; SecondaryVariable m_capillary_pressure; SecondaryVariable m_advection_flux; // scaled constants // ---------------- ConstantBox m_constants; // user models // ----------- user_model_saturation_f m_capillary_pressure_f {nullptr}; user_model_saturation_f m_vapor_pressure_f {nullptr}; user_model_saturation_f m_relative_liquid_permeability_f {nullptr}; user_model_saturation_f m_relative_liquid_diffusivity_f {nullptr}; user_model_saturation_f m_relative_gas_diffusivity_f {nullptr}; // vector of scaling Vector m_aqueous_scaling; Vector m_gaseous_scaling; // These struct are declared as friends, // To make their initialisation easier // (initialisation of referenece, and const reference) friend struct SaturationVariableBox; friend struct SaturationPressureVariableBox; friend struct PressureVariableBox; friend struct LiquidAqueousComponentVariableBox; friend struct LiquidGasAqueousVariableBox; }; //! \brief Shared pointer the unsaturated variables using UnsaturatedVariablesPtr = std::shared_ptr; //! \brief Cast from base variables inline UnsaturatedVariablesPtr cast_from_base( std::shared_ptr ptr) { return std::static_pointer_cast(ptr); } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_VARIABLES_HPP diff --git a/src/reactmicp/systems/unsaturated/variables_box.hpp b/src/reactmicp/systems/unsaturated/variables_box.hpp index 3fbc4c5..93664a9 100644 --- a/src/reactmicp/systems/unsaturated/variables_box.hpp +++ b/src/reactmicp/systems/unsaturated/variables_box.hpp @@ -1,209 +1,211 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_VARIABLESBOX #define SPECMICP_REACTMICP_UNSATURATED_VARIABLESBOX //! \file unsaturated/variables_box.hpp //! \brief Set of variables passed to the equations #include "../../../types.hpp" #include "variables_sub.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { //! \brief Base class for a box of variables //! \internal struct SPECMICP_DLL_LOCAL BaseVariableBox { }; //! \brief Variables box for the saturation equation //! \internal struct SPECMICP_DLL_LOCAL SaturationVariableBox: public BaseVariableBox { MainVariable& liquid_saturation; const MainVariable& solid_concentration; const MainVariable& vapor_pressure; const SecondaryTransientVariable& aqueous_concentration; const SecondaryTransientVariable& porosity; const SecondaryVariable& liquid_permeability; const SecondaryVariable& liquid_diffusivity; SecondaryVariable& relative_liquid_permeability; SecondaryVariable& relative_liquid_diffusivity; SecondaryVariable& capillary_pressure; SecondaryVariable& advection_flux; const ConstantBox& constants; user_model_saturation_f capillary_pressure_f; user_model_saturation_f relative_liquid_permeability_f; user_model_saturation_f relative_liquid_diffusivity_f; //! //! \brief SaturationVariableBox //! \param vars The main set of variables //! SaturationVariableBox(UnsaturatedVariables& vars); // implementation fo the constructor is in variables.cpp }; //! \brief Variables box for the saturation equation //! \internal struct SPECMICP_DLL_LOCAL SaturationPressureVariableBox: public BaseVariableBox { scalar_t binary_diffusion_coefficient; MainVariable& liquid_saturation; MainVariable& partial_pressure; const MainVariable& solid_concentration; const SecondaryTransientVariable& aqueous_concentration; const SecondaryTransientVariable& porosity; const SecondaryVariable& liquid_permeability; const SecondaryVariable& liquid_diffusivity; SecondaryVariable& relative_liquid_permeability; SecondaryVariable& relative_liquid_diffusivity; SecondaryVariable& capillary_pressure; const SecondaryVariable& resistance_gas_diffusivity; const SecondaryVariable& relative_gas_diffusivity; SecondaryVariable& advection_flux; const ConstantBox& constants; user_model_saturation_f capillary_pressure_f; user_model_saturation_f relative_liquid_permeability_f; user_model_saturation_f relative_liquid_diffusivity_f; user_model_saturation_f relative_gas_diffusivity_f; user_model_saturation_f partial_pressure_f; //! //! \brief SaturationVariableBox //! \param vars The main set of variables //! SaturationPressureVariableBox(UnsaturatedVariables& vars); // implementation fo the constructor is in variables.cpp }; //! \brief Set of variables for the liquid transport equation of an aqueous component //! \internal struct SPECMICP_DLL_LOCAL LiquidAqueousComponentVariableBox: public BaseVariableBox { MainVariable& aqueous_concentration; const MainVariable& solid_concentration; const MainVariable& partial_pressure; const MainVariable& saturation; const SecondaryTransientVariable& porosity; const SecondaryVariable& liquid_diffusivity; const SecondaryVariable& relative_liquid_diffusivity; const SecondaryVariable& advection_flux; const ConstantBox& constants; //! //! \brief LiquidAqueousComponentVariableBox //! \param vars The main set of variables //! \param component an aqueous component //! LiquidAqueousComponentVariableBox(UnsaturatedVariables& vars, index_t component); // implementation fo the constructor is in variables.cpp }; //! \brief Set of variables for the liquid and gas transport equation of an //! aqueous component //! \internal struct SPECMICP_DLL_LOCAL LiquidGasAqueousVariableBox: public LiquidAqueousComponentVariableBox { scalar_t binary_diffusion_coefficient; const SecondaryVariable& resistance_gas_diffusivity; const SecondaryVariable& relative_gas_diffusivity; //! //! \brief LiquidAqueousComponentVariableBox //! \param vars The main set of variables //! \param component an aqueous component //! LiquidGasAqueousVariableBox(UnsaturatedVariables& vars, index_t component); // implementation fo the constructor is in variables.cpp }; //! \brief Set of variables for the gas transport equation of an aqueous component //! \internal struct SPECMICP_DLL_LOCAL PressureVariableBox: public BaseVariableBox { scalar_t binary_diffusion_coefficient; MainVariable& partial_pressure; const MainVariable& liquid_saturation; const SecondaryTransientVariable& porosity; const SecondaryVariable& resistance_gas_diffusivity; const SecondaryVariable& relative_gas_diffusivity; const ConstantBox& constants; //! //! \brief PressureVariableBox //! \param vars The main set of variables //! \param component The component (can be water) //! PressureVariableBox(UnsaturatedVariables& vars, index_t component); // implementation fo the constructor is in variables.cpp }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_VARIABLESBOX diff --git a/src/reactmicp/systems/unsaturated/variables_interface.cpp b/src/reactmicp/systems/unsaturated/variables_interface.cpp index e0fb6e3..695cea5 100644 --- a/src/reactmicp/systems/unsaturated/variables_interface.cpp +++ b/src/reactmicp/systems/unsaturated/variables_interface.cpp @@ -1,802 +1,804 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "variables_interface.hpp" #include "variables.hpp" #include "variables_box.hpp" #include "../../solver/staggers_base/variables_base.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "../../../utils/compat.hpp" #include "../../../utils/log.hpp" #include "../../../utils/value_checker.hpp" #include "../../../utils/vector_checker.hpp" #include // This is a boring class, with only small differences between // all the functions and variables. But, they make all the // difference at the end. The main purpose of the class is to // hide all the variables structure and only present a unified // interface to the user. // None of the structure defined in "variables_sub.hpp" should // be leaked outside this class namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { using namespace specmicp::vector_checker; // typedef // ------- using VariablesBase = solver::VariablesBase; using VariablesBasePtr = std::shared_ptr; // ================================= // // Declaration of the implementation // // ================================= // This class just store and retrieve variables group struct VariablesInterface::VariablesInterfaceImpl { UnsaturatedVariablesPtr m_vars; mesh::Mesh1DPtr m_mesh; database::RawDatabasePtr m_database; VariablesInterfaceImpl( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas, units::UnitsSet units_set = {} ); MainVariable& liquid_saturation() { return m_vars->get_liquid_saturation(); } const MainVariable& liquid_saturation() const { return m_vars->get_liquid_saturation(); } MainVariable& aqueous_concentration(index_t component) { return m_vars->get_aqueous_concentration(component); } const MainVariable& aqueous_concentration(index_t component) const { return m_vars->get_aqueous_concentration(component); } MainVariable& partial_pressure(index_t component) { if (not m_vars->component_has_gas(component)) { throw std::logic_error("Component has no associated gas"); } return m_vars->get_pressure_main_variables(component); } const MainVariable& partial_pressure(index_t component) const { return m_vars->get_pressure_main_variables(component); } MainVariable& solid_concentration(index_t component) { return m_vars->get_solid_concentration(component); } const MainVariable& solid_concentration(index_t component) const { return m_vars->get_solid_concentration(component); } SecondaryTransientVariable& porosity() { return m_vars->get_porosity(); } const SecondaryTransientVariable& porosity() const { return m_vars->get_porosity(); } SecondaryTransientVariable& water_aqueous_concentration() { return m_vars->get_water_aqueous_concentration(); } const SecondaryTransientVariable& water_aqueous_concentration() const { return m_vars->get_water_aqueous_concentration(); } SecondaryVariable& liquid_diffusivity() { return m_vars->get_liquid_diffusivity(); } const SecondaryVariable& liquid_diffusivity() const { return m_vars->get_liquid_diffusivity(); } SecondaryVariable& liquid_permeability() { return m_vars->get_liquid_permeability(); } const SecondaryVariable& liquid_permeability() const { return m_vars->get_liquid_permeability(); } scalar_t& binary_gas_diffusivity(index_t component) { return m_vars->get_binary_gas_diffusivity(component); } scalar_t binary_gas_diffusivity(index_t component) const { return m_vars->get_binary_gas_diffusivity(component); } SecondaryVariable& resistance_gas_diffusivity() { return m_vars->get_resistance_gas_diffusivity(); } const SecondaryVariable& resistance_gas_diffusivity() const { return m_vars->get_resistance_gas_diffusivity(); } SecondaryVariable& advection_flux() { return m_vars->get_advection_flux(); } const SecondaryVariable& advection_flux() const { return m_vars->get_advection_flux(); } VariablesValidity check_variables(); bool check_bounds(const Vector& to_check, scalar_t lower, scalar_t upper); VariablesValidity check_saturation(); VariablesValidity check_relative(); VariablesValidity check_porosity(); VariablesValidity check_transport_param(); }; // ================================= // // Implementation // // ================================= VariablesInterface::VariablesInterface( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas): m_impl(make_unique( the_mesh, the_database, component_with_gas)) { } VariablesInterface::VariablesInterface( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas, const units::UnitsSet& units_set ): m_impl(make_unique( the_mesh, the_database, component_with_gas, units_set)) { } VariablesInterface::VariablesInterfaceImpl::VariablesInterfaceImpl( mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas, units::UnitsSet units_set ): m_mesh(the_mesh), m_database(the_database) { std::vector comp_has_gas(the_database->nb_component(), false); for (auto component: component_with_gas) { comp_has_gas[component] = true; } m_vars = std::make_shared( the_mesh, the_database, comp_has_gas, units_set.length); } VariablesInterface::~VariablesInterface() = default; std::shared_ptr VariablesInterface::get_base_variables() { return std::static_pointer_cast(m_impl->m_vars); } std::shared_ptr VariablesInterface::get_variables() { return m_impl->m_vars; } UnsaturatedVariables* VariablesInterface::get_raw_variables() { return m_impl->m_vars.get(); } // Saturation const Vector& VariablesInterface::get_liquid_saturation() const { return m_impl->liquid_saturation().variable; } void VariablesInterface::set_liquid_saturation(index_t node, scalar_t value) { m_impl->liquid_saturation().variable(node) = value; m_impl->liquid_saturation().predictor(node) = value; } void VariablesInterface::set_liquid_saturation(const Vector& value) { m_impl->liquid_saturation().variable = value; m_impl->liquid_saturation().predictor = value; } void VariablesInterface::set_liquid_saturation(scalar_t value) { m_impl->liquid_saturation().variable.setConstant(value); m_impl->liquid_saturation().predictor.setConstant(value); } // Aqueous component concentration const Vector& VariablesInterface::get_aqueous_concentration(index_t component) const { return m_impl->aqueous_concentration(component).variable; } void VariablesInterface::set_aqueous_concentration(index_t component, index_t node, scalar_t value) { MainVariable& aq_conc = m_impl->aqueous_concentration(component); aq_conc.variable(node) = value; aq_conc.predictor(node) = value; } void VariablesInterface::set_aqueous_concentration(index_t component, const Vector& value) { MainVariable& aq_conc = m_impl->aqueous_concentration(component); aq_conc.variable = value; aq_conc.predictor = value; } void VariablesInterface::set_aqueous_concentration(index_t component, scalar_t value) { MainVariable& aq_conc = m_impl->aqueous_concentration(component); aq_conc.variable.setConstant(value); aq_conc.predictor.setConstant(value); } // Partial pressure const Vector& VariablesInterface::get_partial_pressure(index_t component) const { return m_impl->partial_pressure(component).variable; } void VariablesInterface::set_partial_pressure(index_t component, index_t node, scalar_t value) { MainVariable& comp_pressure = m_impl->partial_pressure(component); comp_pressure.variable(node) = value; comp_pressure.predictor(node) = value; } void VariablesInterface::set_partial_pressure(index_t component, const Vector& value) { MainVariable& comp_pressure = m_impl->partial_pressure(component); comp_pressure.variable = value; comp_pressure.predictor = value; } void VariablesInterface::set_partial_pressure(index_t component, scalar_t value) { MainVariable& comp_pressure = m_impl->partial_pressure(component); comp_pressure.variable.setConstant(value); comp_pressure.predictor.setConstant(value); } // Solid concentration const Vector& VariablesInterface::get_solid_concentration(index_t component) const { return m_impl->solid_concentration(component).variable; } void VariablesInterface::set_solid_concentration(index_t component, index_t node, scalar_t value) { MainVariable& solid_conc = m_impl->solid_concentration(component); solid_conc.variable(node) = value; solid_conc.predictor(node) = value; } void VariablesInterface::set_solid_concentration(index_t component, const Vector& value) { MainVariable& solid_conc = m_impl->solid_concentration(component); solid_conc.variable = value; solid_conc.predictor = value; } void VariablesInterface::set_solid_concentration(index_t component, scalar_t value) { MainVariable& solid_conc = m_impl->solid_concentration(component); solid_conc.variable.setConstant(value); solid_conc.predictor.setConstant(value); } // Porosity const Vector& VariablesInterface::get_porosity() const { return m_impl->porosity().variable; } void VariablesInterface::set_porosity(index_t node, scalar_t value) { m_impl->porosity().variable(node) = value; m_impl->porosity().predictor(node) = value; } void VariablesInterface::set_porosity(const Vector& value) { m_impl->porosity().variable = value; m_impl->porosity().predictor = value; } void VariablesInterface::set_porosity(scalar_t value) { m_impl->porosity().variable.setConstant(value); m_impl->porosity().predictor.setConstant(value); } // Water aqueous concentration const Vector& VariablesInterface::get_water_aqueous_concentration() const { return m_impl->water_aqueous_concentration().variable; } void VariablesInterface::set_water_aqueous_concentration(index_t node, scalar_t value) { m_impl->water_aqueous_concentration().variable(node) = value; m_impl->water_aqueous_concentration().predictor(node) = value; } void VariablesInterface::set_water_aqueous_concentration(const Vector& value) { m_impl->water_aqueous_concentration().variable = value; m_impl->water_aqueous_concentration().predictor = value; } void VariablesInterface::set_water_aqueous_concentration(scalar_t value) { m_impl->water_aqueous_concentration().variable.setConstant(value); m_impl->water_aqueous_concentration().predictor.setConstant(value); } // Liquid diffusion coefficient const Vector& VariablesInterface::get_liquid_diffusivity() const { return m_impl->liquid_diffusivity().variable; } void VariablesInterface::set_liquid_diffusivity(index_t node, scalar_t value) { m_impl->liquid_diffusivity().variable(node) = value; } void VariablesInterface::set_liquid_diffusivity(const Vector& value) { m_impl->liquid_diffusivity().variable = value; } void VariablesInterface::set_liquid_diffusivity(scalar_t value) { m_impl->liquid_diffusivity().variable.setConstant(value); } // Liquid permeability const Vector& VariablesInterface::get_liquid_permeability() const { return m_impl->liquid_permeability().variable; } void VariablesInterface::set_liquid_permeability(index_t node, scalar_t value) { m_impl->liquid_permeability().variable(node) = value; } void VariablesInterface::set_liquid_permeability(const Vector& value) { m_impl->liquid_permeability().variable = value; } void VariablesInterface::set_liquid_permeability(scalar_t value) { m_impl->liquid_permeability().variable.setConstant(value); } // Gas diffusivity scalar_t VariablesInterface::get_binary_gas_diffusivity( index_t component ) const { return m_impl->binary_gas_diffusivity(component); } void VariablesInterface::set_binary_gas_diffusivity( index_t component, scalar_t value ) { m_impl->binary_gas_diffusivity(component) = value; } const Vector& VariablesInterface::get_resistance_gas_diffusivity() const { return m_impl->resistance_gas_diffusivity().variable; } void VariablesInterface::set_resistance_gas_diffusivity( index_t node, scalar_t value ) { m_impl->resistance_gas_diffusivity().variable(node) = value; } void VariablesInterface::set_resistance_gas_diffusivity( const Vector& value) { m_impl->resistance_gas_diffusivity().variable = value; } void VariablesInterface::set_resistance_gas_diffusivity( scalar_t value) { m_impl->resistance_gas_diffusivity().variable.setConstant(value); } const Vector& VariablesInterface::get_advection_flux() const { return m_impl->advection_flux().variable; } void VariablesInterface::set_advection_flux(index_t node, scalar_t value) { m_impl->advection_flux().variable(node) = value; } void VariablesInterface::set_advection_flux(const Vector& value) { m_impl->advection_flux().variable = value; } void VariablesInterface::set_advection_flux(scalar_t value) { m_impl->advection_flux().variable.setConstant(value); } // User Models const Vector& VariablesInterface::get_capillary_pressure() const { return m_impl->m_vars->get_capillary_pressure().variable; } void VariablesInterface::set_capillary_pressure_model( user_model_saturation_f capillary_pressure_model ) { m_impl->m_vars->set_capillary_pressure_model(capillary_pressure_model); const Vector& sat = get_liquid_saturation(); Vector& cap_pressure = m_impl->m_vars->get_capillary_pressure().variable; for (auto node: m_impl->m_mesh->range_nodes()) { cap_pressure(node) = capillary_pressure_model(node, sat(node)); } } const Vector& VariablesInterface::get_vapor_pressure() const { return m_impl->m_vars->get_pressure_main_variables(0).variable; } void VariablesInterface::set_vapor_pressure_model( user_model_saturation_f vapor_pressure_model ) { m_impl->m_vars->set_vapor_pressure_model(vapor_pressure_model); } const Vector& VariablesInterface::get_relative_liquid_diffusivity() const { return m_impl->m_vars->get_relative_liquid_diffusivity().variable; } void VariablesInterface::set_relative_liquid_diffusivity_model( user_model_saturation_f relative_liquid_diffusivity_model ) { m_impl->m_vars->set_relative_liquid_diffusivity_model(relative_liquid_diffusivity_model); const Vector& sat = get_liquid_saturation(); Vector& rel_diff = m_impl->m_vars->get_relative_liquid_diffusivity().variable; for (auto node: m_impl->m_mesh->range_nodes()) { rel_diff(node) = relative_liquid_diffusivity_model(node, sat(node)); } } const Vector& VariablesInterface::get_relative_liquid_permeability() const { return m_impl->m_vars->get_relative_liquid_permeability().variable; } void VariablesInterface::set_relative_liquid_permeability_model( user_model_saturation_f relative_liquid_permeability_model ) { m_impl->m_vars->set_relative_liquid_permeability_model(relative_liquid_permeability_model); const Vector& sat = get_liquid_saturation(); Vector& rel_diff = m_impl->m_vars->get_relative_liquid_permeability().variable; for (auto node: m_impl->m_mesh->range_nodes()) { rel_diff(node) = relative_liquid_permeability_model(node, sat(node)); } } const Vector& VariablesInterface::get_relative_gas_diffusivity() const { return m_impl->m_vars->get_relative_gas_diffusivity().variable; } void VariablesInterface::set_relative_gas_diffusivity_model( user_model_saturation_f relative_gas_diffusivity_model ) { m_impl->m_vars->set_relative_gas_diffusivity_model(relative_gas_diffusivity_model); const Vector& sat = get_liquid_saturation(); Vector& rel_diff = m_impl->m_vars->get_relative_gas_diffusivity().variable; for (auto node: m_impl->m_mesh->range_nodes()) { rel_diff(node) = relative_gas_diffusivity_model(node, sat(node)); } } // chemistry void VariablesInterface::initialize_variables(index_t node, const AdimensionalSystemSolutionExtractor& extractor ) { set_porosity(node, extractor.porosity()); scalar_t saturation = extractor.saturation_water(); set_liquid_saturation(node, extractor.saturation_water()); scalar_t rho_l = extractor.density_water(); set_water_aqueous_concentration(node, rho_l*extractor.total_aqueous_concentration(0)); set_solid_concentration(0, node, extractor.total_solid_concentration(0)); if (m_impl->m_vars->component_has_gas(0)) { set_partial_pressure(0, node, m_impl->m_vars->get_vapor_pressure_model()(node, saturation) ); } for (index_t component: m_impl->m_database->range_aqueous_component()) { set_aqueous_concentration(component, node, rho_l*extractor.total_aqueous_concentration(component)); set_solid_concentration(component, node, extractor.total_solid_concentration(component)); if (m_impl->m_vars->component_has_gas(component)) { set_partial_pressure(component, node, extractor.fugacity_gas(m_impl->m_vars->get_id_gas(component)) *m_impl->m_vars->get_total_pressure()); } } m_impl->m_vars->set_adim_solution(node, std::move(extractor.get_solution())); } VariablesValidity VariablesInterface::check_variables() { return m_impl->check_variables(); } bool VariablesInterface::VariablesInterfaceImpl::check_bounds( const Vector& to_check, scalar_t lower, scalar_t upper ) { bool flag = true; for (index_t ind=0; ind< to_check.rows(); ++ind) { const scalar_t& value = to_check(ind); if (value < lower or value > upper) { flag = false; break; } } return flag; } VariablesValidity max_error_level(VariablesValidity err1, VariablesValidity err2) { return (err1>err2)?err1:err2; } VariablesValidity VariablesInterface::VariablesInterfaceImpl::check_variables() { VariablesValidity return_code = VariablesValidity::good; auto tmpret = check_saturation(); return_code = max_error_level(return_code, tmpret); tmpret = check_porosity(); return_code = max_error_level(return_code, tmpret); tmpret = check_relative(); return_code = max_error_level(return_code, tmpret); return return_code; } static bool SPECMICP_DLL_LOCAL saturation_check(const Vector& x) { return (is_bounded(x, 0.0, 1.0) && (any(x) > 0.0)); } VariablesValidity VariablesInterface::VariablesInterfaceImpl::check_saturation() { using namespace vector_checker; const auto& x = m_vars->get_liquid_saturation().variable; if (not saturation_check(x)) { ERROR << "Saturation vector is incorrect !"; return VariablesValidity::error; } return VariablesValidity::good; } static bool SPECMICP_DLL_LOCAL porosity_check(const Vector& x) { return (is_bounded(x, 0.0, 1.0) && (any(x) > 0.0)); } VariablesValidity VariablesInterface::VariablesInterfaceImpl::check_porosity() { using namespace vector_checker; const auto& x = m_vars->get_porosity().variable; if (not porosity_check(x)) { ERROR << "Porosity is incorrect"; return VariablesValidity::error; } return VariablesValidity::good; } static bool SPECMICP_DLL_LOCAL relative_variable_check(const Vector& x) { return (is_bounded(x, 0.0, 1.0) && (any(x) > 0.0)); } VariablesValidity VariablesInterface::VariablesInterfaceImpl::check_relative() { auto is_valid = VariablesValidity::good; if (not relative_variable_check( m_vars->get_relative_liquid_diffusivity().variable)) { ERROR << "Relative liquid diffusivity is incorrect"; is_valid = VariablesValidity::error; } if (not relative_variable_check( m_vars->get_relative_liquid_permeability().variable)) { ERROR << "Relative liquid permeability is incorrect"; is_valid = VariablesValidity::error; } if (not relative_variable_check( m_vars->get_relative_gas_diffusivity().variable)) { ERROR << "Relative gas diffusivity is incorrect"; is_valid = VariablesValidity::error; } if (not relative_variable_check( m_vars->get_resistance_gas_diffusivity().variable)) { ERROR << "Resistance gas diffusivity is incorrect"; is_valid = VariablesValidity::error; } return is_valid; } static bool SPECMICP_DLL_LOCAL transport_parameters_check(const Vector& x) { return (is_lower_bounded(x, 0.0) && (any(x) > 0.0)); } VariablesValidity VariablesInterface::VariablesInterfaceImpl::check_transport_param() { auto is_valid = VariablesValidity::good; if (not transport_parameters_check( m_vars->get_liquid_diffusivity().variable)) { ERROR << "Liquid diffusivity is incorrect"; is_valid = VariablesValidity::error; } if (not transport_parameters_check( m_vars->get_liquid_permeability().variable)) { ERROR << "Liquid permeability is incorrect"; is_valid = VariablesValidity::error; } return is_valid; } } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp diff --git a/src/reactmicp/systems/unsaturated/variables_interface.hpp b/src/reactmicp/systems/unsaturated/variables_interface.hpp index 6a393d3..bd6eca1 100644 --- a/src/reactmicp/systems/unsaturated/variables_interface.hpp +++ b/src/reactmicp/systems/unsaturated/variables_interface.hpp @@ -1,412 +1,414 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_REACTMICP_UNSATURATED_VARIABLESINTERFACE_HPP #define SPECMICP_REACTMICP_UNSATURATED_VARIABLESINTERFACE_HPP #include "types_fwd.hpp" #include "../../../dfpm/meshes/mesh1dfwd.hpp" #include "../../../database/database_fwd.hpp" #include //! \file variables_interface.hpp //! \brief Interface to initialize and store variables namespace specmicp { class AdimensionalSystemSolutionExtractor; namespace units { struct UnitsSet; } //end namespace units namespace reactmicp { namespace systems { namespace unsaturated { //! \brief Return code to check if the variables are ok enum class VariablesValidity { good, warning, error, critical }; class UnsaturatedVariables; //! \brief Initialize safely a set of variables class SPECMICP_DLL_PUBLIC VariablesInterface { public: VariablesInterface(mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas); VariablesInterface(mesh::Mesh1DPtr the_mesh, database::RawDatabasePtr the_database, const std::vector& component_with_gas, const units::UnitsSet& units_set ); ~VariablesInterface(); //! \brief Return the variables to pass to the reactive transport solver solver::VariablesBasePtr get_base_variables(); //! \brief Return the variables UnsaturatedVariablesPtr get_variables(); //! \brief Return the variables UnsaturatedVariables* get_raw_variables(); //! \brief Check the variables VariablesValidity check_variables(); // Variables // Main Variables // ============== // Saturation // ---------- //! \name Liquid saturation //! \brief The saturation of the liquid phase //! @{ //! \brief Return the liquid saturation const Vector& get_liquid_saturation() const; //! \brief Set the liquid saturation at 'node' void set_liquid_saturation(index_t node, scalar_t value); //! \brief Copy 'values' to the liquid saturation vector //! //! \param values a column vector containing the values, //! it's size is the number of nodes void set_liquid_saturation(const Vector& values); //! \brief Set the saturation to be constant accross the mesh void set_liquid_saturation(scalar_t value); //! @} // Aqueous concentration // --------------------- //! \name Aqueous concentration //! \brief Concentration (mol/volume) of the aqueous component //! @{ //! \brief Return the aqueous concentration of 'component' const Vector& get_aqueous_concentration(index_t component) const; //! \brief Set the aqueous concentration of 'component' at 'node' void set_aqueous_concentration( index_t component, index_t node, scalar_t value ); //! \brief Copy 'values' into the aqueous concentration vector //! of 'component' //! //! \param values a column vector containing the values, //! it's size is the number of nodes void set_aqueous_concentration(index_t component, const Vector& values); //! \brief Set a constant aqueous concentration for 'component' void set_aqueous_concentration(index_t component, scalar_t value); //! @} // Partial pressure // -------------- //! \name Partial pressure //! \brief Partial pressure for a gas //! @{ //! \brief Return the partial pressure for 'component' const Vector& get_partial_pressure(index_t component) const; //! \brief Set the partial pressure of 'component' at 'node' void set_partial_pressure(index_t component, index_t node, scalar_t value); //! \brief Copy 'values' into the 'component' partial pressure vector void set_partial_pressure(index_t component, const Vector& values); //! \brief Set a constant partial pressure for 'component' void set_partial_pressure(index_t component, scalar_t value); // @} // Solid concentration // ------------------- //! \name Solid concentration //! \brief Solid concentration (moles/volume) //! @{ //! \brief Return the solid concentration of 'component' const Vector& get_solid_concentration(index_t component) const; //! \brief Set the solid concentration of 'component' at 'node' void set_solid_concentration(index_t component, index_t node, scalar_t value); //! \brief Copy 'values' to the 'component' solid concentration vector void set_solid_concentration(index_t component, const Vector& values); //! \brief Set a constant solid concentration for 'component' void set_solid_concentration(index_t component, scalar_t value); //! @} // Chemistry // --------- void initialize_variables( index_t node, const AdimensionalSystemSolutionExtractor& extractor ); // Secondary Variables // =================== // Porosity // -------- //! \name Porosity //! \brief The porosity of the porous media //! @{ //! \brief Return the porosity vector const Vector& get_porosity() const; //! \brief Set the porosity at 'node' void set_porosity(index_t node, scalar_t value); //! \brief Copy 'values' into the porosity vector void set_porosity(const Vector& values); //! \brief Set a constant porosity accross the mesh void set_porosity(scalar_t value); //! @} // Water aqueous concentration // --------------------------- //! \name Water aqueous concentration //! \brief Aqueous concentration (moles/volume) for the water //! \brief Return the water aqueous concentration const Vector& get_water_aqueous_concentration() const; //! \brief Set the water aqueous concentration at 'node' void set_water_aqueous_concentration(index_t node, scalar_t value); //! \brief Copy values into the water aqueous concentration vector void set_water_aqueous_concentration(const Vector& values); //! \brief Set the water aqueous concentration to be constant accross //! the mesh void set_water_aqueous_concentration(scalar_t value); // Liquid diffusivity // ------------------ //! \name Liquid diffusion coefficient //! \brief Intrinsic diffusion coefficient in the liquid phase //! //! This value only depends on the microstructure, not the saturation //! @{ //! \brief Return the liquid diffusion coefficient const Vector& get_liquid_diffusivity() const; //! \brief Set the liquid diffusion coefficient at 'node' void set_liquid_diffusivity(index_t node, scalar_t value); //! \brief Copy 'values' into the liquid diffusion coefficient vector void set_liquid_diffusivity(const Vector& values); //! \brief Set the liquid diffusion coefficient to be constant accross //! the mesh void set_liquid_diffusivity(scalar_t value); //! @} // Liquid permeability // ------------------- //! \name Liquid permeability //! \brief Intrinsic permeability of the liquid phase //! //! This value only depends on the microstructure, not the saturation //! @{ //! \brief Return the liquid permeability const Vector& get_liquid_permeability() const; //! \brief Set the liquid permeability at 'node' void set_liquid_permeability(index_t node, scalar_t value); //! \brief Copy 'values' into the liquid permeability vector void set_liquid_permeability(const Vector& values); //! \brief Set the liquid permeability to be constant accross the mesh void set_liquid_permeability(scalar_t value); //! @} // Gas diffusivity : binary diffusion coefficient // ---------------------------------------------- //! \name Gas binary diffusion coefficient //! \brief Binary (Gas-Air) diffusion coefficient //! //! This value is independant on the microstructure and the saturation, //! only dependant of the gas //! @{ //! \brief Return the binary gas diffusion coefficient for the gas of //! 'component' scalar_t get_binary_gas_diffusivity(index_t component) const; //! \brief Set the binary gas diffusion coefficient for the gass of //! 'component' void set_binary_gas_diffusivity(index_t component, scalar_t value); //! @} // Gas diffusivity : resistance factor // ----------------------------------- //! \name Gas resistance factor //! \brief Resistance factor for the diffusion coefficient of a gas //! //! This value only depends on the microstructure, not the saturation //! @{ //! \brief Return the gas diffusion coefficient vector const Vector& get_resistance_gas_diffusivity() const; //! \brief Set the gas diffusion coefficient at 'node' void set_resistance_gas_diffusivity(index_t node, scalar_t value); //! \brief Copy 'values' into the gas diffusion coefficient vector void set_resistance_gas_diffusivity(const Vector& values); //! \brief Set the gas diffusion coefficient to be constant accross the mesh void set_resistance_gas_diffusivity(scalar_t value); //! @} // Advection flux // --------------- //! \name Liquid phase velocity //! \brief The liquid phase velocity due to the capillary pressure //! @{ //! \brief Return the liquid phase velocity vector const Vector& get_advection_flux() const; //! \brief Set the liquid phase velocity at 'node' void set_advection_flux(index_t node, scalar_t value); //! \brief Copy 'values' into the liquid phase velocity vector void set_advection_flux(const Vector& value); //! \brief Set the liquid phase velocity to be constant accross the mesh void set_advection_flux(scalar_t value); //! @} // User models // ----------- //! \name Capillary pressure //! \brief The macroscopic capillary pressure //! @{ //! \brief Return the capillary pressure values const Vector& get_capillary_pressure() const; //! \brief Set the capillary pressure model void set_capillary_pressure_model( user_model_saturation_f capillary_pressure_model ); //! @} //! \name Vapor pressure //! \brief The vapor pressure as function of the saturation //! @{ //! \brief Return the water vapor pressure values const Vector& get_vapor_pressure() const; //! \brief Set the vapor pressure model void set_vapor_pressure_model( user_model_saturation_f vapor_pressure_model ); //! @} //! \name Relative liquid diffusivity //! \brief The relative diffusion coefficient of the liquid phase //! @{ //! \brief Return the relative liquid diffusion coefficient values const Vector& get_relative_liquid_diffusivity() const; //! \brief Set the relative liquid diffusion coefficient model void set_relative_liquid_diffusivity_model( user_model_saturation_f relative_liquid_diffusivity_model ); //! @} //! \name Relative liquid permeability //! \brief The relative permeability of the liquid phase //! @{ //! \brief Return the relative liquid permeability values const Vector& get_relative_liquid_permeability() const; //! \brief Set the relative liquid permeability model void set_relative_liquid_permeability_model( user_model_saturation_f relative_liquid_permeability_model ); //! @} //! \name Relative gas diffusivity //! \brief The relative diffusion coefficient of the gas phase //! //! @{ //! \brief Return the relative gas diffusion coefficient values const Vector& get_relative_gas_diffusivity() const; //! \brief Set the relative gas diffusion coefficient model void set_relative_gas_diffusivity_model( user_model_saturation_f relative_gas_diffusivity_model ); //! @} private: //! \brief The implementation class //! \internal struct VariablesInterfaceImpl; //! \brief The implementation details //! \internal std::unique_ptr m_impl; }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_VARIABLESINTERFACE_HPP diff --git a/src/reactmicp/systems/unsaturated/variables_sub.hpp b/src/reactmicp/systems/unsaturated/variables_sub.hpp index cfc28e0..25547e5 100644 --- a/src/reactmicp/systems/unsaturated/variables_sub.hpp +++ b/src/reactmicp/systems/unsaturated/variables_sub.hpp @@ -1,267 +1,269 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file unsaturated/variables_sub.hpp //! \brief base structures for the variables #ifndef SPECMICP_REACTMICP_UNSATURATED_VARIABLESSUB_HPP #define SPECMICP_REACTMICP_UNSATURATED_VARIABLESSUB_HPP #include "../../../types.hpp" #include "../../../specmicp/adimensional/adimensional_system_solution.hpp" #include "../../../utils/compat.hpp" #include "../../../physics/constants.hpp" #include "../../../physics/units.hpp" #include #include namespace specmicp { namespace reactmicp { namespace systems { namespace unsaturated { //! \brief A simple variable struct BaseVariable { Vector variable; //!< The variable //! \brief Return value of the variable scalar_t& operator() (index_t node) { return variable(node); } //! \brief Return value of the variable scalar_t operator() (index_t node) const { return variable(node); } //! \brief Return the size of the vector index_t size() const { return variable.rows(); } //! \brief The variables are all set to 'value' void set_constant(scalar_t value) { variable.setConstant(value); } //! \brief Set the variables to zero void set_zero() { variable.setZero(); } //! \brief Build a variable of size 'size' //! //! The varaibles are initialized to zero BaseVariable(index_t size): variable(Vector::Zero(size)) {} }; //! \brief A transient variable //! //! These type of variable store the rate of change of the variable (velocity) //! and the value at the beginning of the timestep (predictor) struct BaseTransientVariable: public BaseVariable { Vector velocity; //!< Rate of change of the variable Vector predictor; //!< Predictor, value before first iteration BaseTransientVariable(index_t size): BaseVariable(size), velocity(Vector::Zero(size)), predictor(Vector::Zero(size)) {} //! \brief Update the variable void update(scalar_t dt) { variable = predictor + dt*velocity; } }; //! \brief A main variable, used to solve the governing equations //! //! These variables also store the chemistry and transport rates for the //! coupling struct MainVariable: public BaseTransientVariable { //! \brief Transport fluxes of the corresponding governing equations Vector transport_fluxes; //! \brief Chemical exchange rate Vector chemistry_rate; MainVariable(index_t size): BaseTransientVariable(size), transport_fluxes(Vector::Zero(size)), chemistry_rate(Vector::Zero(size)) {} //! \brief Reset the variables //! //! This function is called if the solver failed and must be restarted void reset() { transport_fluxes.setZero(); chemistry_rate.setZero(); velocity.setZero(); variable = predictor; } }; //! \brief List of main variables struct ListMainVariable { // Variables are stored as pointer so we can skip components // that do not exist // But still access their variables through their index using value_type = std::unique_ptr; using vector_type = std::vector; using iterator = vector_type::iterator; using const_iterator = vector_type::const_iterator; vector_type variables; MainVariable& water() { return *variables[0]; } MainVariable& aqueous_component(index_t aq_component) { specmicp_assert(variables[aq_component] != nullptr); return *variables[aq_component]; } MainVariable& component(index_t component) { specmicp_assert(variables[component] != nullptr); return *variables[component]; } MainVariable* operator() (index_t component) { return variables[component].get(); } // Implementations of the following methods // is in variables.cpp //! \brief Initialize the variables ListMainVariable(index_t nb_vars, index_t nb_nodes); //! \brief Initialize some variables //! //! Only initialize values given by 'to_init' ListMainVariable(index_t nb_vars, index_t nb_nodes, std::vector to_init); //! \brief Reset the variables void reset(); //! \brief Hard reset, erase all info for a component; void hard_reset(index_t component, index_t nb_nodes); }; //! \brief A secondary variable struct SecondaryVariable: public BaseVariable { SecondaryVariable(index_t size): BaseVariable(size) {} }; //! \brief A secondary transient variable //! //! e.g. the porosity struct SecondaryTransientVariable: public BaseTransientVariable { SecondaryTransientVariable(index_t size): BaseTransientVariable(size) {} }; //! \brief The chemistry solutions struct ChemistrySolutions { std::vector solutions; ChemistrySolutions(index_t size): solutions(size) {} //! \brief Return a solution AdimensionalSystemSolution& solution(index_t node) { return solutions[node]; } //! \brief Return a const solution const AdimensionalSystemSolution& solution(index_t node) const { return solutions[node]; } //! \brief Set a solution void update_solution( index_t node, const AdimensionalSystemSolution& new_solution ) { solutions[node] = new_solution; } }; //! \brief List of constants used in the problems struct ConstantBox { //! \brief R*T //! //! R : ideal gas constant //! T : temperature scalar_t rt {constants::gas_constant*units::celsius(25.0)}; //! \brief Viscosity of liquid water scalar_t viscosity_liquid_water {constants::water_viscosity}; //! \brief Total pressure scalar_t total_pressure {1.01325e5}; //! \brief Scale the constants void scale(units::LengthUnit length_unit); }; } //end namespace unsaturated } //end namespace systems } //end namespace reactmicp } //end namespace specmicp #endif // SPECMICP_REACTMICP_UNSATURATED_VARIABLESSUB_HPP diff --git a/src/reactmicp_core.hpp b/src/reactmicp_core.hpp index 41d99ed..d1f25c0 100644 --- a/src/reactmicp_core.hpp +++ b/src/reactmicp_core.hpp @@ -1,73 +1,75 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file reactmicp_core.hpp //! \brief Core files of the reactmicp solver - not standalone //! //! This file includes the main headers from the ReactMiCP solver. #ifndef SPECMICP_REACTMICP_CORE_HPP #define SPECMICP_REACTMICP_CORE_HPP #include "types.hpp" #include "database/database.hpp" #include "specmicp.hpp" #include "dfpm/mesh.hpp" // solver #include "reactmicp/solver/reactive_transport_solver.hpp" #include "reactmicp/solver/reactive_transport_solver_structs.hpp" #include "reactmicp/solver/staggers_base/upscaling_stagger_base.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #include "reactmicp/solver/timestepper.hpp" #include "reactmicp/solver/runner.hpp" // output #include "utils/io/csv_formatter.hpp" #include "dfpm/io/meshes.hpp" #include "reactmicp/io/reactive_transport.hpp" #include "physics/io/units.hpp" // configuration #include "utils/io/yaml.hpp" #include "database/io/configuration.hpp" #include "dfpm/io/configuration.hpp" #include "reactmicp/io/configuration.hpp" #include "utils/timer.hpp" #endif // SPECMICP_REACTMICP_CORE_HPP diff --git a/src/reactmicp_saturated.hpp b/src/reactmicp_saturated.hpp index 8242ebc..c04f27e 100644 --- a/src/reactmicp_saturated.hpp +++ b/src/reactmicp_saturated.hpp @@ -1,55 +1,57 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ //! \file reactmicp_saturated.hpp //! \brief Include this header to use the saturated system of ReactMiCP #ifndef SPECMICP_REACTMICP_SATURATED_HPP #define SPECMICP_REACTMICP_SATURATED_HPP // Core files #include "reactmicp_core.hpp" // systems #include "reactmicp/systems/saturated_react/variables.hpp" #include "reactmicp/systems/saturated_react/equilibrium_stagger.hpp" #include "reactmicp/systems/saturated_react/transport_stagger.hpp" #include "reactmicp/systems/saturated_react/init_variables.hpp" #include "reactmicp/systems/saturated_react/diffusive_upscaling_stagger.hpp" // output #include "reactmicp/io/saturated_react.hpp" #endif // SPECMICP_REACTMICP_SATURATED_HPP diff --git a/src/reactmicp_unsaturated.hpp b/src/reactmicp_unsaturated.hpp index 6d6373d..4791322 100644 --- a/src/reactmicp_unsaturated.hpp +++ b/src/reactmicp_unsaturated.hpp @@ -1,55 +1,57 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ //! \file reactmicp_unsaturated.hpp //! \brief The unsaturated system of the ReactMiCP solver #ifndef SPECMICP_REACMICP_UNSATURATED_HPP #define SPECMICP_REACMICP_UNSATURATED_HPP // Core files #include "reactmicp_core.hpp" // System #include "reactmicp/systems/unsaturated/variables_interface.hpp" #include "reactmicp/systems/unsaturated/equilibrium_constraints.hpp" #include "reactmicp/systems/unsaturated/equilibrium_stagger.hpp" #include "reactmicp/systems/unsaturated/transport_constraints.hpp" #include "reactmicp/systems/unsaturated/transport_stagger.hpp" // Output #endif // SPECMICP_REACMICP_UNSATURATED_HPP diff --git a/src/specmicp.hpp b/src/specmicp.hpp index d59467f..8cfa251 100644 --- a/src/specmicp.hpp +++ b/src/specmicp.hpp @@ -1,53 +1,55 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file specmicp.hpp //! \brief Include this file to use SpecMiCP API //! //! This file include the main headers from the SpecMiCP solver #include "types.hpp" #include "database/database.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/adimensional_system_solution_saver.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/io/configuration.hpp" #include "utils/log.hpp" diff --git a/src/specmicp/adimensional/adimensional_system.cpp b/src/specmicp/adimensional/adimensional_system.cpp index 9a333c2..c6b27e1 100644 --- a/src/specmicp/adimensional/adimensional_system.cpp +++ b/src/specmicp/adimensional/adimensional_system.cpp @@ -1,1428 +1,1430 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include #include "adimensional_system.hpp" #include "../../utils/log.hpp" #include "../../physics/constants.hpp" #include "../../physics/laws.hpp" #include "adimensional_system_solution.hpp" #include #include // uncomment to activate the finite difference jacobian // #define SPECMICP_DEBUG_EQUATION_FD_JACOBIAN namespace specmicp { //constexpr scalar_t log10f() const {return std::log(10.0);} //constexpr scalar_t log10 = log10f(); static const scalar_t log10 = std::log(10.0); // Constructor // =========== // No previous solution // -------------------- AdimensionalSystem::AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemOptions& options, const units::UnitsSet& units_set ): AdimemsionalSystemNumbering(ptrdata), OptionsHandler(options), units::UnitBaseClass(units_set), m_inert_volume_fraction(constraints.inert_volume_fraction), m_second(ptrdata), m_equations(total_dofs(), ptrdata) { specmicp_assert(ptrdata->is_valid()); m_fixed_values.setZero(ptrdata->nb_component()+1); number_eq(constraints); } // Previous solution // ----------------- AdimensionalSystem::AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemOptions& options, const units::UnitsSet& units_set ): AdimemsionalSystemNumbering(ptrdata), OptionsHandler(options), units::UnitBaseClass(units_set), m_inert_volume_fraction(constraints.inert_volume_fraction), m_second(previous_solution), m_equations(total_dofs(), ptrdata) { specmicp_assert(ptrdata->is_valid()); m_fixed_values.setZero(ptrdata->nb_component()+1); number_eq(constraints); } // Secondary variables constructor // =============================== // No previous solution // -------------------- AdimensionalSystem::SecondaryVariables::SecondaryVariables( const RawDatabasePtr& data ): secondary_molalities(Vector::Zero(data->nb_aqueous())), loggamma(Vector::Zero(data->nb_component()+data->nb_aqueous())), gas_fugacity(Vector::Zero(data->nb_gas())), gas_concentration(Vector::Zero(data->nb_gas())), sorbed_concentrations(Vector::Zero(data->nb_sorbed())) {} // Previous solution // ----------------- AdimensionalSystem::SecondaryVariables::SecondaryVariables( const AdimensionalSystemSolution& previous_solution ): secondary_molalities(previous_solution.secondary_molalities), loggamma(previous_solution.log_gamma), gas_fugacity(previous_solution.gas_fugacities), gas_concentration(Vector::Zero(previous_solution.gas_fugacities.rows())), sorbed_concentrations(previous_solution.sorbed_molalities) {} // IdEquations constructor // ======================= AdimensionalSystem::IdEquations::IdEquations( index_t nb_dofs, const RawDatabasePtr& data ): ideq(nb_dofs, no_equation), component_equation_type(data->nb_component()+1, no_equation), fixed_activity_species(data->nb_component()+1, no_species), active_aqueous(data->nb_aqueous(), false), active_gas(data->nb_gas(), false), active_sorbed(data->nb_sorbed()) {} // Equation numbering // ================== // Note : this function also computes scaling factor that would be used in the computation // ------ void AdimensionalSystem::number_eq( const AdimensionalSystemConstraints& constraints ) { index_t neq = 0; // units compute_scaling_factors(); // Water // ===== if (constraints.water_equation != WaterEquationType::NoEquation) { m_equations.type_equation(dof_water()) = static_cast(constraints.water_equation); if (constraints.water_equation == WaterEquationType::MassConservation) { m_fixed_values(dof_water()) = constraints.total_concentrations(dof_water()); if (constraints.water_partial_pressure.use_partial_pressure_model) { m_equations.use_water_pressure_model = true; m_equations.water_pressure_model = constraints.water_partial_pressure.partial_pressure_model; } } m_equations.add_equation(dof_water(), &neq); } // Aqueous components // ================== number_eq_aqueous_component(constraints, neq); // Surface model // ============= if (constraints.surface_model.model_type == SurfaceEquationType::Equilibrium) { // add the equation m_equations.add_equation(dof_surface(), &neq); m_equations.type_equation(dof_surface()) = static_cast(constraints.surface_model.model_type); // setup the total concentration m_fixed_values(dof_surface()) = constraints.surface_model.concentration; } // Secondary species // ================= // Secondary aqueous species // ------------------------- bool include_half_cell_reaction = (constraints.electron_constraint.equation_type != ElectronEquationType::NoEquation); bool solve_electron_equation {false}; for (auto j: m_data->range_aqueous()) { bool can_exist { true }; if ( include_half_cell_reaction or not m_data->is_half_cell_reaction(j)) for (const auto& k: m_equations.nonactive_component) { if (m_data->nu_aqueous(j, k) != 0.0) { can_exist = false; break; } } else { can_exist = false; } m_equations.set_aqueous_active(j, can_exist); if (can_exist and m_data->is_half_cell_reaction(j)) solve_electron_equation = true; //std::cout << m_data->labels_aqueous[j] << "can exist ? " << can_exist << " - logk : " << m_data->logk_aqueous(j) << std::endl; } // Gas // --- for (index_t k: m_data->range_gas()) { bool can_exist = true; for (const index_t& n: m_equations.nonactive_component) { if (m_data->nu_gas(k, n) != 0.0) { can_exist = false; break; } } m_equations.set_gas_active(k, can_exist); } // Sorbed species // -------------- for (index_t s: m_data->range_sorbed()) { // Check if the surface model is computed if (constraints.surface_model.model_type != SurfaceEquationType::Equilibrium) { m_equations.set_sorbed_active(s, false); continue; } // If so, check that all components of the sorbed species exist bool can_exist = true; for (const index_t& k: m_equations.nonactive_component) { if (m_data->nu_sorbed(s, k) != 0.0) { can_exist = false; break; } } m_equations.set_sorbed_active(s, can_exist); } // Electron equation // ----------------- if (solve_electron_equation) { m_equations.add_equation(dof_electron(), &neq); m_equations.type_equation(dof_electron()) = static_cast(constraints.electron_constraint.equation_type); if (constraints.electron_constraint.equation_type == ElectronEquationType::Equilibrium) { m_fixed_values(dof_electron()) = 0.0; } else if (constraints.electron_constraint.equation_type == ElectronEquationType::FixedpE) { m_fixed_values(dof_electron()) = constraints.electron_constraint.fixed_value; m_equations.related_species(dof_electron()) = constraints.electron_constraint.species; //assert(m_fixed_activity_species[dof_electron()] >= 0 // and m_fixed_activity_species[dof_electron()] < m_data->nb_aqueous()); //assert(m_data->is_half_cell_reaction(m_fixed_activity_species[dof_electron()])); } // scaling if (get_options().scaling_electron == 0.0) { for (index_t component : m_data->range_aqueous_component()) { if (aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation) { get_options().scaling_electron = total_concentration_bc(component); break; } } } } // above equations are 'free' (i.e. non constrained) m_equations.nb_free_variables = neq; // following equations are complementarity conditions // Minerals // ======== for (index_t m: m_data->range_mineral()) { bool can_precipitate = true; // just check that the molar volume exist auto molar_volume = m_data->molar_volume_mineral(m); // Remove minerals that cannot precipitate for (index_t& k: m_equations.nonactive_component) { if (m_data->nu_mineral(m, k) != 0.0 and molar_volume > 0.0) { can_precipitate = false; break; // this is not a mineral that can precipitate } } if (can_precipitate) { m_equations.add_equation(dof_mineral(m), &neq); } } m_equations.nb_tot_variables = neq; m_equations.nb_complementarity_variables = m_equations.nb_tot_variables - m_equations.nb_free_variables; } void AdimensionalSystem::number_eq_aqueous_component( const AdimensionalSystemConstraints& constraints, index_t& neq ) { using EqT = AqueousComponentEquationType; // First set the charge keeper if (constraints.charge_keeper != no_species) { if (constraints.charge_keeper == 0 or constraints.charge_keeper > m_data->nb_component()) { throw std::invalid_argument("The charge keeper must be an aqueous component. Invalid argument : " + std::to_string(constraints.charge_keeper)); } m_equations.type_equation(dof_component(constraints.charge_keeper)) = static_cast(EqT::ChargeBalance); } // Then go over fix fugacity gas for (const auto& it: constraints.fixed_fugacity_cs) { if (m_equations.type_equation(dof_component(it.id_component)) != static_cast(EqT::NoEquation)) { throw std::invalid_argument("Component '" + m_data->components.get_label(it.id_component) + "' is already constrained, a fixed fugacity condition can not be applied"); } m_equations.type_equation(dof_component(it.id_component)) = static_cast(EqT::FixedFugacity); m_fixed_values(it.id_component) = it.log_value; m_equations.related_species(it.id_component) = it.id_gas; } // Then over the fixed activity species for (const auto& it: constraints.fixed_activity_cs) { if (m_equations.type_equation(dof_component(it.id_component)) != static_cast(EqT::NoEquation)) { throw std::invalid_argument("Component '" + m_data->components.get_label(it.id_component) + "' is already constrained, a fixed activity condition can not be applied."); } m_equations.type_equation(dof_component(it.id_component)) = static_cast(EqT::FixedActivity); m_fixed_values(it.id_component) = it.log_value; } // Then the fixed molality components for (const auto& it: constraints.fixed_molality_cs) { if (m_equations.type_equation(dof_component(it.id_component)) != static_cast(EqT::NoEquation)) { throw std::invalid_argument("Component '" + m_data->components.get_label(it.id_component) + "' is already constrained, a fixed molality condition can not be applied."); } m_equations.type_equation(dof_component(it.id_component)) = static_cast(EqT::FixedMolality); m_fixed_values(it.id_component) = it.log_value; } // Finally number the equations for (index_t component: m_data->range_aqueous_component()) { // If no equation is assigned yet if (m_equations.type_equation(dof_component(component)) == static_cast(EqT::NoEquation)) { // Mass is conserved for this component //###FIXME: H[+], HO[-] const scalar_t& total_concentration = constraints.total_concentrations(dof_component(component)); if (std::abs(total_concentration) > get_options().cutoff_total_concentration) { m_equations.type_equation(dof_component(component)) = static_cast(EqT::MassConservation); m_fixed_values(dof_component(component)) = total_concentration; m_equations.add_equation(component, &neq); } else // add component to the nonactive component list { m_equations.add_non_active_component(component); } } // If equation is already assigned else { m_equations.add_equation(component, &neq); } } if (stdlog::ReportLevel() >= logger::Debug and m_equations.nonactive_component.size() > 0) { // if in debug mode list the non active components DEBUG << "Non active components :"; for (auto it: m_equations.nonactive_component) { DEBUG << " - " << it; } } } // Units // ================= void AdimensionalSystem::set_units(const units::UnitsSet& unit_set) { units::UnitBaseClass::set_units(unit_set); compute_scaling_factors(); } void AdimensionalSystem::compute_scaling_factors() { m_scaling_molar_volume = m_data->scaling_molar_volume(get_units().length); // Unit scaling for the gaseous total concentration // transform mol/m^3 into the right unit (pressure are always in Pa) switch (get_units().length) { case units::LengthUnit::decimeter: m_scaling_gas = 1e-3; break; case units::LengthUnit::centimeter: m_scaling_gas = 1e-6; break; default: m_scaling_gas = 1.0; break; } } // ================ // // // // Residuals // // // // ================ // scalar_t AdimensionalSystem::weigthed_sum_aqueous(index_t component) const { scalar_t sum = 0.0; for (index_t aqueous: m_data->range_aqueous()) { if (not is_aqueous_active(aqueous)) continue; sum += m_data->nu_aqueous(aqueous,component)*secondary_molality(aqueous); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_aqueous(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t aqueous: m_data->range_aqueous()) { if (not is_aqueous_active(aqueous)) continue; sum += log10*m_data->nu_aqueous(aqueous,diff_component)*m_data->nu_aqueous(aqueous,component)*secondary_molality(aqueous); } return sum; } scalar_t AdimensionalSystem::weigthed_sum_sorbed(index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_sorbed(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += log10*m_data->nu_sorbed(s, diff_component)*m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::diff_surface_weigthed_sum_sorbed(index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += log10*m_data->nb_sorption_sites(s)*m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::weigthed_sum_mineral(const Vector& x, index_t component) const { scalar_t sum = 0.0; for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation or m_data->nu_mineral(m, component) == 0.0) continue; const auto concentration = volume_fraction_mineral(x, m)/molar_volume_mineral(m); sum += m_data->nu_mineral(m, component)*concentration; } return sum; } scalar_t AdimensionalSystem::weigthed_sum_gas(index_t component) const { scalar_t sum = 0.0; for (index_t k: m_data->range_gas()) { if (not is_active_gas(k) or m_data->nu_gas(k, component) == 0.0) continue; sum += m_data->nu_gas(k, component)*gas_concentration(k); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_gas(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t k: m_data->range_gas()) { if (not is_active_gas(k) or m_data->nu_gas(k, component) == 0.0) continue; sum += log10*m_data->nu_gas(k, diff_component)*m_data->nu_gas(k, component)*gas_concentration(k); } return sum; } scalar_t AdimensionalSystem::residual_water_conservation(const Vector& x) const { specmicp_assert(water_equation_type() == WaterEquationType::MassConservation); scalar_t res = total_concentration_bc(0); const scalar_t conc_w = density_water() * volume_fraction_water(x); res = total_concentration_bc(0); res -= conc_w/m_data->molar_mass_basis(0); res -= conc_w*weigthed_sum_aqueous(0); if (ideq_surf() != no_equation) res -= conc_w*weigthed_sum_sorbed(0); res -= weigthed_sum_mineral(x, 0); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(0); if (m_equations.use_water_pressure_model) { // water pressure const scalar_t porosity = m_second.porosity; scalar_t sat_w = volume_fraction_water(x) / porosity; if (sat_w < 1) { const scalar_t pressure = m_equations.water_pressure_model(sat_w); res -= m_scaling_gas*(porosity - volume_fraction_water(x))*( pressure / (constants::gas_constant*temperature())); } } res /= total_concentration_bc(0); return res; } scalar_t AdimensionalSystem::residual_water_saturation(const Vector& x) const { specmicp_assert(water_equation_type() == WaterEquationType::SaturatedSystem); scalar_t res = 1 - volume_fraction_water(x) - m_inert_volume_fraction; for (index_t mineral: m_data->range_mineral()) { res -= volume_fraction_mineral(x, mineral); } return res; } scalar_t AdimensionalSystem::residual_component(const Vector &x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation); const scalar_t conc_w = density_water()*volume_fraction_water(x); scalar_t res = total_concentration_bc(component); res -= conc_w*component_molality(x, component); res -= conc_w*weigthed_sum_aqueous(component); if (ideq_surf() != no_equation) res -= conc_w*weigthed_sum_sorbed(component); res -= weigthed_sum_mineral(x, component); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(component); res /= total_concentration_bc(component); return res; } scalar_t AdimensionalSystem::residual_fixed_activity(const Vector& x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedActivity); scalar_t res = (fixed_activity_bc(component) - log_gamma_component(component) - log_component_molality(x, component) ); res /= fixed_activity_bc(component); return res; } scalar_t AdimensionalSystem::residual_fixed_molality(const Vector& x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedMolality); scalar_t res = (fixed_molality_bc(component) - log_component_molality(x, component) ); res /= fixed_molality_bc(component); return res; } scalar_t AdimensionalSystem::residual_fixed_fugacity(const Vector& x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedFugacity); index_t id_g = m_equations.fixed_activity_species[component]; scalar_t res = fixed_fugacity_bc(component) + m_data->logk_gas(id_g); for (index_t component: m_data->range_aqueous_component()) { if (m_data->nu_gas(id_g, component) == 0) continue; res -= m_data->nu_gas(id_g, component)*( log_gamma_component(component) + log_component_molality(x, component)); } res /= fixed_fugacity_bc(component); return res; } scalar_t AdimensionalSystem::residual_mineral(const Vector& x, index_t m) const { specmicp_assert(ideq_min(m) != no_equation); scalar_t res = m_data->logk_mineral(m); for (index_t i: m_data->range_aqueous_component()) { if (m_data->nu_mineral(m, i) != 0) { const auto log_activity_i = log_component_molality(x, i) + log_gamma_component(i); res -= m_data->nu_mineral(m, i)*log_activity_i; } } if (ideq_electron() != no_equation and m_data->is_mineral_half_cell_reaction(m)) res -= m_data->nu_mineral(m, m_data->electron_index())*log_activity_electron(x); return res; } scalar_t AdimensionalSystem::residual_charge_conservation(const Vector& x) const { scalar_t res = 0.0; for (index_t i: m_data->range_aqueous_component()) { if (m_data->charge_component(i) != 0 and ideq_paq(i) != no_equation) res += m_data->charge_component(i)*component_molality(x, i); } for (index_t j: m_data->range_aqueous()) { if (m_data->charge_aqueous(j) == 0 and not is_aqueous_active(j)) continue; res += m_data->charge_aqueous(j)*secondary_molality(j); } return res; } scalar_t AdimensionalSystem::residual_surface(const Vector &x) const { specmicp_assert(ideq_surf() != no_equation); const scalar_t conc_w = density_water()*volume_fraction_water(x); scalar_t res = surface_total_concentration() - conc_w*free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; res -= conc_w*m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } return res/surface_total_concentration(); } scalar_t AdimensionalSystem::residual_electron(const Vector &x) const { specmicp_assert(electron_equation_type() == ElectronEquationType::Equilibrium); const scalar_t conc_w = density_water()*volume_fraction_water(x); scalar_t res = 0.0; res -= conc_w * weigthed_sum_aqueous(m_data->electron_index()); if (ideq_surf() != no_equation) res -= conc_w * weigthed_sum_sorbed(m_data->electron_index()); res -= weigthed_sum_mineral(x, m_data->electron_index()); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(m_data->electron_index()); return res/get_options().scaling_electron; } void AdimensionalSystem::get_residuals(const Vector& x, Vector& residual) { residual.resize(total_variables()); // initialisation of 'main' secondary variables // They are especially nessary if the finite difference jacobian is used // and for the linesearch m_second.porosity = 1 - sum_volume_fraction_minerals(x); set_volume_fraction_gas_phase(x); set_secondary_concentration(x); set_sorbed_concentrations(x); // // water if (ideq_w() != no_equation) { switch (water_equation_type()) { case WaterEquationType::MassConservation: residual(ideq_w()) = residual_water_conservation(x); break; case WaterEquationType::SaturatedSystem: residual(ideq_w()) = residual_water_saturation(x); case WaterEquationType::NoEquation: break; } } // aqueous component for (index_t i: m_data->range_aqueous_component()) { switch (aqueous_component_equation_type(i)) { case AqueousComponentEquationType::NoEquation: break; case AqueousComponentEquationType::MassConservation: residual(ideq_paq(i)) = residual_component(x, i); break; case AqueousComponentEquationType::ChargeBalance: residual(ideq_paq(i)) = residual_charge_conservation(x); break; case AqueousComponentEquationType::FixedActivity: residual(ideq_paq(i)) = residual_fixed_activity(x, i); break; case AqueousComponentEquationType::FixedFugacity: residual(ideq_paq(i)) = residual_fixed_fugacity(x, i); break; case AqueousComponentEquationType::FixedMolality: residual(ideq_paq(i)) = residual_fixed_molality(x, i); break; } } // surface if (ideq_surf() != no_equation) residual(ideq_surf()) = residual_surface(x); // mineral for (index_t m: m_data->range_mineral()) { if (ideq_min(m) != no_equation) residual(ideq_min(m)) = residual_mineral(x, m); } // electron if (ideq_electron() != no_equation ) residual(ideq_electron()) = residual_electron(x); // std::cout << residual << std::endl; } // ================ // // // // Jacobian // // // // ================ // void AdimensionalSystem::get_jacobian(Vector& x, Matrix& jacobian) // //non-optimized Finite difference, for test only #ifdef SPECMICP_DEBUG_EQUATION_FD_JACOBIAN { finite_difference_jacobian(x, jacobian); return; } #else // analytical jacobian { analytical_jacobian(x, jacobian); return; } #endif void AdimensionalSystem::finite_difference_jacobian(Vector& x, Matrix& jacobian) { const int neq = total_variables(); Eigen::VectorXd res(neq); Eigen::VectorXd perturbed_res(neq); jacobian.setZero(neq, neq); get_residuals(x, res); for (int j=0; jmolar_mass_basis(0); tmp -= weigthed_sum_aqueous(0); tmp -= weigthed_sum_sorbed(0); tmp *= rho_w; tmp -= -weigthed_sum_gas(0); if (m_equations.use_water_pressure_model) { // The jacobian of the pressure model is // computed using finite difference const scalar_t sat_w = volume_fraction_water(x)/ porosity(x); if (sat_w >= 1.0) { // doesn't make sense to have a saturation // bigger than one in this case ERROR << "Saturation greater that one detected" << ", skip pressure model"; } else { // compute the perturbation scalar_t sp = sat_w*(1.0 + eps_jacobian); if (sp == 0.0) sp = eps_jacobian; const scalar_t h = sp - sat_w; // can we save one call here ? cache const scalar_t pv_sds = m_equations.water_pressure_model(sp); const scalar_t pv_s = m_equations.water_pressure_model(sat_w); const scalar_t diff = (pv_sds - pv_s) / h; // add the contribution tmp -= m_scaling_gas/(constants::gas_constant*temperature()) *( (1.0-sat_w)*diff - pv_s ); } } jacobian(idw, idw) = tmp/factor; const scalar_t conc_w = density_water()*volume_fraction_water(x); for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(k, 0); tmp -= diff_weigthed_sum_sorbed(k, 0); // fixme gas tmp *= conc_w; tmp -= diff_weigthed_sum_gas(k, 0); jacobian(idw, ideq_paq(k)) = tmp/factor; } if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(m_data->electron_index(), 0); tmp -= diff_weigthed_sum_sorbed(m_data->electron_index(), 0); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(m_data->electron_index(), 0); jacobian(idw, ideq_electron()) = tmp/factor; } for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idw, ideq_min(m)) = -m_data->nu_mineral(m, 0)/molar_volume_mineral(m)/factor; } } else if (water_equation_type() == WaterEquationType::SaturatedSystem) { const index_t idw = ideq_w(); jacobian(idw, idw) = -1; for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idw, ideq_min(m)) = -1; } } } void AdimensionalSystem::jacobian_aqueous_components(Vector& x, Matrix& jacobian) { for (index_t i: m_data->range_aqueous_component()) { const index_t idp = ideq_paq(i); if (idp == no_equation) continue; switch (aqueous_component_equation_type(i)) { case AqueousComponentEquationType::NoEquation: continue; // Mass balance equation // ===================== case AqueousComponentEquationType::MassConservation: { const scalar_t conc_w = density_water()*volume_fraction_water(x); const scalar_t factor = total_concentration_bc(i); // Aqueous components for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp_iip = 0; if (k == i) tmp_iip -= component_molality(x, i)*log10; tmp_iip -= diff_weigthed_sum_aqueous(k, i); tmp_iip -= diff_weigthed_sum_sorbed(k, i); tmp_iip *= conc_w; tmp_iip -= diff_weigthed_sum_gas(k, i); jacobian(idp, ideq_paq(k)) = tmp_iip/factor; } // Minerals for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idp, ideq_min(m)) = - m_data->nu_mineral(m, i)/molar_volume_mineral(m)/factor; } // Water if (ideq_w() != no_equation) { scalar_t tmp_iw = -component_molality(x, i); tmp_iw -= weigthed_sum_aqueous(i); tmp_iw -= weigthed_sum_sorbed(i); tmp_iw *= density_water(); jacobian(idp, ideq_w()) = tmp_iw/factor; } // Surface if (ideq_surf() != no_equation) { scalar_t tmp_s = -conc_w*diff_surface_weigthed_sum_sorbed(i); jacobian(idp, ideq_surf()) = tmp_s/factor; } // Electron if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(m_data->electron_index(), i); tmp -= diff_weigthed_sum_sorbed(m_data->electron_index(), i); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(m_data->electron_index(), i); jacobian(idp, ideq_electron()) = tmp/factor; } break; } // Charge balance equation // ======================= case AqueousComponentEquationType::ChargeBalance: { // Aqueous components for (index_t k: m_data->range_aqueous_component()) { const index_t idc = ideq_paq(k); if (idc == no_equation) continue; scalar_t tmp_drdb = 0.0; if (m_data->charge_component(k) != 0.0) tmp_drdb = m_data->charge_component(k); // Secondary species for (index_t j: m_data->range_aqueous()) { if ( not is_aqueous_active(j) or m_data->nu_aqueous(j, k) == 0.0 or m_data->charge_aqueous(j) == 0.0 ) continue; scalar_t tmp_value = m_data->nu_aqueous(j, k)*m_data->charge_aqueous(j); tmp_value *= secondary_molality(j)/component_molality(x, k); tmp_drdb += tmp_value; } jacobian(idp, idc) += component_molality(x,k)*log10*tmp_drdb; } break; } // Fixed activity equation // ======================= case AqueousComponentEquationType::FixedActivity: { jacobian(idp, idp) = -1.0/fixed_activity_bc(i); break; } // Fixed fugacity equation // ======================= case AqueousComponentEquationType::FixedFugacity: { index_t id_g = m_equations.fixed_activity_species[i]; for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation or m_data->nu_gas(id_g, k) == 0.0) continue; jacobian(idp, ideq_paq(k)) = -m_data->nu_gas(id_g, k)/fixed_fugacity_bc(i); } break; } // end case // Fixed molality component // ======================== case AqueousComponentEquationType::FixedMolality: { jacobian(idp, idp) = -1.0/fixed_molality_bc(i); break; } } // end switch } } void AdimensionalSystem::jacobian_minerals(Vector& x, Matrix& jacobian) { for (index_t m: m_data->range_mineral()) { const index_t idm = ideq_min(m); if (idm == no_equation) continue; for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation) continue; jacobian(idm, ideq_paq(i)) = -m_data->nu_mineral(m, i); } if (ideq_electron() != no_equation and m_data->is_mineral_half_cell_reaction(m)) jacobian(idm, ideq_electron()) = -m_data->nu_mineral(m, m_data->electron_index()); } } void AdimensionalSystem::jacobian_surface(Vector& x, Matrix& jacobian) { const index_t ids = ideq_surf(); const scalar_t factor = surface_total_concentration(); const scalar_t conc_w = density_water()*volume_fraction_water(x); specmicp_assert(ids != no_equation); scalar_t tmp_s = - free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; tmp_s -= m_data->nb_sorption_sites(s)* m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } jacobian(ids, ids) = conc_w*log10 * tmp_s / factor; // water const index_t idw = ideq_w(); if (idw != no_equation) { const scalar_t rho_w = density_water(); scalar_t tmp_w = - free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; tmp_w -= m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } jacobian(ids, idw) = rho_w * tmp_w / factor; } // component for (index_t k: m_data->range_aqueous_component()) { const index_t idk = ideq_paq(k); if (idk == no_equation) continue; scalar_t tmp_k = - conc_w*diff_surface_weigthed_sum_sorbed(k); jacobian(ids, idk) = tmp_k/factor; } if (ideq_electron() != no_equation) { scalar_t tmp_e = - conc_w*diff_surface_weigthed_sum_sorbed(m_data->electron_index()); jacobian(ids, ideq_electron()) = tmp_e/factor; } // water } void AdimensionalSystem::jacobian_electron(Vector& x, Matrix& jacobian) { const auto ide = ideq_electron(); const auto dofe = m_data->electron_index(); const scalar_t conc_w = density_water()*volume_fraction_water(x); const scalar_t factor = get_options().scaling_electron; // Aqueous components for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp_eip = 0; tmp_eip -= diff_weigthed_sum_aqueous(k, dofe); tmp_eip -= diff_weigthed_sum_sorbed(k, dofe); tmp_eip *= conc_w; tmp_eip -= diff_weigthed_sum_gas(k, dofe); jacobian(ide, ideq_paq(k)) = tmp_eip/factor; } // Minerals for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(ide, ideq_min(m)) = - m_data->nu_mineral(m, dofe)/molar_volume_mineral(m)/factor; } // Water if (ideq_w() != no_equation) { scalar_t tmp_iw = 0; tmp_iw -= weigthed_sum_aqueous(dofe); tmp_iw -= weigthed_sum_sorbed(dofe); tmp_iw *= density_water(); jacobian(ide, ideq_w()) = tmp_iw/factor; } // Surface if (ideq_surf() != no_equation) { scalar_t tmp_s = -conc_w*diff_surface_weigthed_sum_sorbed(dofe); jacobian(ide, ideq_surf()) = tmp_s/factor; } // Electron if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(dofe, dofe); tmp -= diff_weigthed_sum_sorbed(dofe, dofe); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(dofe, dofe); jacobian(ide, ide) = tmp/factor; } } // ========================== // // // // Secondary variables // // // // ========================== // void AdimensionalSystem::set_secondary_variables(const Vector& x) { m_second.porosity = 1 - sum_volume_fraction_minerals(x) - m_inert_volume_fraction; set_volume_fraction_gas_phase(x); set_pressure_fugacity(x); if (ideq_surf() != no_equation) set_sorbed_concentrations(x); set_secondary_concentration(x); compute_log_gamma(x); } void AdimensionalSystem::set_volume_fraction_gas_phase(const Vector& x) { m_second.volume_fraction_gas = m_second.porosity - volume_fraction_water(x); } void AdimensionalSystem::set_pressure_fugacity(const Vector& x) { const auto rt = constants::gas_constant*temperature(); for (index_t k: m_data->range_gas()) { if (not is_active_gas(k)) continue; scalar_t logp = -m_data->logk_gas(k); for (index_t i: m_data->range_aqueous_component()) { if (m_data->nu_gas(k, i) == 0.0) continue; const auto log_activity_i = log_component_molality(x, i) + log_gamma_component(i); logp += m_data->nu_gas(k, i) * log_activity_i; } if (ideq_electron() != no_equation and m_data->is_gas_half_cell_reaction(k)) logp += m_data->nu_gas(k, m_data->electron_index())*log_activity_electron(x); m_second.gas_fugacity(k) = pow10(logp); const scalar_t pressure = gas_fugacity(k)*gas_total_pressure(); const scalar_t concentration = m_scaling_gas*volume_fraction_gas_phase()*pressure/rt; m_second.gas_concentration(k) = concentration; } } void AdimensionalSystem::set_secondary_concentration(const Vector& x) { for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j)) { m_second.secondary_molalities(j) = 0.0; continue; } scalar_t logconc = -m_data->logk_aqueous(j) - log_gamma_secondary(j); for (index_t k: m_data->range_aqueous_component()) { if (m_data->nu_aqueous(j, k) == 0) continue; const auto log_activity_k = log_component_molality(x, k) + log_gamma_component(k); logconc += m_data->nu_aqueous(j, k)*log_activity_k; } if (ideq_electron() != no_equation and m_data->is_half_cell_reaction(j)) logconc += m_data->nu_aqueous(j, m_data->electron_index())*log_activity_electron(x); m_second.secondary_molalities(j) = pow10(logconc); } } void AdimensionalSystem::set_sorbed_concentrations(const Vector& x) { for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) { m_second.sorbed_concentrations(s) = 0.0; continue; } scalar_t logconc = -m_data->logk_sorbed(s) + m_data->nb_sorption_sites(s)*(log_free_sorption_site_concentration(x)); for (index_t k: m_data->range_aqueous_component()) { if (m_data->nu_sorbed(s, k) == 0.0) continue; const auto activity_k = log_component_molality(x, k) + log_gamma_component(k); logconc += m_data->nu_sorbed(s, k)*activity_k; } if (ideq_electron() != no_equation and m_data->is_sorbed_half_cell_reaction(s)) logconc += m_data->nu_sorbed(s, m_data->electron_index())*log_activity_electron(x); m_second.sorbed_concentrations(s) = pow10(logconc); } } void AdimensionalSystem::set_ionic_strength(const Vector& x) { scalar_t ionic = 0; for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation or m_data->charge_component(i) == 0) continue; ionic += component_molality(x, i)*std::pow(m_data->charge_component(i),2); } for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j) or m_data->charge_aqueous(j) == 0) continue; ionic += secondary_molality(j)*std::pow(m_data->charge_aqueous(j),2); } ionic_strength() = ionic/2; } void AdimensionalSystem::compute_log_gamma(const Vector& x) { set_ionic_strength(x); const scalar_t sqrti = std::sqrt(ionic_strength()); for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation) { log_gamma_component(i) = 0.0; continue; } log_gamma_component(i) = laws::extended_debye_huckel( ionic_strength(), sqrti, m_data->charge_component(i), m_data->a_debye_component(i), m_data->b_debye_component(i) ); } for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j)) { log_gamma_secondary(j) = 0.0; continue; } log_gamma_secondary(j) = laws::extended_debye_huckel( ionic_strength(), sqrti, m_data->charge_aqueous(j), m_data->a_debye_aqueous(j), m_data->b_debye_aqueous(j) ); } } bool AdimensionalSystem::hook_start_iteration(const Vector& x, scalar_t norm_residual) { if (not get_options().non_ideality) { set_secondary_variables(x); // we still need to compute secondary species ! // if (norm_residual < nb_free_variables()*get_options().start_non_ideality_computation) // { // set_secondary_variables(x); // } return true; } not_in_linesearch = true; scalar_t previous_norm = m_second.loggamma.norm(); if (previous_norm == 0) previous_norm = 1; bool may_have_converged = false; if (norm_residual < nb_free_variables()*get_options().start_non_ideality_computation) { // Use fixed point iterations for non-ideality for (int i=0; i 1e-6) { WARNING << "Activity coefficient have not converged !" << std::endl << "output can not be trusted\n Difference : " +std::to_string(std::abs(previous_norm - m_second.loggamma.norm())); } } // Set the correct value for the water total saturation if (ideq_w() == no_equation) { xtot(dof_water()) = volume_fraction_water(x); } return AdimensionalSystemSolution(xtot, m_second.secondary_molalities, m_second.loggamma, m_second.ionic_strength, m_second.gas_fugacity, m_second.sorbed_concentrations, m_inert_volume_fraction); } // Water, saturation and density // ============================== scalar_t AdimensionalSystem::density_water() const { return laws::density_water(units::celsius(25.0), length_unit(), mass_unit()); } scalar_t AdimensionalSystem::volume_fraction_water(const Vector& x) const { if (ideq_w() != no_equation) return x(ideq_w()); else return porosity(x); } scalar_t AdimensionalSystem::volume_fraction_mineral(const Vector& x, index_t mineral) const { specmicp_assert(mineral >= 0 and mineral < m_data->nb_mineral()); if (ideq_min(mineral) == no_equation) return 0.0; else return x(ideq_min(mineral)); } scalar_t AdimensionalSystem::sum_volume_fraction_minerals(const Vector& x) const { scalar_t sum_saturations = 0.0; for (index_t mineral: m_data->range_mineral()) { sum_saturations += volume_fraction_mineral(x, mineral); } return sum_saturations; } // Starting guess // ============== void AdimensionalSystem::reasonable_starting_guess(Vector &xtot) { xtot.resize(total_dofs()); xtot(dof_water()) = 0.8; for (index_t i: m_data->range_aqueous_component()) { xtot(dof_component(i)) = -4.0; } if (ideq_surf() != no_equation) xtot(dof_surface()) = std::log10(0.8*surface_total_concentration()); else xtot(dof_surface()) = -HUGE_VAL; if (ideq_electron() != no_equation) xtot(dof_electron()) = -4; else xtot(dof_electron()) = -HUGE_VAL; xtot.segment(offset_minerals(), m_data->nb_mineral()).setZero(); m_second = SecondaryVariables(m_data); } void AdimensionalSystem::reasonable_restarting_guess(Vector& xtot) { std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> dis(-2, 2); xtot(dof_water()) = 0.5; for (index_t i: m_data->range_aqueous_component()) { //if (xtot(dof_component(i)) > 0 or xtot(dof_component(i)) < -9) xtot(i) = get_options().restart_concentration + dis(gen); } if (ideq_surf() != no_equation) xtot(dof_surface()) = std::log10(0.8*surface_total_concentration()); else xtot(dof_surface()) = -HUGE_VAL; if (ideq_electron() != no_equation) xtot(dof_electron()) = -4; else xtot(dof_electron()) = -HUGE_VAL; xtot.segment(offset_minerals(), m_data->nb_mineral()).setZero(); m_second = SecondaryVariables(m_data); } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system.hpp b/src/specmicp/adimensional/adimensional_system.hpp index 94d4423..e866b4d 100644 --- a/src/specmicp/adimensional/adimensional_system.hpp +++ b/src/specmicp/adimensional/adimensional_system.hpp @@ -1,780 +1,782 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ADIMENSIONALSYSTEM_HPP #define SPECMICP_ADIMENSIONALSYSTEM_HPP //! \file adimensional_system.hpp The MiCP program to solve speciation #include "../../types.hpp" #ifndef SPECMICP_DATABASE_HPP #include "database.hpp" #endif #include "../../micpsolver/micpprog.hpp" #include "../../physics/units.hpp" #include "../../utils/options_handler.hpp" #include "adimensional_system_numbering.hpp" #include "adimensional_system_structs.hpp" //! \namespace specmicp main namespace for the SpecMiCP solver namespace specmicp { struct AdimensionalSystemSolution; //! \brief The equilibrium speciation problem //! //! Represent the equilibrium speciation problem as a Mixed Complementarity program //! //! The main variables are : //! - \f$phi_w\f$ the volume fraction of water (total saturation) //! - \f$b_i\f$ the molality of aqueous component //! - \f$phi_m\f$ the volume fraction of mineral //! - \f$s_f\f$ the concentration (molality) of free sorption sites //! //! The solid phase equilibrium is solved by using a complementarity formulation //! \f[ S^t_m \geq 0, \; - \mathrm{SI}_m \geq 0 , \; \mathrm{and} \; - S^t_m \mathrm{SI}_m = 0 \f] //! //! The secondary variables (molalities of secondary aqueous species, gas fugacities, ionic strength, ...) //! are solved using a fixed point iteration at the beginning of each iteration. //! //! This class should only be used through the AdimensionalSystemSolver. class SPECMICP_DLL_LOCAL AdimensionalSystem : public micpsolver::MiCPProg, public AdimemsionalSystemNumbering, public OptionsHandler, private units::UnitBaseClass { public: //! \brief Create a reduced system //! //! \param ptrdata Shared pointer to the thermodynamic database //! \param constraints Constraints to apply to the system //! \param options Numerical options, mainly related to the secondary variables //! \param units_set The set of units AdimensionalSystem(RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemOptions& options=AdimensionalSystemOptions(), const units::UnitsSet& units_set=units::UnitsSet() ); //! \brief Create a reduced system, initialize the system using a previous solution //! //! \param ptrdata Shared pointer to the thermodynamic database //! \param constraints Constraints to apply to the system //! \param previous_solution The previous solution to use for initialization //! \param options Numerical options, mainly related to the secondary variables //! \param units_set The set of units AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemOptions& options=AdimensionalSystemOptions(), const units::UnitsSet& units_set=units::UnitsSet() ); // Variables // ========== //! \name Variables //! \brief How many ? //! //! @{ //! \brief Return the total number of variables index_t total_variables() const {return m_equations.nb_tot_variables;} //! \brief Return the number of 'free' variables (not subject to complementarity conditions) index_t nb_free_variables() const {return m_equations.nb_free_variables;} //! \brief Return the number of variables subjected to the complementarity conditions index_t nb_complementarity_variables() const {return m_equations.nb_complementarity_variables;} //! @} //! \brief Return a pointer to the database RawDatabasePtr get_database() {return m_data;} // The linear system // ================== //! \name Residuals and Jacobian //! \brief Compute the residuals and the jacobian //! //! @{ //! \brief Return the residuals //! //! \param x Vector of the main variables //! \param[out] residual Vector containing the residuals void get_residuals(const Vector& x, Vector& residual); //! \brief Return the jacobian //! //! \param x Vector of the main variables //! \param[out] jacobian Dense matrix representing the jacobian void get_jacobian(Vector& x, Matrix& jacobian); //! \brief Return the residual for the water conservation equation //! //! \param x Vector of the main variables scalar_t residual_water_conservation(const Vector& x) const; //! \brief Return the residual for the water saturation equation //! //! \param x Vector of the main variables scalar_t residual_water_saturation(const Vector& x) const; //! \brief Return the residual for the conservation equation of component (i) //! //! For water (i==0) use the method : 'residual_water' //! \param x Vector of the main variables //! \param i Index of the component (in the database) scalar_t residual_component(const Vector& x, index_t i) const; //! \brief Compute the residual for the surface sorption //! \param x Vector of the main variables scalar_t residual_surface(const Vector& x) const; //! \brief Equilibrium condition for the minerals //! \param x Vector of the main variables //! \param m Index of the mineral (in the database) scalar_t residual_mineral(const Vector& x, index_t m) const; //! \brief Return the residual of the charge conservation equation //! //! This equation may be used instead of a mass conservation equation to //! explicitely enforce the electroneutrality. //! The component corresponding to this equation is called the charge keeper //! \param x Vector of the main variables scalar_t residual_charge_conservation(const Vector& x) const; //! \brief Return the residual corresponding to a fixed fugacity equation //! \param x Vector of the main variables //! \param component Index of the corresponding component (in the database) scalar_t residual_fixed_fugacity(const Vector& x, index_t component) const; //! \brief Return the residual corresponding to a fixed activity equation //! //! If 'component ' is charged, then a charge keeper should be set. //! \param x Vector of the main variables //! \param component Index of the corresponding component (in the database) scalar_t residual_fixed_activity(const Vector& x, index_t component) const; //! \brief Return the residual corresponding to a fixed molality equation //! //! If 'component ' is charged, then a charge keeper should be set. //! \param x Vector of the main variables //! \param component Index of the corresponding component (in the database) scalar_t residual_fixed_molality(const Vector& x, index_t component) const; //! \brief Return the residual corresponding to the electron equation scalar_t residual_electron(const Vector &x) const; //! \brief Compute the jacobian analytically void analytical_jacobian(Vector& x, Matrix& jacobian); //! \brief Compute the jacobian using finite difference void finite_difference_jacobian(Vector& x, Matrix& jacobian); //! \brief Return a scale factor to avoid negative mass during Newton's iteration //! //! \param x Vector of the main variables //! \param update Update of the current iteration double max_lambda(const Vector &x, const Vector &update); //! @} // Getters // ####### // Equation id access // ================== //! \name Equation Id //! \brief The equation id is the row of the equation in the residuals/jacobian //! //! The degree of freedom getter function are inherited from specmicp::AdimensionalSystemNumbering //! @{ //! \brief Return the equation id //! \param i Index of the main variable (in the set of the main variables) index_t ideq(index_t i) const {return m_equations.ideq[i];} //! \brief Return the equation number for conservation of water index_t ideq_w() const {return m_equations.ideq[dof_water()];} //! \brief Return the equation number of component 'i' //! \param i Index of the component (in the database) index_t ideq_paq(index_t i) const { specmicp_assert(i < m_data->nb_component()); return m_equations.ideq[dof_component(i)]; } //! \brief Return the equation number of the electron equation index_t ideq_electron() const { return m_equations.ideq[dof_electron()]; } //! \brief Return the equation number of the free surface concentration index_t ideq_surf() const { return m_equations.ideq[dof_surface()]; } //! \brief Return the equation number of mineral 'm' //! \param m Index of the mineral (in the database) index_t ideq_min(index_t m) const { specmicp_assert(m < m_data->nb_mineral()); return m_equations.ideq[dof_mineral(m)]; } //! @} //! \name Equation type //! \brief Which equation is actually solved //! //! @{ //! \brief Return the type of equation used for the solvent //! //! Can be no equation, mass conservation, saturation of the system, ... //! //! \sa #WaterEquationType, #aqueous_component_equation_type, #AqueousComponentEquationType WaterEquationType water_equation_type() const { return static_cast(m_equations.type_equation(dof_water())); } //! \brief Return the type of equation for aqueous species 'component' //! //! For water used the method #water_equation_type //! \param component Index of the aqueous component (in the database) //! //! \sa #AqueousComponentEquationType, water_equation_type, #WaterEquationType AqueousComponentEquationType aqueous_component_equation_type(index_t component) const { specmicp_assert(component > 0 and component < m_data->nb_component()); return static_cast(m_equations.type_equation(dof_component(component))); } //! \brief Return the type of equation for the electron ElectronEquationType electron_equation_type() const { return static_cast(m_equations.type_equation(dof_electron())); } //! \brief Return true if an equation exist for this component //! //! \param component Index of the component (in the database) bool is_active_component(index_t component) const { specmicp_assert(component < m_data->nb_component() and component > no_species); return m_equations.id_equation(dof_component(component)) != no_equation; } //! \brief Return the surface model SurfaceEquationType surface_model() const { if (ideq_surf() == no_equation) return SurfaceEquationType::NoEquation; return SurfaceEquationType::Equilibrium; } //! \brief Return true if 'component' is the charge keeper //! //! The charge keeper is the component added or removed to satisfy the charge balance //! \param component Index of the aqueous component (in the database) bool is_charge_keeper(index_t component) { return (aqueous_component_equation_type(component) == AqueousComponentEquationType::ChargeBalance); } //! \brief Return the component that does not exist in the solution (inactive dof) const std::vector& get_non_active_component() {return m_equations.nonactive_component;} //! @} // Variables // ========= //! \name2 Main variables //! \brief Access to the main variables //! //! @{ //! \brief Return the volume fraction of water //! //! \param x Vector of the main variables scalar_t volume_fraction_water(const Vector& x) const; //! \brief Return the density of water scalar_t density_water() const; //! \brief Return the volume fraction of a mineral //! //! \param x Vector of the main variables //! \param mineral Index of the mineral (in the database) scalar_t volume_fraction_mineral(const Vector& x, index_t mineral) const; //! \brief Return the volume of minerals //! //! \param mineral Index of the mineral (in the database) scalar_t molar_volume_mineral(index_t mineral) const { return m_scaling_molar_volume*m_data->unsafe_molar_volume_mineral(mineral); } //! \brief Return the sum of saturation of the minerals //! //! This corresponds to the volume fraction of the solid phases (minus the inert phase) //! \param x Vector of the main variables scalar_t sum_volume_fraction_minerals(const Vector& x) const; //! \brief Return the porosity //! //! Computed 'on-the-fly' //! //! \param x Vector of the main variables scalar_t porosity(const Vector& x) const { return 1-sum_volume_fraction_minerals(x)-m_inert_volume_fraction; } //! \brief Return the log_10 of the component molality //! //! \param x Vector of the main variables //! \param component Index of the aqueous component (in the database) scalar_t log_component_molality(const Vector& x, index_t component) const { specmicp_assert(ideq_paq(component) != no_equation and component < m_data->nb_component()); return x(ideq_paq(component)); } //! \brief Return the molality of 'component' //! //! \param x Vector of the main variables //! \param component Index of the aqueous component (in the database) scalar_t component_molality(const Vector& x, index_t component) const { return pow10(log_component_molality(x, component)); } //! \brief Return the concentration of free sorption site scalar_t free_sorption_site_concentration(const Vector& x) const { return pow10(log_free_sorption_site_concentration(x)); } //! \brief Return the log_10 of the free sorption site concentration scalar_t log_free_sorption_site_concentration(const Vector& x) const { specmicp_assert(ideq_surf() != no_equation); return x(ideq_surf()); } //! \brief log activity of the electron scalar_t log_activity_electron(const Vector& x) const { specmicp_assert(ideq_electron() != no_equation); return x(ideq_electron()); } //! \brief return the activity of the electro scalar_t activity_electron(const Vector& x) const { return pow10(log_activity_electron(x)); } //! @} //! \name Secondary variables //! \brief Access to the secondary variables //! //! @{ //! \brief Return the concentration of secondary species 'aqueous' //! //! \param aqueous Index of the secondary aqueous species (in the database) scalar_t secondary_molality(index_t aqueous) const { if (not is_aqueous_active(aqueous)) return 0.0; return m_second.secondary_molalities(dof_aqueous(aqueous)); } //! \brief Return true if 'aqueous' is active //! //! i.e. Return true if all its component are present in the system //! \param aqueous Index of the secondary aqueous species (in the database) bool is_aqueous_active(index_t aqueous) const { return m_equations.active_aqueous[dof_aqueous(aqueous)]; } //! \brief Return log_10(γ_i) where i is a component //! //! γ is the activity coefficient //! \param component Index of the aqueous component (in the database) scalar_t log_gamma_component(index_t component) const { return m_second.loggamma(dof_component_gamma(component)); } //! \brief Return log_10(γ_j) where j is a secondary aqueous species //! //! γ is the activity coefficient //! \param aqueous Index of the secondary aqueous species (in the database) scalar_t log_gamma_secondary(index_t aqueous) const { return m_second.loggamma(dof_aqueous_gamma(aqueous)); } //! \brief Return the ionic strength scalar_t ionic_strength() const noexcept { return m_second.ionic_strength; } //! \brief Return the total concentration of 'component' //! //! Only use this method if the mass is conserved for 'component' //! \param component Index of the aqueous component (in the database) scalar_t total_concentration_bc(index_t component) const { specmicp_assert((component > 0 and aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation) or ( water_equation_type() == WaterEquationType::MassConservation)); return m_fixed_values(component); } //! \brief Return the fixed activity of 'component' //! //! Only use this method if 'component' has a fixed activity constraint //! \param component Index of the aqueous component (in the database) scalar_t fixed_activity_bc(index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedActivity); return m_fixed_values(component); } //! \brief Return the fixed molality of 'component' //! //! Only use this method if 'component' has a fixed molality constraint //! \param component Index of the aqueous component (in the database) scalar_t fixed_molality_bc(index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedMolality); return m_fixed_values(component); } //! \brief Return the fixed fugacity value for 'component' scalar_t fixed_fugacity_bc(index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedFugacity); return m_fixed_values(component); } //! \brief Return the total concentration for the electron scalar_t electron_total_concentration() const { return 0.0; } // Gas // --- //! \brief Return the fugacity of 'gas' //! //! \param gas Index of the gas (in the database) scalar_t gas_fugacity(index_t gas) const { return m_second.gas_fugacity(gas); } //! \brief Return the concentration of 'gas' in the system //! //! \param gas Index of the gas (in the database) scalar_t gas_concentration(index_t gas) const { return m_second.gas_concentration(gas); } //! \brief Return true if gas is active //! //! \param gas Index of the gas (in the database) bool is_active_gas(index_t gas) const { return m_equations.active_gas[gas]; } //! \brief Return the volume fraction (total saturation) of the gas phase scalar_t volume_fraction_gas_phase() const noexcept { return m_second.volume_fraction_gas; } // Sorbed species // -------------- //! \brief Return the surface total concentration const scalar_t& surface_total_concentration() const { return m_fixed_values(dof_surface()); } //! \brief Return true if 'sorbed' is an active species //! \param sorbed Index of the sorbed species (in the database) bool is_active_sorbed(index_t sorbed) const { return m_equations.active_sorbed[sorbed]; } //! \brief Return the molality of the sorbed species 'sorbed' //! \param sorbed Index of the sorbed species (in the database) const scalar_t& sorbed_species_concentration(index_t sorbed) const { return m_second.sorbed_concentrations(sorbed); } // Pressure and temperature // ------------------------ //! \brief Return the gas pressure //! //! This is a fixed value (1 atm) scalar_t gas_total_pressure() const { return 1.01325e5; // Note : all pressure are in pascal, unit conversion is done for the concentration } //! \brief Return the temperature //! //! This is a fixed value (25°C) scalar_t temperature() const noexcept { return 273.16+25; } //! @} // Solution // ================= //! \brief Return the equilibrium state of the system, the Solution of the speciation problem //! //! \param xtot the complete set of main variables //! \param x the reduced set of main variables, only the variables with an equation AdimensionalSystemSolution get_solution(Vector& xtot, const Vector& x); //! \name Secondary variables computation //! \brief Algorithms to compute the secondary variables //! //! @{ //! \brief Compute the ionic strength //! //! \param x Vector of the main variables void set_ionic_strength(const Vector& x); //! \brief Compute the activity coefficients //! //! \param x Vector of the main variables void compute_log_gamma(const Vector& x); //! \brief Compute the secondary aqueous species molalities //! //! \param x Vector of the main variables void set_secondary_concentration(const Vector& x); //! \brief Compute the secondary variables //! //! \param x Vector of the main variables void set_secondary_variables(const Vector& x); //! \brief Compute the gas phase volume fraction //! //! \param x Vector of the main variables void set_volume_fraction_gas_phase(const Vector& x); //! \brief Compute the fugacity for all the gas //! //! \param x Vector of the main variables void set_pressure_fugacity(const Vector& x); //! \brief Compute the sorbed species concentrations //! //! \param x Vector of the main variables void set_sorbed_concentrations(const Vector& x); //! \brief This function is called at the beginning of each iteration by the solver //! //! It does the fixed-point iteration to compute the secondary variables //! \param x Vector of the main variables //! \param norm_residual Norm of the current residuals bool hook_start_iteration(const Vector &x, scalar_t norm_residual); //! @} //! \brief A reasonable (well... maybe...) starting guess //! //! \param xtot Vector of the main variables //! \sa #reasonable_starting_guess void reasonable_starting_guess(Vector& xtot); //! \brief A reasonable (maybe...) restarting guess //! //! \param xtot Vector of the main variables //! \sa #reasonable_restarting_guess void reasonable_restarting_guess(Vector& xtot); //! \brief Set the units void set_units(const units::UnitsSet& unit_set); // Private Members and attributes // ############################## private: // scaling factors void compute_scaling_factors(); //! \brief Sum of the aqueous molalities weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_aqueous(index_t component) const; //! \brief Sum of the sorbed concentration weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_sorbed(index_t component) const; //! \brief Sum of the mineral concentration weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_mineral(const Vector& x, index_t component) const; //! \brief Sum of the gas concentration weigthed by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_gas(index_t component) const; //! \brief Derivative of the aqueous weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_aqueous scalar_t diff_weigthed_sum_aqueous(index_t diff_component, index_t component) const; //! \brief Derivative of the sorbed weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_sorbed scalar_t diff_weigthed_sum_sorbed(index_t diff_component, index_t component) const; //! \brief Derivative of the sorbed weigthed sum with respect to the free surface concentration //! \sa weigthed_sum_sorbed scalar_t diff_surface_weigthed_sum_sorbed(index_t component) const; //! \brief Derivative of the gas weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_sorbed scalar_t diff_weigthed_sum_gas(index_t diff_component, index_t component) const; // Jacobian // ######## //! \brief Compute the water equation contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_water(Vector& x, Matrix& jacobian); //! \brief Compute the aqueous components equation contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_aqueous_components(Vector& x, Matrix& jacobian); //! \brief Compute the mineral equations contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_minerals(Vector& x, Matrix& jacobian); //! \brief Compute the contribution of the surface sorption equation to te Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_surface(Vector& x, Matrix& jacobian); //! \brief Compute the contribution of the electron equation to te Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_electron(Vector& x, Matrix& jacobian); // Equation numbering // ################## //! \brief Number the equations //! \param constraints the constraints to apply to the system //! \sa number_eq_aqueous_component void number_eq(const AdimensionalSystemConstraints& constraints); //! \brief Number the equations for the aqueous components //! \param constraints the constraints to apply to the system //! \param[in,out] neq the number of equations in the system //! \sa number_eq void number_eq_aqueous_component( const AdimensionalSystemConstraints& constraints, index_t& neq ); // Setter // ###### // main variables // -------------- // they are set by the solver // Secondary variables // ------------------- //! \brief Return a reference to log_10(γ_i) where i is a component scalar_t& log_gamma_component(index_t component) { return m_second.loggamma(dof_component_gamma(component)); } //! \brief Return a reference to log_10(γ_j) where j is a secondary aqueous species scalar_t& log_gamma_secondary(index_t aqueous) { return m_second.loggamma(dof_aqueous_gamma(aqueous)); } //! \brief Return a reference to the ionic strength scalar_t& ionic_strength() { return m_second.ionic_strength; } // Attributes // ########## //! \struct SecondaryVariables //! \brief Contains information about the secondary variables struct SecondaryVariables { scalar_t ionic_strength {0.0}; //!< The ionic Strength scalar_t volume_fraction_gas {0.0}; //!< The gas saturation scalar_t porosity {0.0}; //!< The porosity Vector secondary_molalities; //!< The secondary molalities Vector loggamma; //!< The log of activity coefficients Vector gas_fugacity; //!< The gas fugacities Vector gas_concentration; //!< The gas concentrations Vector sorbed_concentrations; //!< The sorbed concentrations //! \brief Initialization without a previous solution SecondaryVariables(const RawDatabasePtr& data); //! \brief Initialization with a previous solution SecondaryVariables(const AdimensionalSystemSolution& previous_solution); }; //! \struct IdEquations //! \brief BookKeeper for the equations id and type struct IdEquations { bool use_water_pressure_model {false}; water_partial_pressure_f water_pressure_model {nullptr}; index_t nb_tot_variables {0}; index_t nb_free_variables {0}; index_t nb_complementarity_variables {0}; std::vector ideq; std::vector component_equation_type; std::vector fixed_activity_species; std::vector nonactive_component {}; std::vector active_aqueous; std::vector active_gas; std::vector active_sorbed; //! \brief Initialize the data structure IdEquations(index_t nb_dofs, const RawDatabasePtr& data); //! \brief Return the equation id const index_t& id_equation(index_t dof) const { return ideq[dof]; } //! \brief Return a reference to the equation id index_t& id_equation(index_t dof) { return ideq[dof]; } //! \brief Return a reference to the type of equation of 'dof' index_t& type_equation(index_t dof) { return component_equation_type[dof]; } //! \brief Return the equation type for 'dof' index_t type_equation(index_t dof) const { return component_equation_type[dof]; } //! \brief Return the related species for dof //! //! The exact meaning of this relation is dependant upon the equation type index_t& related_species(index_t dof) { return fixed_activity_species[dof]; } //! \brief Add a non active component to the system void add_non_active_component(index_t id) { nonactive_component.push_back(id); } //! \brief Add an equation void add_equation(index_t id, index_t *neq) { ideq[id] = *neq; ++(*neq); } //! \brief Set the active flag of aqueous species 'id' to 'is_active' void set_aqueous_active(index_t id, bool is_active) { active_aqueous[id] = is_active; } //! \brief Set the active flag of gas 'id' to 'is_active' void set_gas_active(index_t id, bool is_active) { active_gas[id] = is_active; } //! \brief Set the active flag of sorbed species 'id' to 'is_active' void set_sorbed_active(index_t id, bool is_active) { active_sorbed[id] = is_active; } }; bool not_in_linesearch {true}; scalar_t m_inert_volume_fraction; scalar_t m_scaling_molar_volume {1.0}; scalar_t m_scaling_gas {1.0}; Vector m_fixed_values {}; SecondaryVariables m_second; IdEquations m_equations; }; } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEM_HPP diff --git a/src/specmicp/adimensional/adimensional_system_numbering.hpp b/src/specmicp/adimensional/adimensional_system_numbering.hpp index c6fdbce..f89d75f 100644 --- a/src/specmicp/adimensional/adimensional_system_numbering.hpp +++ b/src/specmicp/adimensional/adimensional_system_numbering.hpp @@ -1,120 +1,122 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ADIMENSIONALSYSTEMNUMBERING #define SPECMICP_ADIMENSIONALSYSTEMNUMBERING #include "../../types.hpp" #ifndef SPECMICP_DATABASE_HPP #include "../../database.hpp" #endif namespace specmicp { //! \brief The equation numbering scheme for the adimensional system //! //! This is the numbering of the main variables (the non-reduced vector) class AdimemsionalSystemNumbering { public: //! \brief Initialize the numbering scheme //! \param ptr_database shared_ptr to the database container AdimemsionalSystemNumbering(RawDatabasePtr ptr_database): m_data(ptr_database) {} //! \brief Return the dof for water conservation index_t dof_water() const noexcept {return m_data->water_index();} //! \brief Return the dof corresponding to the component conservation //! \param component Index of the component index_t dof_component(index_t component) const NOEXCEPT { specmicp_assert_component_bounds(component, m_data); return component; } //! \brief Return the dof corresponding to the electron activity index_t dof_electron() const noexcept { return m_data->electron_index(); } //! \brief Return the dof corresponding to the sorption sites conservation index_t dof_surface() const noexcept { return m_data->nb_component(); } //! \brief Return the offset for the dof of minerals //! \sa dof_mineral index_t offset_minerals() const noexcept { return m_data->nb_component()+1; } //! \brief Return the dof for mineral 'mineral' //! \param mineral Index of the mineral (in the database) index_t dof_mineral(index_t mineral) const NOEXCEPT { specmicp_assert_mineral_bounds(mineral, m_data); return offset_minerals()+mineral; } //! \brief Return the number of dofs index_t total_dofs() const noexcept { return m_data->nb_component()+m_data->nb_mineral()+1; } // secondary species //! \brief dof of the activitiy coefficient for 'component' //! \param component Index of the component (in the database) index_t dof_component_gamma(index_t component) const { specmicp_assert_component_bounds(component, m_data); return component; } //! \brief dof of a secondary aqueous species //! \param aqueous Index of the aqueous species (in the database) index_t dof_aqueous(index_t aqueous) const { specmicp_assert(aqueous < m_data->nb_aqueous()); return aqueous; } //! \brief dof of the activity coefficient for 'aqueous' //! \param aqueous Index of the aqueous species (in the database) index_t dof_aqueous_gamma(index_t aqueous) const { specmicp_assert_aqueous_bounds(aqueous, m_data); return m_data->nb_component()+aqueous; } //! \brief Return the database RawDatabasePtr get_database() { return m_data; } protected: RawDatabasePtr m_data; }; } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEMNUMBERING diff --git a/src/specmicp/adimensional/adimensional_system_pcfm.cpp b/src/specmicp/adimensional/adimensional_system_pcfm.cpp index 8f902cf..e300bc6 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm.cpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm.cpp @@ -1,199 +1,201 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "adimensional_system_pcfm.hpp" #include "adimensional_system.hpp" #include #include "../../utils/log.hpp" namespace specmicp { // AdimensionalSystemPCFM AdimensionalSystemPCFM::AdimensionalSystemPCFM(std::shared_ptr program): m_data(program->get_database()), m_program(program) { check_validity(); } AdimensionalSystemPCFM::AdimensionalSystemPCFM( std::shared_ptr program, const PCFMOptions& options): OptionsHandler(options), m_data(program->get_database()), m_program(program) { check_validity(); } bool AdimensionalSystemPCFM::check_validity() { bool is_valid = true; if (m_program->water_equation_type() != WaterEquationType::NoEquation) { ERROR << "The implementation of the positive continuous fraction method does not compute the conservation of water"; is_valid = false; } if (m_program->get_database()->nb_mineral() != 0.0) { WARNING << "The implementation of the positive continuous fraction method does not compute the solid phase assemblage"; is_valid = false; } return is_valid; } PCFMReturnCode AdimensionalSystemPCFM::solve(Vector &x) { index_t cnt = 0; m_errors.setZero(m_program->total_variables()); while (cnt < get_options().max_iterations) { one_iteration(x); scalar_t error = m_errors.lpNorm(); DEBUG << "PCFM error : " << error << " ?< " << get_options().tolerance; if (not std::isfinite(error)) return PCFMReturnCode::Error; if (error < get_options().tolerance) return PCFMReturnCode::Success; ++cnt; } if (cnt == get_options().max_iterations) return PCFMReturnCode::MaxIterationsReached; return PCFMReturnCode::NotConvergedYet; } void AdimensionalSystemPCFM::one_iteration(Vector &x) { m_program->set_secondary_concentration(x); m_program->set_sorbed_concentrations(x); for (index_t component: m_data->range_aqueous_component()) { if (m_program->ideq_paq(component) != no_equation) { solve_component(component, x); } } if (m_program->ideq_surf() != no_equation) { solve_surface(x); } } void AdimensionalSystemPCFM::solve_component(index_t component, Vector& x) { specmicp_assert(component > 0 and component < m_data->nb_component() and "Must be an aqueous component"); specmicp_assert(m_program->ideq_paq(component) != no_equation and "No corresponding equation for this component"); specmicp_assert(m_program->aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation); const scalar_t total_concentration = m_program->total_concentration_bc(component); scalar_t conc_w = m_program->density_water()*m_program->volume_fraction_water(x); scalar_t sum_reac = conc_w*m_program->component_molality(x, component); scalar_t sum_prod = 0.0; // compute the lhs and rhs of the mass balance so that every contribution is positive if (total_concentration >= 0) { sum_prod += total_concentration; } else { sum_reac -= total_concentration; } for (index_t aqueous: m_data->range_aqueous()) { if (m_data->nu_aqueous(aqueous, component) > 0) sum_reac += conc_w*m_data->nu_aqueous(aqueous, component)*m_program->secondary_molality(aqueous); else sum_prod -= conc_w*m_data->nu_aqueous(aqueous, component)*m_program->secondary_molality(aqueous); } for (index_t sorbed: m_data->range_sorbed()) { if (m_data->nu_sorbed(sorbed, component) > 0) sum_reac += m_data->nu_sorbed(sorbed, component)*m_program->sorbed_species_concentration(sorbed); else sum_prod -= m_data->nu_sorbed(sorbed, component)*m_program->sorbed_species_concentration(sorbed); } specmicp_assert(std::isfinite(sum_reac)); specmicp_assert(sum_reac > 0.0 && "Sum of reactants concentration should be positive"); specmicp_assert(sum_prod > 0.0 && "Sum of products should be positive"); // compute the step size scalar_t theta; const scalar_t factor = (sum_prod/sum_reac); if (sum_reac > sum_prod) theta = 0.9 - 0.8*factor; else theta = 0.9 - 0.8/factor; // theta *= get_options().theta_factor; scalar_t new_conc = (1-theta + theta*factor)*m_program->component_molality(x, component); x(m_program->ideq_paq(component)) = std::log10(new_conc); m_errors(m_program->ideq_paq(component)) = std::abs(sum_reac - sum_prod)/(sum_reac + sum_prod); } void AdimensionalSystemPCFM::solve_surface(Vector& x) { specmicp_assert(m_program->ideq_surf() != no_equation); specmicp_assert(m_program->surface_total_concentration() > 0); scalar_t sum_prod = m_program->surface_total_concentration(); scalar_t sum_reac = m_program->free_sorption_site_concentration(x); for (index_t sorbed: m_data->range_sorbed()) { sum_reac += m_data->nb_sorption_sites(sorbed)*m_program->sorbed_species_concentration(sorbed); } specmicp_assert(std::isfinite(sum_reac)); specmicp_assert(sum_reac > 0.0 && "Sum of reactants concentration should be positive"); specmicp_assert(sum_prod > 0.0 && "Sum of products should be positive"); scalar_t theta; const scalar_t factor = (sum_prod/sum_reac); if (sum_reac > sum_prod) theta = 0.9 - 0.8*factor; else theta = 0.9 - 0.8/factor; // theta *= get_options().theta_factor; scalar_t new_conc = (1-theta + theta*factor)*m_program->free_sorption_site_concentration(x); x(m_program->ideq_surf()) = std::log10(new_conc); m_errors(m_program->ideq_surf()) = std::abs(sum_reac - sum_prod)/(sum_reac + sum_prod); } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_pcfm.hpp b/src/specmicp/adimensional/adimensional_system_pcfm.hpp index 1a501f7..857b575 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm.hpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP #define SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP #include "../../database.hpp" #include "adimensional_system_pcfm_structs.hpp" #include "../../utils/options_handler.hpp" //! \file adimensional_system_pcfm.hpp The positive continuous fraction method namespace specmicp { // forward declaration class AdimensionalSystem; //! \brief The positive continuous fraction method //! //! It is particularly well adapted for aqueous only systems //! //! References : //! - Carrayrou (2002) class SPECMICP_DLL_LOCAL AdimensionalSystemPCFM: public OptionsHandler { public: AdimensionalSystemPCFM(std::shared_ptr program); AdimensionalSystemPCFM( std::shared_ptr program, const PCFMOptions& options); //! \brief Pre-solve the problem //! \param x Vector of the main variable (should be initialized) PCFMReturnCode solve(Vector& x); //! \brief Run one iteration of the PCFM method void one_iteration(Vector& x); //! \brief Run the PCFM method for one component void solve_component(index_t component, Vector& x); //! \brief Run the PCFM method for the surface equation void solve_surface(Vector& x); //! \brief Check the validity of the problem; for now just print error message //! \return Return true if the problem is true bool check_validity(); private: RawDatabasePtr m_data; std::shared_ptr m_program; Vector m_errors {}; }; //! \brief Initialize a system using the positive continuous fraction method //! //! \param program shared_ptr to the program //! \param x Vector of the main variables (should be initialized) //! //! \sa AdimensionalSystemPCFM inline PCFMReturnCode positive_continuous_fraction_method( std::shared_ptr program, Vector& x ) { return AdimensionalSystemPCFM(program).solve(x); } } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP diff --git a/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp b/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp index 81b54b0..360954c 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp @@ -1,74 +1,76 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_ADIMENSIONALSYSTEMPCFMSTRUCTS_HPP #define SPECMICP_ADIMENSIONALSYSTEMPCFMSTRUCTS_HPP #include "../../types.hpp" //! \file adimensional_system_pcfm_structs.hpp //! \brief Enum and structs used by the pcfm solver //! \sa specmicp::AdimensionalSystemPCFM namespace specmicp { //! \enum PCFMReturnCode //! \brief The return codes for the positive continuous fraction method //! \sa specmicp::AdimensionalSystemPCFM enum class PCFMReturnCode { LolThatsNotSupposedToHappen, //! Bummer... Error, //!< Some kind of error happended MaxIterationsReached, //!< The maximum number of iterations was reached NotConvergedYet, //!< The problem has not converged yet Success //!< Success ! }; //! \struct PCFMOptions //! \brief Options for the Positive continuous fraction method //! \sa specmicp::AdimensionalSystemPCFM struct PCFMOptions { index_t max_iterations; //!< The maximum number of iterations scalar_t tolerance; //!< The tolerance (should be relatively high around 0.5) scalar_t theta_factor; //!< multiplicatif factor for theta PCFMOptions(): max_iterations(100), tolerance(0.5), theta_factor(0.25) {} }; } // end namespace specmicp #endif diff --git a/src/specmicp/adimensional/adimensional_system_solution.hpp b/src/specmicp/adimensional/adimensional_system_solution.hpp index 3e890f0..7d59e53 100644 --- a/src/specmicp/adimensional/adimensional_system_solution.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution.hpp @@ -1,85 +1,87 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP #include "../../types.hpp" //! \file adimensional_system_solution.hpp Structure to contain the solution returned by AdimensionalSystemSolution namespace specmicp { //! \brief Solution of an adimensional system struct SPECMICP_DLL_PUBLIC AdimensionalSystemSolution { bool is_valid {false}; //!< True if this is a valid solution scalar_t inert_volume_fraction; //!< Inert volume fraction scalar_t ionic_strength; //!< Ionic strength Vector main_variables; //!< The main variables Vector secondary_molalities; //!< Molalities of secondary aqueous Vector log_gamma; //!< Log_10 of activities coefficients Vector gas_fugacities; //!< Gas fugacities Vector sorbed_molalities; //!< Sorbed molalities //! \brief Build an empty solution AdimensionalSystemSolution(): is_valid(false) {} //! \brief Build a valid solution AdimensionalSystemSolution( const Vector& variables, const Vector& aqueous_molalities, const Vector& loggama, scalar_t the_ionic_strength, const Vector& fugacities, const Vector& sorbed_species_molalities, scalar_t the_inert_volume_fraction=0.0 ): inert_volume_fraction(the_inert_volume_fraction), ionic_strength(the_ionic_strength), main_variables(variables), secondary_molalities(aqueous_molalities), log_gamma(loggama), gas_fugacities(fugacities), sorbed_molalities(sorbed_species_molalities) { is_valid = true; } }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp b/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp index 34faf5c..900cca1 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp +++ b/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp @@ -1,228 +1,230 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "adimensional_system_solution_extractor.hpp" #include "../../physics/laws.hpp" #include "../../database/database.hpp" namespace specmicp { scalar_t AdimensionalSystemSolutionExtractor::density_water() const { return laws::density_water(units::celsius(25.0), length_unit(), mass_unit()); } scalar_t AdimensionalSystemSolutionExtractor::mass_concentration_water() const { return density_water()*volume_fraction_water(); } scalar_t AdimensionalSystemSolutionExtractor::pH() const { // find species responsible for pH index_t id = m_data->get_id_component("HO[-]"); if (id != no_species) { return 14+log_activity_component(id); } else { id = m_data->get_id_component("H[+]"); if (id != no_species) return -log_activity_component(id); throw std::runtime_error("No component corresponding to the dissociation of water !"); } } scalar_t AdimensionalSystemSolutionExtractor::total_saturation_minerals() const { return m_solution.main_variables.segment(offset_minerals(), m_data->nb_mineral()).sum(); } scalar_t AdimensionalSystemSolutionExtractor::mole_concentration_mineral(index_t mineral) const { return volume_fraction_mineral(mineral)/m_data->molar_volume_mineral(mineral, length_unit()); } scalar_t AdimensionalSystemSolutionExtractor::mass_concentration_mineral(index_t mineral) const { return mole_concentration_mineral(mineral)*m_data->molar_mass_mineral(mineral, mass_unit()); } //! \brief Return the total aqueous concentration scalar_t AdimensionalSystemSolutionExtractor::total_aqueous_concentration(index_t component) const { scalar_t conc = molality_component(component); for (index_t aqueous: m_data->range_aqueous()) { if (m_data->nu_aqueous(aqueous, component) != 0.0) { conc += m_data->nu_aqueous(aqueous, component)*molality_aqueous(aqueous); } } return conc; } //! \brief Return the total solid concentration scalar_t AdimensionalSystemSolutionExtractor::total_solid_concentration(index_t component) const { scalar_t conc= 0; for (index_t mineral: m_data->range_mineral()) { if (m_data->nu_mineral(mineral, component) != 0.0) { conc += m_data->nu_mineral(mineral, component) * volume_fraction_mineral(mineral) / m_data->molar_volume_mineral(mineral, length_unit()); } } return conc; } //! \brief Return the total immobile concentration scalar_t AdimensionalSystemSolutionExtractor::total_immobile_concentration(index_t component) const { scalar_t conc= total_solid_concentration(component); const scalar_t conc_w = density_water()*volume_fraction_water(); for (index_t sorbed: m_data->range_sorbed()) { if (m_data->nu_sorbed(sorbed, component) != 0.0) { conc += conc_w*m_data->nu_sorbed(sorbed, component) * molality_sorbed_species(sorbed); } } return conc; } //! Return the saturation index for 'mineral' scalar_t AdimensionalSystemSolutionExtractor::saturation_index(index_t mineral) const { scalar_t saturation_index = - m_data->logk_mineral(mineral); for (index_t component: m_data->range_aqueous_component()) { if (m_data->nu_mineral(mineral, component) == 0.0) continue; saturation_index += m_data->nu_mineral(mineral, component) * log_activity_component(component); } return saturation_index; } //! Return the saturation index for 'mineral_kinetic' scalar_t AdimensionalSystemSolutionExtractor::saturation_index_kinetic(index_t mineral_kinetic) const { scalar_t saturation_index = - m_data->logk_mineral_kinetic(mineral_kinetic); for (index_t component: m_data->range_aqueous_component()) { if (m_data->nu_mineral_kinetic(mineral_kinetic, component) == 0.0) continue; saturation_index += m_data->nu_mineral_kinetic(mineral_kinetic, component) * log_activity_component(component); } return saturation_index; } // ########################### // // // // Modificator // // // // ########################### // void AdimensionalSystemSolutionModificator::scale_total_concentration( index_t component, scalar_t new_value) { const scalar_t old_value = total_solid_concentration(component); const scalar_t factor = new_value/old_value; m_nonconst_solution.main_variables.segment(dof_mineral(0), m_data->nb_mineral()) *= factor; } void AdimensionalSystemSolutionModificator::remove_solids() { m_nonconst_solution.main_variables.segment(dof_mineral(0), m_data->nb_mineral()).setZero(); } Vector AdimensionalSystemSolutionModificator::set_minerals_kinetics(std::vector& list_species) { index_t nb_kinetics = list_species.size(); index_t nb_new_mineral = m_data->nb_mineral() - nb_kinetics; std::vector minerals_to_keep; minerals_to_keep.reserve(nb_new_mineral); std::vector new_kinetics_index(nb_kinetics, no_species); Vector saturation_kinetics(nb_kinetics); index_t new_ind_eq = offset_minerals(); index_t new_ind_kin = 0; index_t tot_ind_kin = m_data->nb_mineral_kinetic(); // ###TODO optimize for (index_t mineral: m_data->range_mineral()) { auto is_kin = std::find(list_species.begin(), list_species.end(), mineral); // If mineral is still at equilibrium if (is_kin == list_species.end()) { minerals_to_keep.push_back(mineral); m_nonconst_solution.main_variables(new_ind_eq) = volume_fraction_mineral(mineral); ++new_ind_eq; } // If mineral is governed by kinetics else { saturation_kinetics(new_ind_kin) = volume_fraction_mineral(mineral); ++new_ind_kin; // save the new index (index in the kinetics vector) // The order is conserved ! new_kinetics_index[is_kin - list_species.begin()] = tot_ind_kin; ++tot_ind_kin; } } // change the database database::Database dbhandler(m_data); dbhandler.minerals_keep_only(minerals_to_keep); specmicp_assert(new_ind_eq == total_dofs()); // update the list of species list_species.swap(new_kinetics_index); // resize m_nonconst_solution.main_variables.conservativeResize(total_dofs()); return saturation_kinetics; } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp b/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp index 201c1cc..1d4fbe4 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp @@ -1,356 +1,358 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP #include "../../types.hpp" #include "../../database.hpp" #include "adimensional_system_solution.hpp" #include "../../physics/units.hpp" #include "../../physics/constants.hpp" #include "adimensional_system_numbering.hpp" //! \file adimensional_system_solution_extractor.hpp Obtain data from AdimensionalSystemSolution namespace specmicp { //! \class AdimensionalSystemSolutionExtractor //! \brief Obtain physical variables from AdimensionalSystemSolution //! //! This class can't modify the solution, use specmicp::AdimensionalSystemSolutionModificator for this. //! //! \ingroup specmicp_api //! \sa specmicp::AdimensionalSystemSolutionModificator class SPECMICP_DLL_PUBLIC AdimensionalSystemSolutionExtractor: public AdimemsionalSystemNumbering, public units::UnitBaseClass { public: // public members // ############### //! \brief Constructor //! //! \param solution Reference to a solution from the AdimensionalSystemSolution //! \param thedatabase shared_ptr to the database //! \param units_set Units used by the solver AdimensionalSystemSolutionExtractor( const AdimensionalSystemSolution& solution, RawDatabasePtr thedatabase, units::UnitsSet units_set): AdimemsionalSystemNumbering(thedatabase), units::UnitBaseClass(units_set), m_solution(solution) {} // Primary variables // ================= // water // ------ //! \brief Return the total saturation of water //! //! \deprecated, use the correct name : volume fraction scalar_t total_saturation_water() const SPECMICP_DEPRECATED("Use volume_fraction_water instead") { return m_solution.main_variables(dof_water());} //! \brief Return the volume fraction of water scalar_t volume_fraction_water() const { return m_solution.main_variables(dof_water());} //! \brief Return the density of water scalar_t density_water() const; // electron // --------- //! \brief Return the log of the activity electron scalar_t log_activity_electron() const { return m_solution.main_variables(dof_electron()); } //! \brief Return the activity of the electron scalar_t activity_electron() const { return pow10(log_activity_electron()); } //! \brief Return the pE scalar_t pE() const { return -log_activity_electron(); } scalar_t Eh() const { return std::log(10.0)*constants::gas_constant*units::celsius(25.0)/constants::faraday_constant*pE(); } // component // --------- //! \brief Return the log_10 of the molality of 'component' scalar_t log_molality_component(index_t component) const { if (component == m_data->water_index()) return std::log10(1.0/m_data->molar_mass_basis(component, mass_unit())); else if (component == m_data->electron_index()) return -HUGE_VAL; return m_solution.main_variables(dof_component(component));} //! \brief Return the molality of 'component' scalar_t molality_component(index_t component) const { if (component == m_data->water_index()) return 1.0/m_data->molar_mass_basis(component, mass_unit()); else if (component == m_data->electron_index()) return 0.0; return pow10(log_molality_component(component)); } // solid phases // ------------ //! \brief Return the total saturation of 'mineral' //! //! \deprecated, use the volume fraction instead scalar_t total_saturation_mineral(index_t mineral) const SPECMICP_DEPRECATED("Use volume_fraction_mineral instead") { return m_solution.main_variables(dof_mineral(mineral)); } //! \brief Return the volume fraction of 'mineral' scalar_t volume_fraction_mineral(index_t mineral) const { return m_solution.main_variables(dof_mineral(mineral)); } // surface // ------- //! \brief Return the concentration of free surface scalar_t log_free_surface_concentration() const { return m_solution.main_variables(dof_surface()); } //! \brief Return the concentration of free surface scalar_t free_surface_concentration() const { return pow10(m_solution.main_variables(dof_surface())); } // Secondary variables // =================== //! \brief Return the ionic strength of the solution scalar_t ionic_strength() const {return m_solution.ionic_strength;} // component // --------- //! \brief Return the log_10 of the activity coefficient of 'component' scalar_t log_activity_coefficient_component(index_t component) const { return m_solution.log_gamma(dof_component_gamma(component)); } //! \brief Return the activity coefficient of 'component' scalar_t activity_coefficient_component(index_t component) const { return pow10(log_activity_coefficient_component(component)); } //! \brief Return the log_10 of the activity of 'component scalar_t log_activity_component(index_t component) const { return log_molality_component(component) + log_activity_coefficient_component(component); } //! \brief Return the activity of 'component' scalar_t activity_component(index_t component) const { return pow10(log_activity_component(component)); } // aqueous species // --------------- //! \brief Return the molality of secondary specis 'aqueous' scalar_t molality_aqueous(index_t aqueous) const { return m_solution.secondary_molalities(dof_aqueous(aqueous));} //! \brief Return the log10 of the activity ocefficient of secondary species 'aqueous' scalar_t log_activity_coefficient_aqueous(index_t aqueous) const { return m_solution.log_gamma(dof_aqueous_gamma(aqueous)); } //! \brief Return the activity coefficient of secondary species 'aqueous' scalar_t activity_coefficient_aqueous(index_t aqueous) const { return pow10(log_activity_coefficient_aqueous(aqueous)); } //! \brief Return the activity of secondary species 'aqueous' scalar_t activity_aqueous(index_t aqueous) const { return activity_coefficient_aqueous(aqueous)*molality_aqueous(aqueous); } // gas fugacity // ------------- //! \brief Return fugacity for 'gas' scalar_t fugacity_gas(index_t gas) const { return m_solution.gas_fugacities(gas); } // Sorbed species // -------------- //! \brief Return sorbed species molalities for 'sorbed' scalar_t molality_sorbed_species(index_t sorbed) const { return m_solution.sorbed_molalities(sorbed); } // Tertiary variables // ================== // Water // ----- //! \brief Return the saturation of water scalar_t saturation_water() const {return volume_fraction_water()/porosity();} //! \brief Return the mass concentration of water scalar_t mass_concentration_water() const; //! \brief Return the pH of the solution scalar_t pH() const; // Component // --------- //! \brief Return the total aqueous concentration scalar_t total_aqueous_concentration(index_t component) const; //! \brief Return the total solid concentration scalar_t total_solid_concentration(index_t component) const; //! \brief Return the total immobile concentration scalar_t total_immobile_concentration(index_t component) const; // Gas phase // --------- //! \brief Return the saturation of the gas phase scalar_t saturation_gas_phase() const {return 1-saturation_water();} //! \brief Return the total saturation of the gas phase //! \deprecated use volume fraction instead scalar_t total_saturation_gas_phase() const SPECMICP_DEPRECATED("Use volume fraction gas phase instead") { return porosity() - saturation_water(); } //! \brief Return the volume fraction occupied by the gas phase scalar_t volume_fraction_gas_phase() const { return porosity() - volume_fraction_water(); } // Component // --------- // Solid phases // ------------ //! \brief Return the concentration of 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t mole_concentration_mineral(index_t mineral) const; //! \brief Return the mass concentration of 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t mass_concentration_mineral(index_t mineral) const; //! \brief Return the total saturation of all minerals //! Deprecated, use the volume fraction function instead scalar_t total_saturation_minerals() const; //! \brief Return the volume fraction occupied by the minerals scalar_t volume_fraction_minerals() const {return total_saturation_minerals();} //! \brief Return the inert volume fraction scalar_t volume_fraction_inert() const {return m_solution.inert_volume_fraction;} //! \brief Return the porosity scalar_t porosity() const {return 1 - total_saturation_minerals() - volume_fraction_inert();} //! \brief Return the saturation index for 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t saturation_index(index_t mineral) const; //! \brief Return the saturation index for 'mineral_kinetic' //! //! \param mineral_kinetic Index of the mineral governed by the kinetic (in the database) scalar_t saturation_index_kinetic(index_t mineral_kinetic) const; //! \brief Return the vector of main variables, can be used to initialize the solver Vector get_main_variables() const {return m_solution.main_variables;} //! \brief Return a copy of the solution AdimensionalSystemSolution get_solution() const {return m_solution;} protected: // private attributes // ################## const AdimensionalSystemSolution& m_solution; }; //! \class AdimensionalSystemSolutionModificator //! \brief Special class to modify (scale) the solution //! //! The set of modification are limited to straightforward modification that does not modify the equilibrium //! //! \sa AdimensionalSystemExtractor //! \ingroup specmicp_api class SPECMICP_DLL_PUBLIC AdimensionalSystemSolutionModificator: public AdimensionalSystemSolutionExtractor { public: AdimensionalSystemSolutionModificator( AdimensionalSystemSolution& solution, RawDatabasePtr thedatabase, units::UnitsSet units_set): AdimensionalSystemSolutionExtractor(solution, thedatabase, units_set), m_nonconst_solution(solution) {} //! \brief Scale the solid phases with respect to the total solid concentration of a component //! //! \param component Index of the component (in the database) //! \param new_value New value of the total solid concentration void scale_total_concentration(index_t component, scalar_t new_value); //! \brief Remove the solid phases void remove_solids(); //! \brief Set some species to be considered as governed by kinetics //! //! \param[in,out] list_species list of minerals to flag as kinetics, //! The list will contain the new indexes of the corresponding solid phases; //! \return the vector of saturation //! //! This function modify the databse Vector set_minerals_kinetics(std::vector& list_species); private: AdimensionalSystemSolution& m_nonconst_solution; }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solution_saver.cpp b/src/specmicp/adimensional/adimensional_system_solution_saver.cpp index fac9394..fb5c765 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_saver.cpp +++ b/src/specmicp/adimensional/adimensional_system_solution_saver.cpp @@ -1,560 +1,562 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "adimensional_system_solution_saver.hpp" #include "adimensional_system_solution.hpp" #include "../../utils/log.hpp" #include "../../utils/dateandtime.hpp" #include "../../utils/io/yaml.hpp" #include #include #include #include #include #include // formatting #include "config_solution_output_format.h" namespace specmicp { //! \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_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_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_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 ) { YAML::Emitter solution_yaml; io::configure_yaml_emitter(solution_yaml); set_yaml_emitter(solution, solution_yaml); io::save_yaml(filename, solution_yaml); } void AdimensionalSystemSolutionSaver::set_yaml_emitter( const AdimensionalSystemSolution& solution, YAML::Emitter& yaml_tree ) { //# Fixme better str for the date yaml_tree << YAML::Comment("Solution file generated by SpecMiCP"); 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::string AdimensionalSystemSolutionSaver::format_solution( const AdimensionalSystemSolution& solution ) { YAML::Emitter solution_yaml; io::configure_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 ) { YAML::Emitter yaml_tree; yaml_tree << YAML::Comment("Solution file generated by SpecMiCP"); 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; for (std::size_t ind=0; ind 0) { the_solution.is_valid = false; return the_solution; } 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 "'."); } const YAML::Node& yaml_solution = root[SECTION_VALUES][0]; parse_one_solution(yaml_solution, the_solution); return the_solution; } void AdimensionalSystemSolutionSaver::parse_one_solution( const YAML::Node& yaml_solution, AdimensionalSystemSolution& the_solution ) { read_main_variables(yaml_solution, the_solution); read_aqueous_molalities(yaml_solution, the_solution); read_loggamma(yaml_solution, the_solution); read_gas_fugacities(yaml_solution, the_solution); read_sorbed_molalities(yaml_solution, the_solution); the_solution.inert_volume_fraction = io::get_yaml_mandatory(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 ) { YAML::Node root = io::parse_yaml_file(filename); int retcode = parse_check_metadata(root); if (retcode > 0 ) return; 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; ind() != m_data->metadata.name) { WARNING << "SolutionSaver : The name of the database does not match the record in the solution !"; return 1; } 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; } void AdimensionalSystemSolutionSaver::format_main_variables( const AdimensionalSystemSolution& solution, YAML::Emitter& out) { out << YAML::Key << SECTION_MAIN << YAML::Value; out << YAML::BeginMap; out << YAML::Key << VALUE_COMPONENT << YAML::Value; out << YAML::BeginMap; // water out << YAML::Key << m_data->get_label_component(0) << YAML::Value << solution.main_variables(dof_component(0)) << YAML::Comment("Volume fraction solution"); // electron out << YAML::Key << m_data->get_label_component(1) << YAML::Value << solution.main_variables(dof_component(1)) << YAML::Comment("pE"); // aqueous components for (auto component: m_data->range_aqueous_component()) { out << YAML::Key << m_data->get_label_component(component) << YAML::Value << solution.main_variables(dof_component(component)) << YAML::Comment("log10 molality (mol/kgw)"); } out << YAML::EndMap; out << YAML::Key << VALUE_FREE_SURFACE << YAML::Value << solution.main_variables(dof_surface()) << YAML::Comment("mol/kgw"); out << YAML::Key << VALUE_MINERAL << YAML::Value << YAML::Comment("Volume fraction solid phases"); out << YAML::BeginMap; for (auto mineral: m_data->range_mineral()) { out << YAML::Key << m_data->get_label_mineral(mineral) << YAML::Value << solution.main_variables(dof_mineral(mineral)); } out << YAML::EndMap; out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::format_aqueous_molalities( const AdimensionalSystemSolution& solution, YAML::Emitter& out ) { out << YAML::Key << SECTION_AQUEOUS << YAML::Value << YAML::Comment("molality (mol/kg)"); out << YAML::BeginMap; for (auto aqueous: m_data->range_aqueous()) { out << YAML::Key << m_data->get_label_aqueous(aqueous) << YAML::Value << solution.secondary_molalities(aqueous); } out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::format_loggamma( const AdimensionalSystemSolution& solution, YAML::Emitter& out ) { out << YAML::Key << SECTION_LOGGAMMA << YAML::Value << YAML::Comment("log10 activity coeficient"); out << YAML::BeginMap; out << YAML::Key << VALUE_COMPONENT << YAML::Value; out << YAML::BeginMap; for (auto component: m_data->range_aqueous_component()) { out << YAML::Key << m_data->get_label_component(component) << YAML::Value << solution.log_gamma(dof_component_gamma(component)); } out << YAML::EndMap; out << YAML::Key << VALUE_AQUEOUS << YAML::Value; out << YAML::BeginMap; for (auto aqueous: m_data->range_aqueous()) { out << YAML::Key << m_data->get_label_aqueous(aqueous) << YAML::Value << solution.log_gamma(dof_aqueous_gamma(aqueous)); } out << YAML::EndMap; out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::format_gas_fugacities( const AdimensionalSystemSolution& solution, YAML::Emitter& out ) { out << YAML::Key << SECTION_GAS << YAML::Value; out << YAML::BeginMap; for (auto gas: m_data->range_gas()) { out << YAML::Key << m_data->get_label_gas(gas) << YAML::Value << solution.gas_fugacities(gas); } out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::format_sorbed_molalities( const AdimensionalSystemSolution& solution, YAML::Emitter& out ) { out << YAML::Key << SECTION_SORBED << YAML::Value; out << YAML::BeginMap; for (auto sorbed: m_data->range_sorbed()) { out << YAML::Key << m_data->get_label_sorbed(sorbed) << YAML::Value << solution.sorbed_molalities(sorbed); } out << YAML::EndMap; } void AdimensionalSystemSolutionSaver::read_main_variables( 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 // -------------- io::check_mandatory_yaml_node(root, SECTION_MAIN, SECTION_VALUES); const YAML::Node& main = root[SECTION_MAIN]; // components io::check_mandatory_yaml_node(main, VALUE_COMPONENT, SECTION_VALUES); const YAML::Node& components = main[VALUE_COMPONENT]; for (auto& it: components) { 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 '" + 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; } } } // sorption solution.main_variables(dof_surface()) = io::get_yaml_optional(main, VALUE_FREE_SURFACE, SECTION_MAIN, -INFINITY); // minerals io::check_mandatory_yaml_node(main, VALUE_MINERAL, SECTION_VALUES); const YAML::Node& minerals = main[VALUE_MINERAL]; for (auto& it: minerals) { 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 '" + label + "' does not exist in the database !"); } solution.main_variables(dof_mineral(id)) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_loggamma( const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.log_gamma = Vector::Zero(m_data->nb_component()+m_data->nb_aqueous()); io::check_mandatory_yaml_node(root, SECTION_LOGGAMMA, SECTION_VALUES); const YAML::Node& loggamma = root[SECTION_LOGGAMMA]; // components io::check_mandatory_yaml_node(loggamma, VALUE_COMPONENT, SECTION_LOGGAMMA); const YAML::Node& components = loggamma[VALUE_COMPONENT]; for (auto& it: components) { 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 '" + label + "' does not exist in the database !"); } solution.log_gamma(dof_component_gamma(id)) = it.second.as(); } // aqueous io::check_mandatory_yaml_node(loggamma, VALUE_AQUEOUS, SECTION_LOGGAMMA); const YAML::Node& aqueous = loggamma[VALUE_AQUEOUS]; for (auto& it: aqueous) { 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 '" + label + "' does not exist in the database !"); } solution.log_gamma(dof_aqueous_gamma(id)) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_aqueous_molalities( const YAML::Node& root, AdimensionalSystemSolution &solution ) { solution.secondary_molalities = Vector::Zero(m_data->nb_aqueous()); io::check_mandatory_yaml_node(root, SECTION_AQUEOUS, SECTION_VALUES); const YAML::Node& aqueous_section = root[SECTION_AQUEOUS]; for (auto& it: aqueous_section) { 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 '" + label + "' does not exist in the database !"); } solution.secondary_molalities(id) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_gas_fugacities( const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.gas_fugacities = Vector::Zero(m_data->nb_gas()); io::check_mandatory_yaml_node(root, SECTION_GAS, SECTION_VALUES); const YAML::Node& gas_section = root[SECTION_GAS]; for (auto& it: gas_section) { 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 '" + label + "' does not exist in the database !"); } solution.gas_fugacities(id) = it.second.as(); } } void AdimensionalSystemSolutionSaver::read_sorbed_molalities( const YAML::Node& root, AdimensionalSystemSolution& solution ) { solution.sorbed_molalities = Vector::Zero(m_data->nb_sorbed()); io::check_mandatory_yaml_node(root, SECTION_SORBED, SECTION_VALUES); const YAML::Node& sorbed_section = root[SECTION_SORBED]; for (auto& it: sorbed_section) { 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 '" + label + "' does not exist in the database !"); } 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 a4f7e32..7095340 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_saver.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution_saver.hpp @@ -1,202 +1,204 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +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 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 YAML-formatted string std::string format_solution(const AdimensionalSystemSolution& solution); //! \brief Save the solution as a YAML file //! //! \param filepath path the file where to solve the solution //! \param solution the solution to save void save_solution( const std::string& filename, const AdimensionalSystemSolution& solution ); //! \brief Save a set of solutions as a YAML file //! //! \param filepath path to the file where to solve the solutions //! \param solutions vector of solutions void save_solutions( const std::string& filepath, const std::vector& solutions ); //! \brief Create a solution from a YAML input AdimensionalSystemSolution parse_solution(std::istream& input); //! \brief Create a solution from a YAML file AdimensionalSystemSolution parse_solution(const std::string& filename); //! \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_yaml_emitter( const AdimensionalSystemSolution& solution, YAML::Emitter& yaml_tree ); //! \brief Build the Json::Value tree corresponding to the solution (w/o metadata) void SPECMICP_DLL_LOCAL format_solution( const AdimensionalSystemSolution& solution, YAML::Emitter& out ); //! \brief Format the main variables void SPECMICP_DLL_LOCAL format_main_variables( const AdimensionalSystemSolution& solution, YAML::Emitter& out ); //! \brief Format the main variables void SPECMICP_DLL_LOCAL format_aqueous_molalities( const AdimensionalSystemSolution& solution, YAML::Emitter& out ); //! \brief Format the log of activity coefficients void SPECMICP_DLL_LOCAL format_loggamma( const AdimensionalSystemSolution& solution, YAML::Emitter& out ); //! \brief Format the gas fugacities void SPECMICP_DLL_LOCAL format_gas_fugacities( const AdimensionalSystemSolution& solution, YAML::Emitter& out ); //! \brief Format the sorbed molalities 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 SPECMICP_DLL_LOCAL parse_check_metadata(const YAML::Node& root); //! \brief Parse one solution from the JSON tree void SPECMICP_DLL_LOCAL parse_one_solution( const YAML::Node& yaml_solution, AdimensionalSystemSolution& the_solution ); //! \brief Parse the main variables void SPECMICP_DLL_LOCAL read_main_variables( const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the activity coefficients void SPECMICP_DLL_LOCAL read_aqueous_molalities( const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the activity coefficients void SPECMICP_DLL_LOCAL read_loggamma( const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parse the gas fugacities void SPECMICP_DLL_LOCAL read_gas_fugacities( const YAML::Node& root, AdimensionalSystemSolution& solution ); //! \brief Parsed the sorbed molalities void SPECMICP_DLL_LOCAL read_sorbed_molalities( const YAML::Node& root, AdimensionalSystemSolution& solution ); }; //! \brief Serialize a solution as a JSON-formatted string std::string SPECMICP_DLL_PUBLIC 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_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_yaml( const std::string& filename, const RawDatabasePtr& the_database ); //! \brief Read a solution from a JSON file AdimensionalSystemSolution SPECMICP_DLL_PUBLIC parse_solution_yaml( std::istream& input, const RawDatabasePtr& the_database ); } //end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONSAVER_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solver.cpp b/src/specmicp/adimensional/adimensional_system_solver.cpp index 8184754..e5617bc 100644 --- a/src/specmicp/adimensional/adimensional_system_solver.cpp +++ b/src/specmicp/adimensional/adimensional_system_solver.cpp @@ -1,445 +1,447 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "../../micpsolver/micpsolver.hpp" #include "adimensional_system_solver.hpp" #include "adimensional_system.hpp" #include "adimensional_system_solution.hpp" #include "adimensional_system_pcfm.hpp" #include "../../utils/log.hpp" #include namespace specmicp { AdimensionalSystemSolution solve_equilibrium( std::shared_ptr data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { AdimensionalSystemSolver solver(data, constraints, options); Vector variables; micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve the problem"); return solver.get_raw_solution(variables); } AdimensionalSystemSolution SPECMICP_DLL_PUBLIC solve_equilibrium( RawDatabasePtr data_ptr, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemSolverOptions& options ) { AdimensionalSystemSolver solver(data_ptr, constraints, previous_solution, options); Vector variables; micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve the problem"); return solver.get_raw_solution(variables); } // constructor // ----------- AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints ): OptionsHandler(), m_data(data), m_system(std::make_shared( data, constraints, get_options().system_options, get_options().units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ): OptionsHandler(options), m_data(data), m_system(std::make_shared( data, constraints, options.system_options, options.units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution ): OptionsHandler(), m_data(data), m_system(std::make_shared( data, constraints, previous_solution, get_options().system_options, get_options().units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemSolverOptions& options ): OptionsHandler(options), m_data(data), m_system(std::make_shared( data, constraints, previous_solution, options.system_options, options.units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolution AdimensionalSystemSolver::get_raw_solution(Vector& x) { set_true_variable_vector(x); return m_system->get_solution(x, m_var); } // Solving the system // ------------------ micpsolver::MiCPPerformance AdimensionalSystemSolver::solve(Vector& x, bool init) { m_system->set_units(get_options().units_set); if (init) { m_system->reasonable_starting_guess(x); if (get_options().use_pcfm) { run_pcfm(x); } } else if (get_options().force_pcfm) { run_pcfm(x); } set_true_variable_vector(x); micpsolver::MiCPPerformance perf = solve_system(); int cnt = 0; while (perf.return_code < micpsolver::MiCPSolverReturnCode::Success // != micpsolver::MiCPSolverReturnCode::ResidualMinimized and get_options().allow_restart and cnt < 3) { WARNING << "Failed to solve the system ! Return code :" << (int) perf.return_code << ". We shake it up and start again"; const scalar_t save_penalization_factor = get_options().solver_options.penalization_factor; const bool save_scaling = get_options().solver_options.use_scaling; get_options().solver_options.use_scaling = true; if (save_penalization_factor == 1) get_options().solver_options.penalization_factor = 0.8; set_return_vector(x); m_system->reasonable_restarting_guess(x); if (get_options().use_pcfm or get_options().force_pcfm) run_pcfm(x); set_true_variable_vector(x); micpsolver::MiCPPerformance perf2 = solve_system(); get_options().solver_options.penalization_factor = save_penalization_factor; get_options().solver_options.use_scaling = save_scaling; perf += perf2; ++cnt; } if (perf.return_code > micpsolver::MiCPSolverReturnCode::NotConvergedYet) set_return_vector(x); return perf; } micpsolver::MiCPPerformance AdimensionalSystemSolver::solve_system() { micpsolver::MiCPSolver solver(m_system); solver.set_options(get_options().solver_options); solver.solve(m_var); return solver.get_perfs(); } // Variables management // --------------------- void AdimensionalSystemSolver::set_true_variable_vector(const Vector& x) { const std::vector& non_active_component = m_system->get_non_active_component(); uindex_t new_i {0}; if (m_system->is_active_component(0)) { m_var(new_i) = x(m_system->dof_water()); ++new_i; } for (index_t i: m_data->range_aqueous_component()) { const auto it = std::find(non_active_component.cbegin(), non_active_component.cend(),i); if (it != non_active_component.cend()) continue; scalar_t value = x(m_system->dof_component(i)); if (value == -HUGE_VAL) // check for previously undefined value { value = m_system->get_options().new_component_concentration; } m_var(new_i) = value; ++new_i; } if (m_system->ideq_surf() != no_equation) { m_var(new_i) = x(m_system->dof_surface()); ++new_i; } if (m_system->ideq_electron() != no_equation) { m_var(new_i) = x(m_system->dof_electron()); ++new_i; } for (index_t m: m_data->range_mineral()) { bool to_keep = true; for (auto it=non_active_component.begin(); it!=non_active_component.end(); ++it) { if (m_data->nu_mineral(m, *it) != 0) to_keep = false; } if (to_keep) { m_var(new_i) = x(m_system->dof_mineral(m)); ++new_i; } } m_var.conservativeResize(new_i); specmicp_assert(new_i == (unsigned) m_system->total_variables()); } void AdimensionalSystemSolver::set_return_vector(Vector& x) { const std::vector& non_active_component = m_system->get_non_active_component(); uindex_t new_i = 0; if (m_system->is_active_component(0)) { x(m_system->dof_water()) = m_var(new_i); ++new_i; } else { x(m_system->dof_water()) = m_system->volume_fraction_water(x); } for (index_t i: m_data->range_aqueous_component()) { const auto it = std::find(non_active_component.cbegin(), non_active_component.cend(),i); if (it != non_active_component.cend()) { x(m_system->dof_component(i)) = -HUGE_VAL; continue; } x(m_system->dof_component(i)) = m_var(new_i) ; ++new_i; } if (m_system->ideq_surf() != no_equation) { x(m_system->dof_surface()) = m_var(new_i); ++new_i; } else x(m_system->dof_surface()) = -HUGE_VAL; if (m_system->ideq_electron() != no_equation) { x(m_system->dof_electron()) = m_var(new_i); ++new_i; } else x(m_system->dof_electron()) = -HUGE_VAL; for (index_t m: m_data->range_mineral()) { bool to_keep = true; for (const index_t& k: non_active_component) { if (m_data->nu_mineral(m, k) != 0.0) to_keep = false; } if (to_keep) { x(m_system->dof_mineral(m)) =m_var(new_i); ++new_i; } else { x(m_system->dof_mineral(m)) = 0.0; } } } // PCFM // ---- void AdimensionalSystemSolver::run_pcfm(Vector &x) { DEBUG << "Start PCFM initialization."; // we set up the true variable set_true_variable_vector(x); // The residual is computed to have some point of comparison Vector residuals(m_system->total_variables()); residuals.setZero(); m_system->get_residuals(m_var, residuals); const scalar_t res_0 = residuals.norm(); // the pcfm iterations are executed AdimensionalSystemPCFM pcfm_solver(m_system); PCFMReturnCode retcode = pcfm_solver.solve(m_var); // Check the answer if (retcode < PCFMReturnCode::Success) { // small prograss is still good enough m_system->get_residuals(m_var, residuals); const scalar_t final_residual = residuals.norm(); DEBUG << "Final pcfm residuals : " << final_residual << " set_secondary_variables(m_var); } } // Initialisation of variables // --------------------------- void AdimensionalSystemSolver::initialise_variables( Vector& x, scalar_t volume_fraction_water, std::map log_molalities, std::map volume_fraction_minerals, scalar_t log_free_sorption_site_concentration ) { m_system->reasonable_starting_guess(x); if (volume_fraction_water < 0 or volume_fraction_water > 1) { WARNING << "Initial guess for the volume fraction of water is not between 0 and 1"; } x(m_system->dof_water()) = volume_fraction_water; for (auto pair: log_molalities) { index_t idc = m_data->get_id_component(pair.first); if (idc == no_species or idc == m_data->electron_index() or idc == m_data->water_index()) { throw std::invalid_argument("This is not an aqueous component : "+pair.first); } if (pair.second > 0) { WARNING << "Initial molality for : " << pair.first << "is bigger than 1 molal."; } x(m_system->dof_component(idc)) = pair.second; } for (auto pair: volume_fraction_minerals) { index_t idm = m_data->get_id_mineral(pair.first); if (idm == no_species ) { throw std::invalid_argument("This is not a mineral at equilibrium : "+pair.first); } if (pair.second < 0 or pair.second > 1) { WARNING << "Initial volume fraction for : " << pair.first << "is not between 0 and 1."; } x(m_system->dof_mineral(idm)) = pair.second; } if (log_free_sorption_site_concentration != 0.0) x(m_system->dof_surface()) = log_free_sorption_site_concentration; } void AdimensionalSystemSolver::initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities ) { m_system->reasonable_starting_guess(x); if (volume_fraction_water < 0 or volume_fraction_water > 1) { WARNING << "Initial guess for the volume fraction of water is not between 0 and 1"; } x(m_system->dof_water()) = volume_fraction_water; if (log_molalities > 0) { WARNING << "Initial molality for : " << log_molalities << "is bigger than 1 molal."; } x.segment(1, m_data->nb_component()-1).setConstant(log_molalities); } void AdimensionalSystemSolver::initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities, scalar_t log_free_sorption_site_concentration ) { initialise_variables(x, volume_fraction_water, log_molalities); x(m_system->dof_surface()) = log_free_sorption_site_concentration; } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_solver.hpp b/src/specmicp/adimensional/adimensional_system_solver.hpp index f55dd89..cb3cac1 100644 --- a/src/specmicp/adimensional/adimensional_system_solver.hpp +++ b/src/specmicp/adimensional/adimensional_system_solver.hpp @@ -1,202 +1,204 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP #include "../../database.hpp" #include "adimensional_system_solver_structs.hpp" #include "../../utils/options_handler.hpp" #include //! \file adimensional_system_solver.hpp //! \brief Solve a reduced system namespace specmicp { // forward declaration class AdimensionalSystem; struct AdimensionalSystemSolution; //! \brief Solve an adimensional system //! //! Take care of non-existing component in the system //! and restart the computation if necessary //! //! \ingroup specmicp_api class SPECMICP_DLL_PUBLIC AdimensionalSystemSolver: public OptionsHandler { public: using SystemPtr = std::shared_ptr; //! Default constructor //! //! Another constructor is necessary AdimensionalSystemSolver() {} //! \brief Initialise a solver from scratch //! //! \param data A raw database //! \param constraints The system to solver AdimensionalSystemSolver(RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints ); //! \brief Initialise a solver from scratch //! //! \param data A raw database //! \param constraints The system to solver //! \param options (optional) customize the behavior of the solver AdimensionalSystemSolver(RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ); //! \brief Initialise a solver from a previous solution //! //! \param data A raw database //! \param constraints The system to solver //! \param previous_solution A solution of a similar system that will be used to initialize the system AdimensionalSystemSolver(RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution ); //! \brief Initialise a solver from a previous solution //! //! \param data A raw database //! \param constraints The system to solver //! \param previous_solution A solution of a similar system that will be used to initialize the system //! \param options customize the behavior of the solver AdimensionalSystemSolver(RawDatabasePtr& data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemSolverOptions& options ); //! \brief solve the problem using initial guess x //! //! \param[in,out] x in -> initial guess, out -> solution //! \param init if true, the algorithm guess a starting point micpsolver::MiCPPerformance solve(Vector& x, bool init=false); //! \brief Return the system used for the computation SystemPtr get_system() {return m_system;} //! \brief Return the solution in a manageable form //! //! \param x The solution (complete set of the main variables) AdimensionalSystemSolution get_raw_solution(Vector& x); //! \brief Initialize the problem using the Positive continuous fraction method //! //! \sa specmicp::AdimensionalSystemPCFM void run_pcfm(Vector& x); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for chosen aqueous component //! \param volume_fraction_minerals volume fraction of the minerals //! \param log_free_sorption_site_concentration concentration of free sorption site void initialise_variables(Vector& x, scalar_t volume_fraction_water, std::map log_molalities, std::map volume_fraction_minerals = {}, scalar_t log_free_sorption_site_concentration = 0 ); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for all aqueous components void initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities ); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for all aqueous components //! \param log_free_sorption_site_concentration concentration of free sorption site void initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities, scalar_t log_free_sorption_site_concentration ); private: //! \brief set up the true variable vector //! //! \param x The solution (complete set of the main variables) void SPECMICP_DLL_LOCAL set_true_variable_vector(const Vector& x); //! \brief set up the true solution vector //! //! add zero components //! \param x The solution (complete set of the main variables) void SPECMICP_DLL_LOCAL set_return_vector(Vector& x); //! \brief solve the problem micpsolver::MiCPPerformance SPECMICP_DLL_LOCAL solve_system(); RawDatabasePtr m_data; //! The raw database SystemPtr m_system; //! The system to solve Vector m_var; //! Copy of the solution vector (necessary in case of failing) }; //! \brief Solve a reduced system, function provided for convenience //! //! \param data_ptr the database //! \param constraints Constraints applied to the system //! \param options Options for the solver AdimensionalSystemSolution SPECMICP_DLL_PUBLIC solve_equilibrium( RawDatabasePtr data_ptr, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ); //! \brief Solve a reduced system, function provided for convenience //! //! \param data_ptr the database //! \param constraints constraints applied to the system //! \param previous_solution a previous solution //! \param options options for the solver AdimensionalSystemSolution SPECMICP_DLL_PUBLIC solve_equilibrium( RawDatabasePtr data_ptr, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemSolverOptions& options ); } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solver_structs.cpp b/src/specmicp/adimensional/adimensional_system_solver_structs.cpp index edbac66..0da0678 100644 --- a/src/specmicp/adimensional/adimensional_system_solver_structs.cpp +++ b/src/specmicp/adimensional/adimensional_system_solver_structs.cpp @@ -1,62 +1,64 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "adimensional_system_solver_structs.hpp" #include "config_default_options_solver.h" namespace specmicp { AdimensionalSystemOptions::AdimensionalSystemOptions(): non_ideality(SPECMICP_DEFAULT_ENABLE_NONIDEAL), non_ideality_max_iter(SPECMICP_DEFAULT_NONIDEAL_MAX_ITER), scaling_electron(SPECMICP_DEFAULT_SCALING_ELECTRON), non_ideality_tolerance(SPECMICP_DEFAULT_NONIDEAL_TOL), under_relaxation_factor(SPECMICP_DEFAULT_UNDERRELAX_FACTOR), restart_concentration(SPECMICP_DEFAULT_RESTART_CONC), new_component_concentration(SPECMICP_DEFAULT_NEW_COMPONENT_CONC), start_non_ideality_computation(SPECMICP_DEFAULT_TRHSOLD_START_NONIDEAL), cutoff_total_concentration(SPECMICP_DEFAULT_CUTOFF_TOT_CONC) {} AdimensionalSystemSolverOptions::AdimensionalSystemSolverOptions(): allow_restart(SPECMICP_DEFAULT_ALLOW_RESTART), use_pcfm(SPECMICP_DEFAULT_USE_PCFM), force_pcfm(SPECMICP_DEFAULT_FORCE_PCFM) { units_set.length = SPECMICP_DEFAULT_LENGTH_UNIT; // disable the descent condition check solver_options.maxstep = SPECMICP_DEFAULT_MAX_STEP; solver_options.factor_descent_condition = SPECMICP_DEFAULT_FACTOR_DESC_COND; } } //end namespace spemicp diff --git a/src/specmicp/adimensional/adimensional_system_solver_structs.hpp b/src/specmicp/adimensional/adimensional_system_solver_structs.hpp index 0b9e6c9..8d81980 100644 --- a/src/specmicp/adimensional/adimensional_system_solver_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_solver_structs.hpp @@ -1,71 +1,73 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP #include "../../types.hpp" #include "../../micpsolver/micpsolver_structs.hpp" #include "adimensional_system_structs.hpp" #include "../../physics/units.hpp" //! \file adimensional_system_solver_structs.hpp Options and conditions for AdimensionalSystemSolver namespace specmicp { //! \struct AdimensionalSystemSolverOptions //! \brief Options for the Equilibrium solver //! //! Most of the options are contained in the MiCP solver options or the AdimensionalSystem options struct SPECMICP_DLL_PUBLIC AdimensionalSystemSolverOptions { //! Allow the restarting if the problem failed the first part bool allow_restart; //! If true use the pcfm method to initialize the problem bool use_pcfm; //! Use pcfm before every trial bool force_pcfm; //! Set of units units::UnitsSet units_set; //! Options of the MiCP solver micpsolver::MiCPSolverOptions solver_options {}; //! Options of the system AdimensionalSystemOptions system_options {}; AdimensionalSystemSolverOptions(); }; } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP diff --git a/src/specmicp/adimensional/adimensional_system_structs.hpp b/src/specmicp/adimensional/adimensional_system_structs.hpp index 02125fe..513eacd 100644 --- a/src/specmicp/adimensional/adimensional_system_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_structs.hpp @@ -1,338 +1,340 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP #include "../../types.hpp" //! \file adimensional_system_structs.hpp //! \brief Options and constraints for the AdimensionalSystem namespace specmicp { //! \struct AdimensionalSystemOptions //! \brief Options for the Adimensional Systems //! //! It is mainly about the secondary variables fixed-point iterations struct SPECMICP_DLL_PUBLIC AdimensionalSystemOptions { //! Solve for non ideality bool non_ideality; //! Max iterations for the non ideality model index_t non_ideality_max_iter; //! Scaling the electron equation scalar_t scaling_electron; //! Tolerance for non ideality scalar_t non_ideality_tolerance; //! Under relaxation factor for the conservation of water scalar_t under_relaxation_factor; //! Log of the molality used to restart the computation scalar_t restart_concentration; //! Log_10 of the molality for a new component scalar_t new_component_concentration; //! Factor to start the non-ideality computation scalar_t start_non_ideality_computation; //! Cutoff for including components in the computation scalar_t cutoff_total_concentration; AdimensionalSystemOptions(); // in adimensional_system_solver_structs.cpp }; //! \enum AqueousComponentEquationType //! \brief Type of an aqueous component equation enum class AqueousComponentEquationType { NoEquation = no_equation, //!< Not an equation, component is not present in the system MassConservation, //!< Mass balance ChargeBalance, //!< M.B. replaced by charge balance FixedFugacity, //!< M.B. replaced by a fixed fugacity equation FixedActivity, //!< M.B. replaced by a fixed activity equation FixedMolality //!< The molality of the species is fixed }; //! \enum WaterEquationType //! \brief The type of the equation solved for the water enum class WaterEquationType { NoEquation = no_equation, //!< Amount of water is not solved MassConservation, //!< Water is conserved SaturatedSystem //!< System is saturated }; //! \struct FixedFugacityConstraint //! \brief Struct to contain information needed to solve a fix fugacity problem struct FixedFugacityConstraint { index_t id_gas; //!< Index of the fixed-fugacity gas index_t id_component; //!< Index of the corresponding component scalar_t log_value; //!< Log_10 of the fugacity FixedFugacityConstraint(index_t gas, index_t component, scalar_t logvalue): id_gas(gas), id_component(component), log_value(logvalue) {} }; //! \struct FixedActivityConstraint //! \brief Struct to contain information needed to solve a fix activity problem. struct FixedActivityConstraint { index_t id_component; //!< Index of the fixed-activity component scalar_t log_value; //!< Log_10 of the activity FixedActivityConstraint(index_t component, scalar_t logvalue): id_component(component), log_value(logvalue) {} }; //! \struct FixedMolalityConstraint //! \brief Contain information about a fixed molality constraint struct FixedMolalityConstraint { index_t id_component; //!< Index of the component scalar_t log_value; //!< Log_10 of the molality FixedMolalityConstraint(index_t component, scalar_t logvalue): id_component(component), log_value(logvalue) {} }; //! \enum SurfaceEquationType //! \brief The model for surface sorption enum class SurfaceEquationType { NoEquation = no_equation, //!< Do not include surface sorption Equilibrium //!< Equilibrium model }; //! \struct SurfaceConstraint //! This struct contains the information to set-up the surface sorption model struct SurfaceConstraint { SurfaceEquationType model_type; //!< The model to use scalar_t concentration; //!< The total concentration of sorption sites //! \brief By default, we don't include surface sorption in the computation SurfaceConstraint() noexcept: model_type(SurfaceEquationType::NoEquation), concentration(0.0) {} //! \brief When a concentration is supplied, the surface sorption model is equilibrium SurfaceConstraint(scalar_t surface_concentration) noexcept: model_type(SurfaceEquationType::Equilibrium), concentration(surface_concentration) {} }; //! \enum ElectronEquationType the type of the equation for the electron enum class ElectronEquationType { NoEquation = no_equation, //!< Do not compute the concentration equation of the electron Equilibrium, //!< Set the concentration of electron to be 0 FixedpE //!< Activity of the electron is fixed }; //! \struct ElectronConstraint //! \brief the constraint for the electron struct ElectronConstraint { ElectronEquationType equation_type{ElectronEquationType::NoEquation}; //!< The equation type scalar_t fixed_value; //!< The fixed value of pE if needed index_t species {no_species}; //!< In case of fixed pE, this is the reaction to use //! \brief By default we assume equilibrium ElectronConstraint(): equation_type(ElectronEquationType::Equilibrium), fixed_value(0.0) {} //! \brief When a value is provided, we assume that the pE is fixed ElectronConstraint(scalar_t pe_value, scalar_t aqueous_species): equation_type(ElectronEquationType::FixedpE), fixed_value(pe_value), species(aqueous_species) {} }; //! \brief Return the partial pressure as function of the liquid saturation //! //! This function must return the pressure in Pa using water_partial_pressure_f = std::function; //! \brief Constraints for the partial pressure model struct WaterPartialPressureConstraint { bool use_partial_pressure_model; //!< True if we use partial pressure model water_partial_pressure_f partial_pressure_model; //!< The model given by the user //! \brief By default the partial pressure constraint is disabled WaterPartialPressureConstraint(): use_partial_pressure_model(false), partial_pressure_model(nullptr) {} //! \brief Enble the water partial pressure model WaterPartialPressureConstraint(water_partial_pressure_f& model): WaterPartialPressureConstraint() { if (model != nullptr) { use_partial_pressure_model = true; partial_pressure_model = model; } } }; //! \struct AdimensionalSystemConstraints //! \brief Struct to contains the "Boundary conditions" for the AdimensionalSystem //! //! \ingroup specmicp_api struct AdimensionalSystemConstraints { Vector total_concentrations; //!< Total concentrations WaterEquationType water_equation{WaterEquationType::MassConservation}; //!< Water equation index_t charge_keeper{no_species}; //!< The equation for this component is replace by the charge balance std::vector fixed_fugacity_cs {}; //!< Contains information about fixed fugacity constraints std::vector fixed_activity_cs {}; //!< Contains information about fixed activity constraints std::vector fixed_molality_cs {}; //!< Contains information about fixed molality constraints scalar_t inert_volume_fraction{ 0.0 }; //!< Volume fraction of inert solid (inert in the equilibrium computation) SurfaceConstraint surface_model{}; //!< Surface sorption model ElectronConstraint electron_constraint{}; //!< constraint for the electron WaterPartialPressureConstraint water_partial_pressure {}; //!< The partial pressure of water (if any) AdimensionalSystemConstraints(): total_concentrations() {} AdimensionalSystemConstraints(const Vector& total_concs): total_concentrations(total_concs) {} //! \brief Set the total concentrations void set_total_concentrations(const Vector& total_concs) {total_concentrations = total_concs;} //! \brief Enable the conservation of water void enable_conservation_water() noexcept {water_equation = WaterEquationType::MassConservation;} //! \brief Disable the conservation of water void disable_conservation_water() noexcept {water_equation = WaterEquationType::NoEquation;} //! \brief The system is saturated void set_saturated_system() noexcept {water_equation = WaterEquationType::SaturatedSystem;} //! \brief Disable the surface sorption model void disable_surface_model() noexcept {surface_model.model_type = SurfaceEquationType::NoEquation;} //! \brief Enable the surface sorption model //! \param surface_sorption_model_concentration concentration of the surface sorption sites void enable_surface_model(scalar_t surface_sorption_model_concentration) noexcept { surface_model.model_type = SurfaceEquationType::Equilibrium; surface_model.concentration = surface_sorption_model_concentration; } //! \brief Set the charge keeper to 'component' //! //! \param component Index of the component (in the database) void set_charge_keeper(index_t component) noexcept { charge_keeper = component; } //! \brief Add a fixed fugacity gas condition //! //! \param constraint struct containing the information about a fixed-fugacity constraint void add_fixed_fugacity_gas(const FixedFugacityConstraint& constraint) { fixed_fugacity_cs.push_back(constraint); } //! \brief Add a fixed fugacity gas condition //! //! \param gas Index of the gas (in the database) //! \param component Index of the corresponding component (in the database) //! \param logvalue Log_10 of the fugacity void add_fixed_fugacity_gas(index_t gas, index_t component, scalar_t logvalue) { fixed_fugacity_cs.emplace_back(FixedFugacityConstraint(gas, component, logvalue)); } //! \brief Add a fixed activity component condition //! //! \param constraint struct containing the information about a fixed-activity constraint void add_fixed_activity_component(const FixedActivityConstraint& constraint) { fixed_activity_cs.push_back(constraint); } //! \brief Add a fixed activity condition for a component //! //! \param component Index of the corresponding component (in the database) //! \param log_value Log_10 of the activity void add_fixed_activity_component(index_t component, scalar_t log_value) { fixed_activity_cs.emplace_back(FixedActivityConstraint(component, log_value)); } //! \brief Add a fixed molality condition for a component //! //! \param component Index of the corresponding component (in the database) //! \param log_value Log_10 of the molality void add_fixed_molality_component(index_t component, scalar_t log_value) { fixed_molality_cs.emplace_back(FixedMolalityConstraint(component, log_value)); } //! \brief Set the inert volume fraction //! //! The volume fraction of the inert phase is used to offset the saturation. //! This inert phase may correspond to aggregates or solid phases governed by kinetics. //! //! \param value volume fraction of the inert phase void set_inert_volume_fraction(scalar_t value) noexcept { inert_volume_fraction = value; } //! \brief Set a partial pressure model for water //! //! The partial pressure model for water is a function taking the saturation //! and returning the partial pressure of water void set_water_partial_pressure_model(water_partial_pressure_f model) { water_partial_pressure.use_partial_pressure_model = true; water_partial_pressure.partial_pressure_model = model; } // //! \brief Set the system at a fixed pE // void set_fixed_pe(scalar_t pe_value, index_t aqueous_species) noexcept { // electron_constraint = ElectronConstraint(pe_value, aqueous_species); // } }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP diff --git a/src/specmicp/adimensional/config_default_options_solver.h b/src/specmicp/adimensional/config_default_options_solver.h index c479ca5..5c8f1a4 100644 --- a/src/specmicp/adimensional/config_default_options_solver.h +++ b/src/specmicp/adimensional/config_default_options_solver.h @@ -1,87 +1,89 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file config_default_options_solver.h //! \internal //! \brief Defaut options for the adimensional solver #ifndef SPECMICP_ADIM_CONFIG_DEFAULTOPTIONSSOLVER_H #define SPECMICP_ADIM_CONFIG_DEFAULTOPTIONSSOLVER_H #include "../../micpsolver/micpsolver_structs.hpp" // System options #define SPECMICP_DEFAULT_ENABLE_NONIDEAL true #define SPECMICP_DEFAULT_NONIDEAL_MAX_ITER 10 #define SPECMICP_DEFAULT_SCALING_ELECTRON 0.0 #define SPECMICP_DEFAULT_NONIDEAL_TOL 1e-8 #define SPECMICP_DEFAULT_UNDERRELAX_FACTOR 0.9 #define SPECMICP_DEFAULT_RESTART_CONC -6.0 #define SPECMICP_DEFAULT_NEW_COMPONENT_CONC -4.0 #define SPECMICP_DEFAULT_TRHSOLD_START_NONIDEAL 0.1 #define SPECMICP_DEFAULT_CUTOFF_TOT_CONC 1e-12 // Micpslover options #define SPECMICP_DEFAULT_USE_CRASHING MICPSOLVER_DEFAULT_USE_CRASHING #define SPECMICP_DEFAULT_USE_SCALING MICPSOLVER_DEFAULT_USE_SCALING #define SPECMICP_DEFAULT_USE_NONMONOTONE_LSEARCH MICPSOLVER_DEFAULT_USE_NONMONOTONE_LSEARCH #define SPECMICP_DEFAULT_MAX_ITER MICPSOLVER_DEFAULT_MAX_ITER #define SPECMICP_DEFAULT_MAX_ITER_MAXSTEP MICPSOLVER_DEFAULT_MAX_ITER_MAXSTEP #define SPECMICP_DEFAULT_MAX_FACT_STEP MICPSOLVER_DEFAULT_MAX_FACT_STEP #define SPECMICP_DEFAULT_RES_TOL MICPSOLVER_DEFAULT_RES_TOL #define SPECMICP_DEFAULT_STEP_TOL MICPSOLVER_DEFAULT_STEP_TOL #define SPECMICP_DEFAULT_COND_THRESHOLD MICPSOLVER_DEFAULT_COND_THRESHOLD #define SPECMICP_DEFAULT_PENALIZATION_FACTOR MICPSOLVER_DEFAULT_PENALIZATION_FACTOR #define SPECMICP_DEFAULT_MAX_STEP 10.0 #define SPECMICP_DEFAULT_FACTOR_DESC_COND -1.0 #define SPECMICP_DEFAULT_POWER_DESC_COND MICPSOLVER_DEFAULT_POWER_DESC_COND #define SPECMICP_DEFAULT_COEFF_ACCEPT_NEWTON MICPSOLVER_DEFAULT_COEFF_ACCEPT_NEWTON #define SPECMICP_DEFAULT_FACTOR_GRADIENT MICPSOLVER_DEFAULT_FACTOR_GRADIENT #define SPECMICP_DEFAULT_PROJ_VAR MICPSOLVER_DEFAULT_PROJ_VAR #define SPECMICP_DEFAULT_TRHSOLD_STATIONARY MICPSOLVER_DEFAULT_TRHSOLD_STATIONARY #define SPECMICP_DEFAULT_TRHSOLD_CYCLING_LSEARCH MICPSOLVER_DEFAULT_TRHSOLD_CYCLING_LSEARCH // Adim solver options #define SPECMICP_DEFAULT_ALLOW_RESTART true #define SPECMICP_DEFAULT_USE_PCFM false #define SPECMICP_DEFAULT_FORCE_PCFM false #define SPECMICP_DEFAULT_LENGTH_UNIT specmicp::units::LengthUnit::meter #endif // SPECMICP_ADIM_CONFIG_DEFAULTOPTIONSSOLVER_H diff --git a/src/specmicp/adimensional/config_solution_output_format.h b/src/specmicp/adimensional/config_solution_output_format.h index 72940a3..8cff8b6 100644 --- a/src/specmicp/adimensional/config_solution_output_format.h +++ b/src/specmicp/adimensional/config_solution_output_format.h @@ -1,64 +1,66 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ //! \file config_solution_output_format.h //! \internal //! \brief Names of the sections, subsections, keys sed in the yaml output of a solution #ifndef SPEMCICP_ADIM_SOLUTION_OUTPUTFORMAT_HPP #define SPEMCICP_ADIM_SOLUTION_OUTPUTFORMAT_HPP #define SECTION_VALUES "solutions" // metatada #define VALUE_META_NAME "name" #define VALUE_META_DATE "date" #define VALUE_META_DATABASE "database" #define VALUE_META_DATABASE_VERSION "database_version" // main sections #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" // individual values #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" #endif // SPEMCICP_ADIM_SOLUTION_OUTPUTFORMAT_HPP diff --git a/src/specmicp/adimensional/equilibrium_curve.cpp b/src/specmicp/adimensional/equilibrium_curve.cpp index c77ee6c..8dbd157 100644 --- a/src/specmicp/adimensional/equilibrium_curve.cpp +++ b/src/specmicp/adimensional/equilibrium_curve.cpp @@ -1,96 +1,98 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "equilibrium_curve.hpp" #include "adimensional_system_solver.hpp" #include "../../utils/log.hpp" #define INITIALIZE true #define DONT_INITIALIZE false namespace specmicp { void EquilibriumCurve::solve_first_problem() { AdimensionalSystemSolver solver(m_data, m_constraints, m_solver_options); m_current_perf = solver.solve(m_solution_vector, INITIALIZE); if (m_current_perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { error_handling("Failed to solve first problem, return code : " + std::to_string((int) m_current_perf.return_code) + "."); } m_current_solution = solver.get_raw_solution(m_solution_vector); } void EquilibriumCurve::solve_problem() { AdimensionalSystemSolver solver(m_data, m_constraints, m_current_solution, m_solver_options); m_current_perf = solver.solve(m_solution_vector, DONT_INITIALIZE); if (m_current_perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { error_handling("Failed to solve problem, return code : " + std::to_string((int) m_current_perf.return_code) + "."); } m_current_solution = solver.get_raw_solution(m_solution_vector); } void EquilibriumCurve::error_handling(std::string msg) const { ERROR << msg; throw std::runtime_error(msg); } void EquilibriumCurve::set_problem() { update_problem(); } void EquilibriumCurve::post_processing() { output(); } void EquilibriumCurve::run_step() { set_problem(); solve_problem(); post_processing(); } } // end namespace specmicp #undef INITIALIZE #undef DONT_INITIALIZE diff --git a/src/specmicp/adimensional/equilibrium_curve.hpp b/src/specmicp/adimensional/equilibrium_curve.hpp index b82b5a6..0ab2b42 100644 --- a/src/specmicp/adimensional/equilibrium_curve.hpp +++ b/src/specmicp/adimensional/equilibrium_curve.hpp @@ -1,142 +1,144 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP #define SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP #include "../../types.hpp" #include "../../database.hpp" #include "adimensional_system_solver_structs.hpp" #include "adimensional_system_solution.hpp" //! \file equilibrium_curve.hpp ABC to compute a reaction path namespace specmicp { //! \brief Abstract Base Class to compute an equilibrium curve //! //! class SPECMICP_DLL_PUBLIC EquilibriumCurve { public: EquilibriumCurve() {} EquilibriumCurve(RawDatabasePtr database, AdimensionalSystemConstraints constraints ): m_data(database), m_constraints(constraints) {} //! \brief Run one step of the equilibrium curve void run_step(); //! \brief Return the raw database RawDatabasePtr database() const {return m_data;} //! \brief Return the current solution const AdimensionalSystemSolution& current_solution() const { return m_current_solution; } //! \brief Return the current solution vector Vector& solution_vector() { return m_solution_vector; } //! \brief Return the current MiCPsolver performance const micpsolver::MiCPPerformance& solver_performance() const { return m_current_perf; } //! \brief Return a const reference to the solver options const AdimensionalSystemSolverOptions& solver_options() const { return m_solver_options; } //! \brief Return a const reference to the BC of AdimensionalSystem const AdimensionalSystemConstraints& constraints() const { return m_constraints; } //! \brief update the problem; virtual void update_problem() = 0; //! \brief Output - do nothing by default virtual void output() {} //! \brief How to handle an error virtual void error_handling(std::string msg) const; //! \brief Solve the first problem void solve_first_problem(); protected: //! \brief Set the database void set_database(RawDatabasePtr the_database) { m_data =the_database; } //! \brief Read-write reference to the conditions AdimensionalSystemConstraints& constraints() { return m_constraints; } //! \brief Read-write reference to the options of AdimensionalSystemSolver AdimensionalSystemSolverOptions& solver_options() { return m_solver_options; } //! \brief Input the first solution void initialize_solution(const AdimensionalSystemSolution& init) { m_current_solution = init; } private: //! \brief Set the problem, according user input void set_problem(); //! \brief Solve the problem //! //! May fail, call error_handling void solve_problem(); //! \brief Post processing of the data void post_processing(); RawDatabasePtr m_data; AdimensionalSystemConstraints m_constraints; AdimensionalSystemSolverOptions m_solver_options; AdimensionalSystemSolution m_current_solution; micpsolver::MiCPPerformance m_current_perf; Vector m_solution_vector; }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_model.hpp b/src/specmicp/adimensional_kinetics/kinetic_model.hpp index 0462be8..175bf8d 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_model.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_model.hpp @@ -1,85 +1,87 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP #include "../../types.hpp" #include "kinetic_variables.hpp" namespace specmicp { namespace kinetics { // \brief Base class for a kinetic model class AdimKineticModel { public: AdimKineticModel() {} AdimKineticModel(const std::vector& list_species): m_list_species(list_species) {} virtual ~AdimKineticModel() {} //! \brief Return the number of kinetic minerals included in the problem index_t get_neq() {return m_list_species.size();} //! \brief Compute the kinetic rates and store them in dydt virtual void compute_rate( scalar_t t, const Vector& y, AdimKineticVariables& variables, Vector& dydt ) = 0; void add_equation(index_t species) {m_list_species.push_back(species);} //! \brief Index of species corresponding to equation 'id_equation' index_t index_species(index_t id_equation) {return m_list_species[id_equation];} //! \brief Iterator over the species vector std::vector::iterator species_begin() {return m_list_species.begin();} std::vector::iterator species_end() {return m_list_species.end();} private: std::vector m_list_species; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system.cpp b/src/specmicp/adimensional_kinetics/kinetic_system.cpp index 593e8c7..4f6af27 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system.cpp @@ -1,110 +1,112 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "kinetic_system.hpp" #include "kinetic_model.hpp" #include "../adimensional/adimensional_system_solver.hpp" #include "../../utils/log.hpp" namespace specmicp { namespace kinetics { void AdimKineticSystem::update_total_concentrations(const Vector& y) { //Vector y_temp = y.cwiseMax(Vector::Zero(y.rows())); Vector update_minerals = (y - m_variables.concentration_minerals()); m_variables.total_concentrations() = m_variables.total_concentrations_initial(); for (auto it=m_model->species_begin(); it!=m_model->species_end(); ++it) { for (index_t component: m_data->range_component()) { if (m_data->nu_mineral_kinetic(*it, component) == 0.0) continue; m_variables.total_concentration(component) -= m_data->nu_mineral_kinetic(*it, component)*update_minerals(it-m_model->species_begin()); } } } void AdimKineticSystem::update_to_new_initial_condition(const Vector& y, scalar_t dt) { update_total_concentrations(y); m_variables.rate_components() += ( m_variables.total_concentrations() - m_variables.total_concentrations_initial() )/dt; m_variables.concentration_minerals() = y; m_variables.total_concentrations_initial() = m_variables.total_concentrations(); } void AdimKineticSystem::compute_rates(scalar_t t, const Vector& y, Vector& dydt) { m_model->compute_rate(t, y, m_variables, dydt); } void AdimKineticSystem::compute_equilibrium( AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions& options) { AdimensionalSystemSolver solver; Vector variables; specmicp::micpsolver::MiCPPerformance perf; constraints.total_concentrations = m_variables.total_concentrations(); if (m_variables.equilibrium_solution().is_valid) { solver = AdimensionalSystemSolver(m_data, constraints, m_variables.equilibrium_solution(), options); variables = m_variables.equilibrium_solution().main_variables; perf = solver.solve(variables); } else { solver = AdimensionalSystemSolver(m_data, constraints, options); perf = solver.solve(variables, true); } //std::cout << variables << std::endl; if ((int) perf.return_code < 0) { ERROR << "Failed to solve the system ! Error code " << (int) perf.return_code; } m_variables.update_equilibrium_solution(solver.get_raw_solution(variables)); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system.hpp b/src/specmicp/adimensional_kinetics/kinetic_system.hpp index 01cdfd0..a64acb2 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system.hpp @@ -1,124 +1,126 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP #include #include "../../types.hpp" #include "../../database.hpp" #include "kinetic_variables.hpp" #include "../adimensional/adimensional_system_solver_structs.hpp" namespace specmicp { //! \namespace specmicp::kinetics //! \brief Solver for kinetics systems namespace kinetics { class AdimKineticModel; //! \brief Kinetics System, //! //! Wrapper for a kinetic model class AdimKineticSystem { public: AdimKineticSystem( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentrations, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_data(database), m_model(model), m_constraints(constraints), m_variables(total_concentrations, mineral_concentrations) {} AdimKineticSystem( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentrations, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_data(database), m_model(model), m_constraints(constraints), m_variables(total_concentrations, mineral_concentrations, equilibrium_solution) {} //! \brief Compute the kinetics rates to be solved //! //! Use the kinetic model provided by the user void compute_rates(scalar_t x, const Vector& y, Vector& dydt); //! \brief Compute the equilibrium state of the solution void compute_equilibrium( AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions& options ); //! \brief Update the total concentrations //! //! \param y vector of variables (mols of minerals) void update_total_concentrations(const Vector& y); void update_to_new_initial_condition(const Vector& y, scalar_t dt); //! \brief Right Hand side function for the integrator void rhs(scalar_t x, const Vector& y, Vector& dydt, AdimensionalSystemSolverOptions& options) { update_total_concentrations(y); compute_equilibrium(m_constraints, options); compute_rates(x, y, dydt); } AdimKineticVariables& variables() {return m_variables;} AdimensionalSystemConstraints& constraints() {return m_constraints;} private: RawDatabasePtr m_data; std::shared_ptr m_model; AdimensionalSystemConstraints m_constraints; AdimKineticVariables m_variables; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp index d72602c..248f81b 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp @@ -1,66 +1,68 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "kinetic_system_euler_solver.hpp" #include "kinetic_model.hpp" #include "../../odeint/runge_kutta_step.hpp" #include namespace specmicp { namespace kinetics { void AdimKineticSystemEulerSolver::solve(scalar_t dt, scalar_t total) { double t = 0.0; Vector y = m_system.variables().concentration_minerals(); Vector dydx(y.rows()); dydx.setZero(); while (t < total) { m_system.rhs(t, y, dydx, get_options().speciation_options); y += dt*dydx; m_system.update_to_new_initial_condition(y, dt); t += dt; if (t+dt > total) dt =(total - t); } m_system.update_total_concentrations(y); m_system.compute_equilibrium(m_system.constraints(), get_options().speciation_options); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp index 55aabfa..14fe5b0 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp @@ -1,86 +1,88 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP #include "kinetic_system.hpp" #include "kinetic_system_solver_structs.hpp" #include "../../utils/options_handler.hpp" namespace specmicp { namespace kinetics { class AdimKineticModel; class SPECMICP_DLL_PUBLIC AdimKineticSystemEulerSolver: public OptionsHandler { public: AdimKineticSystemEulerSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentration, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_concentration, constraints, database) {} AdimKineticSystemEulerSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentration, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_concentration, constraints, equilibrium_solution, database) {} void solve(scalar_t dt, scalar_t total); scalar_t current_dt() {return m_current_dt;} AdimKineticVariables& variables() {return m_system.variables();} private: scalar_t m_current_dt; AdimKineticSystem m_system; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp index 5aa0e75..583f94d 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp @@ -1,82 +1,84 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "kinetic_system_solver.hpp" #include "kinetic_model.hpp" #include "../../odeint/runge_kutta_step.hpp" #include namespace specmicp { namespace kinetics { void AdimKineticSystemSolver::solve(scalar_t dt, scalar_t total) { double t = 0.0; Vector y = m_system.variables().concentration_minerals(); Vector dydx(y.rows()); dydx.setZero(); m_system.rhs(t, y, dydx, get_options().speciation_options); odeint::rhs_f rhs = std::bind(std::mem_fn(&AdimKineticSystem::rhs), m_system, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, get_options().speciation_options); //odeint::CashKarpStep driver = odeint::get_cash_karp_step(rhs); odeint::DormandPrinceStep driver = odeint::get_dormand_prince_step(rhs); odeint::StepLength stepl(dt, total); int cnt = 0; while (t < total) { driver.rk_step(y, dydx, t, stepl); m_system.update_to_new_initial_condition(y, stepl.did); cnt +=1; scalar_t remaining = stepl.remaining(t); if (remaining == 0.0) break; if (stepl.next > remaining) stepl.next = remaining; stepl.get_next(); m_current_dt = stepl.test; } m_system.update_total_concentrations(y); m_system.compute_equilibrium(m_system.constraints(), get_options().speciation_options); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp index a85ac57..ccd118c 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp @@ -1,86 +1,88 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP #include "kinetic_system.hpp" #include "kinetic_system_solver_structs.hpp" #include "../../utils/options_handler.hpp" namespace specmicp { namespace kinetics { class AdimKineticModel; class SPECMICP_DLL_PUBLIC AdimKineticSystemSolver: public OptionsHandler { public: AdimKineticSystemSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_moles, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_moles, constraints, database) {} AdimKineticSystemSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_moles, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_moles, constraints, equilibrium_solution, database) {} void solve(scalar_t dt, scalar_t total); scalar_t current_dt() {return m_current_dt;} AdimKineticVariables& variables() {return m_system.variables();} private: scalar_t m_current_dt; AdimKineticSystem m_system; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp index 6bb7c8a..655150d 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp @@ -1,52 +1,54 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS #include "../adimensional/adimensional_system_solver_structs.hpp" #include "../../odeint/runge_kutta_step_structs.hpp" namespace specmicp { namespace kinetics { struct AdimKineticSystemSolverOptions { odeint::EmbeddedRungeKuttaStepOptions rk_options; AdimensionalSystemSolverOptions speciation_options; }; } // end namespace kinetics } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS diff --git a/src/specmicp/adimensional_kinetics/kinetic_variables.hpp b/src/specmicp/adimensional_kinetics/kinetic_variables.hpp index 9f20898..f562cea 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_variables.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_variables.hpp @@ -1,139 +1,141 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICVARIABLES_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICVARIABLES_HPP #include "../../types.hpp" #include "../../database.hpp" #include "../adimensional/adimensional_system_solution.hpp" namespace specmicp { namespace kinetics { //! \brief Variables used in a kinetic computation class AdimKineticVariables { public: AdimKineticVariables( const Vector& total_concentrations, const Vector& mineral_concentration ): m_mineral_kinetics(mineral_concentration), m_total_concentrations_initial(total_concentrations), m_total_concentrations(total_concentrations), m_rate(Vector::Zero(total_concentrations.rows())) {} AdimKineticVariables( const Vector& total_concentrations, const Vector& mineral_concentration, const AdimensionalSystemSolution& equilibrium_solution ): m_mineral_kinetics(mineral_concentration), m_total_concentrations_initial(total_concentrations), m_total_concentrations(total_concentrations), m_rate(Vector::Zero(total_concentrations.rows())), m_equilibrium_solution(equilibrium_solution) {} //! \brief Return the number of species considered in the kinetics computation index_t get_neq() {return m_mineral_kinetics.rows();} // Concentration of minerals // --------------------------- //! \brief Return mole number of mineral "mineral kinetic" scalar_t concentration_mineral(index_t mineral_kinetic) const {return m_mineral_kinetics(mineral_kinetic);} //! \brief Return a const reference to the vector of moles number const Vector& concentration_minerals() const {return m_mineral_kinetics;} //! \brief Return a reference to the vector of moles number Vector& concentration_minerals() {return m_mineral_kinetics;} // Total concentrations // -------------------- //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t total_concentration(index_t component) const {return m_total_concentrations(component);} //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t& total_concentration(index_t component) {return m_total_concentrations(component);} //! \brief Return a const reference to the total concentration (at equilibrium) vector const Vector& total_concentrations() const {return m_total_concentrations;} //! \brief Return a reference to the total concentration at equilibrium vector Vector& total_concentrations() {return m_total_concentrations; } // Initial total concentrations // ---------------------------- //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t total_concentration_initial(index_t component) const { return m_total_concentrations_initial(component);} //! \brief Return a const reference to the total concentration (at equilibrium) vector const Vector& total_concentrations_initial() const {return m_total_concentrations_initial;} //! \brief Return a reference to the total concentration at equilibrium vector Vector& total_concentrations_initial() {return m_total_concentrations_initial; } // Rates // ----- //! \brief Return the value of the flux for 'component' scalar_t rate_component(index_t component) const { return m_rate(component); } //! \brief Return a const reference to the flux vector const Vector& rate_components() const {return m_rate;} //! \brief Return a reference to the flux vector Vector& rate_components() {return m_rate;} //! \brief reset the rates void reset_rate() {m_rate.setZero();} // Equilibrium // ------------ //! \brief Const Reference to the equilibrium state const AdimensionalSystemSolution& equilibrium_solution() const {return m_equilibrium_solution;} //! \brief Reference to the equilibrium State AdimensionalSystemSolution& equilibrium_solution() {return m_equilibrium_solution;} //! \brief Update the equilibrium state void update_equilibrium_solution(const AdimensionalSystemSolution& other) {m_equilibrium_solution = other;} private: Vector m_mineral_kinetics; //!< Number of moles of minerals at equilibrium Vector m_total_concentrations_initial; //!< Initial total concentrations at equilibrium Vector m_total_concentrations; //!< total concentration at equilibrium, Vector m_rate; AdimensionalSystemSolution m_equilibrium_solution; //!< Current equilibrium state }; } // end namespace kinetics } // end namespace specmicp #endif // SPECMICP_SPECMICP_KINETICS_KINETICVARIABLES_HPP diff --git a/src/specmicp/io/configuration.cpp b/src/specmicp/io/configuration.cpp index 104c48a..5ee17f3 100644 --- a/src/specmicp/io/configuration.cpp +++ b/src/specmicp/io/configuration.cpp @@ -1,595 +1,597 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "configuration.hpp" #include "../../utils/io/yaml.hpp" #include "../adimensional/adimensional_system_solver_structs.hpp" #include "../adimensional/config_default_options_solver.h" #include "../problem_solver/formulation.hpp" #include "../../database.hpp" #include "../../physics/units.hpp" #include "../../physics/laws.hpp" #define S_UNITS "units" #define S_UNITS_A_LENGTH "length" #define S_SPECMICP "specmicp_options" #define S_SPECMICP_A_MAX_ITER "maximum_iteration" #define S_SPECMICP_A_RES_TOL "residual_tolerance" #define S_SPECMICP_A_STEP_TOL "step_tolerance" #define S_SPECMICP_A_MAX_STEP_LENGTH "maximum_step_length" #define S_SPECMICP_A_MAX_STEP_MAX_ITER "maximum_step_max_iteration" #define S_SPECMICP_A_SCALING "enable_scaling" #define S_SPECMICP_A_NONMONOTONE "enable_nonmonotone_linesearch" #define S_SPECMICP_A_DESCENT_DIRECTION "factor_descent_direction" #define S_SPECMICP_A_COND_CHECK "threshold_condition_check" #define S_SPECMICP_A_TRSHOLD_CYCLING_LSEARCH "threshold_cycling_linesearch" #define S_SPECMICP_A_NONIDEAL_TOL "non_ideality_tolerance" #define S_SPECMICP_A_CUTOFF_TOT_CONC "cutoff_total_concentration" #define S_FORMULATION "formulation" #define S_FORMULATION_A_SOLUTION "solution" #define S_FORMULATION_A_AQUEOUS "aqueous" #define S_FORMULATION_A_MINERALS "solid_phases" #define S_FORMULATION_A_AMOUNT "amount" #define S_FORMULATION_A_UNIT "unit" #define S_FORMULATION_A_LABEL "label" #define S_CONSTRAINTS "constraints" #define S_CONSTRAINTS_A_CHARGEKEEPER "charge_keeper" #define S_CONSTRAINTS_A_FIXEDACTIVITY "fixed_activity" #define S_CONSTRAINTS_A_FIXEDMOLALITY "fixed_molality" #define S_CONSTRAINTS_A_FIXEDFUGACITY "fixed_fugacity" #define S_CONSTRAINTS_A_SATURATED_SYSTEM "saturated_system" #define S_CONSTRAINTS_A_CONSERVATION_WATER "conservation_water" #define S_CONSTRAINTS_A_SURFACE_MODEL "surface_model" #define S_CONSTRAINTS_A_SURFACE_CONCENTRATION "surface_site_concentration" #define S_CONSTRAINTS_A_LABEL "label" #define S_CONSTRAINTS_A_AMOUNT "amount" #define S_CONSTRAINTS_A_AMOUNTLOG "amount_log" #define S_CONSTRAINTS_A_LABEL_COMPONENT "label_component" #define S_CONSTRAINTS_A_LABEL_GAS "label_gas" namespace specmicp { namespace io { // Additional declarations // ======================= void configure_specmicp_constraints_fixed_activity( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_activity, const RawDatabasePtr& raw_db ); void configure_specmicp_constraints_fixed_fugacity( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_fugacity, const RawDatabasePtr& raw_db ); void configure_specmicp_constraints_fixed_molality( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_molality, const RawDatabasePtr& raw_db ); scalar_t molar_mass_aqueous_unknown_class(const std::string& label, const RawDatabasePtr& raw_db); scalar_t molar_mass_solid_unknown_class(const std::string& label, const RawDatabasePtr& raw_db ); scalar_t molar_volume_solid_unknown_class(const std::string& label, const RawDatabasePtr& raw_db ); // Implementation // ============== void configure_specmicp_options( AdimensionalSystemSolverOptions& options, const YAML::Node& configuration ) { check_mandatory_yaml_node(configuration, S_SPECMICP, "__main__"); const YAML::Node& conf = configuration[S_SPECMICP]; // fixme units //options.units_set = the_units_set; options.solver_options.fvectol = get_yaml_optional(conf, S_SPECMICP_A_RES_TOL, S_SPECMICP, SPECMICP_DEFAULT_RES_TOL); options.solver_options.steptol = get_yaml_optional(conf, S_SPECMICP_A_STEP_TOL, S_SPECMICP, SPECMICP_DEFAULT_STEP_TOL); options.solver_options.max_iter = get_yaml_optional(conf, S_SPECMICP_A_MAX_ITER, S_SPECMICP, SPECMICP_DEFAULT_MAX_ITER); options.solver_options.maxstep = get_yaml_optional(conf, S_SPECMICP_A_MAX_STEP_LENGTH, S_SPECMICP, SPECMICP_DEFAULT_MAX_STEP); options.solver_options.maxiter_maxstep = get_yaml_optional(conf, S_SPECMICP_A_MAX_STEP_MAX_ITER, S_SPECMICP, std::min(SPECMICP_DEFAULT_MAX_ITER_MAXSTEP, options.solver_options.max_iter) ); options.solver_options.use_scaling = get_yaml_optional(conf, S_SPECMICP_A_SCALING, S_SPECMICP, SPECMICP_DEFAULT_USE_SCALING); options.solver_options.non_monotone_linesearch = get_yaml_optional(conf, S_SPECMICP_A_NONMONOTONE, S_SPECMICP, SPECMICP_DEFAULT_USE_NONMONOTONE_LSEARCH); options.solver_options.factor_descent_condition = get_yaml_optional(conf, S_SPECMICP_A_DESCENT_DIRECTION, S_SPECMICP, SPECMICP_DEFAULT_FACTOR_DESC_COND ); options.solver_options.condition_limit = get_yaml_optional(conf, S_SPECMICP_A_COND_CHECK, S_SPECMICP, SPECMICP_DEFAULT_COND_THRESHOLD); options.solver_options.threshold_cycling_linesearch = get_yaml_optional(conf, S_SPECMICP_A_TRSHOLD_CYCLING_LSEARCH, S_SPECMICP, SPECMICP_DEFAULT_TRHSOLD_CYCLING_LSEARCH ); options.system_options.non_ideality_tolerance = get_yaml_optional(conf, S_SPECMICP_A_NONIDEAL_TOL, S_SPECMICP, SPECMICP_DEFAULT_NONIDEAL_TOL); options.system_options.cutoff_total_concentration = get_yaml_optional(conf, S_SPECMICP_A_CUTOFF_TOT_CONC, S_SPECMICP, SPECMICP_DEFAULT_CUTOFF_TOT_CONC); if (configuration[S_UNITS]) { const YAML::Node& conf = configuration[S_UNITS]; if (conf[S_UNITS_A_LENGTH]) { const std::string length_u = conf[S_UNITS_A_LENGTH].as(); if (length_u == "centimeter") options.units_set.length = units::LengthUnit::centimeter; else if (length_u == "decimeter") options.units_set.length = units::LengthUnit::decimeter; else if (length_u == "meter") options.units_set.length = units::LengthUnit::meter; else throw std::invalid_argument("Unknown length unit : '"+length_u+"'.\n" + "Valid options : 'centimeter', 'decimeter', 'meter'."); } } } void configure_specmicp_formulation( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& units_sets ) { configure_specmicp_formulation_solution(formulation, conf_formulation, units_sets); configure_specmicp_formulation_aqueous(formulation, conf_formulation, raw_db, units_sets); configure_specmicp_formulation_solid(formulation, conf_formulation, raw_db, units_sets); } void configure_specmicp_formulation_solution( Formulation& formulation, const YAML::Node& conf_formulation, const units::UnitsSet& _) { check_mandatory_yaml_node(conf_formulation, S_FORMULATION_A_SOLUTION, S_FORMULATION); const YAML::Node& sol_conf = conf_formulation[S_FORMULATION_A_SOLUTION]; check_mandatory_yaml_node(sol_conf, S_FORMULATION_A_AMOUNT, S_FORMULATION_A_SOLUTION); scalar_t factor=1.0; if (sol_conf[S_FORMULATION_A_UNIT]) { units::AmountUnit unit; units::parse_amount_unit(sol_conf[S_FORMULATION_A_UNIT].as(), unit); if (unit.type != units::AmountUnitType::Mass ) { throw std::invalid_argument("'" + sol_conf[S_FORMULATION_A_UNIT].as() + "'' is not a mass unit (in the solution configuration) !"); } factor = unit.factor_si; } formulation.set_mass_solution(sol_conf[S_FORMULATION_A_AMOUNT].as()*factor); } void configure_specmicp_formulation_aqueous( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& _) { check_mandatory_yaml_node(conf_formulation, S_FORMULATION_A_AQUEOUS, S_FORMULATION); const YAML::Node& aq_conf = conf_formulation[S_FORMULATION_A_AQUEOUS]; for (auto aqueous_conf: aq_conf) { check_mandatory_yaml_node(aqueous_conf, S_FORMULATION_A_LABEL, S_FORMULATION_A_AQUEOUS); check_mandatory_yaml_node(aqueous_conf, S_FORMULATION_A_AMOUNT, S_FORMULATION_A_AQUEOUS); check_mandatory_yaml_node(aqueous_conf, S_FORMULATION_A_UNIT, S_FORMULATION_A_AQUEOUS); std::string label = aqueous_conf[S_FORMULATION_A_LABEL].as(); scalar_t factor = 1.0; units::AmountUnit unit; units::parse_amount_unit(aqueous_conf[S_FORMULATION_A_UNIT].as(), unit); if (unit.type == units::AmountUnitType::Molality) { factor = unit.factor_si; } else if (unit.type == units::AmountUnitType::MoleConcentration) { factor = unit.factor_si/laws::density_water(units::celsius(25.0), units::LengthUnit::meter, units::MassUnit::kilogram); } else if (unit.type == units::AmountUnitType::MassConcentration) { const scalar_t molar_mass = molar_mass_aqueous_unknown_class(label, raw_db); factor = unit.factor_si / molar_mass / laws::density_water(units::celsius(25.0), units::LengthUnit::meter, units::MassUnit::kilogram); } else if (unit.type == units::AmountUnitType::Mass) { const scalar_t molar_mass = molar_mass_aqueous_unknown_class(label, raw_db); factor = unit.factor_si / molar_mass / formulation.mass_solution; } else if (unit.type == units::AmountUnitType::NumberOfMoles) { factor = unit.factor_si / formulation.mass_solution; } else { throw std::invalid_argument("'"+aqueous_conf[S_FORMULATION_A_UNIT].as() + "' is not a valid unit for an aqueous species"); } const scalar_t molality = factor*aqueous_conf[S_FORMULATION_A_AMOUNT].as(); formulation.add_aqueous_species(label, molality); } } void configure_specmicp_formulation_solid( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& unit_set) { check_mandatory_yaml_node(conf_formulation, S_FORMULATION_A_MINERALS, S_FORMULATION); const YAML::Node& minerals_conf = conf_formulation[S_FORMULATION_A_MINERALS]; for (auto solid_conf : minerals_conf) { check_mandatory_yaml_node(solid_conf, S_FORMULATION_A_LABEL, S_FORMULATION_A_AQUEOUS); check_mandatory_yaml_node(solid_conf, S_FORMULATION_A_AMOUNT, S_FORMULATION_A_AQUEOUS); check_mandatory_yaml_node(solid_conf, S_FORMULATION_A_UNIT, S_FORMULATION_A_AQUEOUS); const std::string label = solid_conf[S_FORMULATION_A_LABEL].as(); scalar_t factor = 1.0; units::AmountUnit unit; units::parse_amount_unit(solid_conf[S_FORMULATION_A_UNIT].as(), unit); // convert to mole concentration is SI if (unit.type == units::AmountUnitType::MoleConcentration or unit.type == units::AmountUnitType::NumberOfMoles) { factor = unit.factor_si; } else if (unit.type == units::AmountUnitType::MassConcentration or unit.type == units::AmountUnitType::Mass ) { const scalar_t molar_mass = molar_mass_solid_unknown_class(label, raw_db); factor = unit.factor_si / molar_mass; } else if (unit.type == units::AmountUnitType::Volume) { const scalar_t molar_volume = molar_volume_solid_unknown_class(label, raw_db); // may raise an error factor = unit.factor_si / molar_volume; } else { throw std::invalid_argument("'"+solid_conf[S_FORMULATION_A_UNIT].as() + "' is not a valid unit for a solid phase"); } // set to the correct units switch (unit_set.length) { case units::LengthUnit::decimeter: factor *= 1e-3; break; case units::LengthUnit::centimeter: factor *= 1e-6; break; case units::LengthUnit::meter: break; // just to remove warning } const scalar_t mole_conc = factor*solid_conf[S_FORMULATION_A_AMOUNT].as(); formulation.add_mineral(label, mole_conc); } } void configure_specmicp_constraints( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints, const RawDatabasePtr& raw_db ) { // Component equations // =================== // Charge keeper // ------------- if (conf_constraints[S_CONSTRAINTS_A_CHARGEKEEPER]) { const std::string label = conf_constraints[S_CONSTRAINTS_A_CHARGEKEEPER].as(); const index_t id = raw_db->get_id_component(label); if (id == no_species) { throw std::invalid_argument("'"+label+"' is not a valid component (charge_keeper)."); } constraints.set_charge_keeper(id); } // Fixed activity // -------------- if (conf_constraints[S_CONSTRAINTS_A_FIXEDACTIVITY]) { configure_specmicp_constraints_fixed_activity(constraints, conf_constraints[S_CONSTRAINTS_A_FIXEDACTIVITY], raw_db); } // Fixed fugacity // -------------- if (conf_constraints[S_CONSTRAINTS_A_FIXEDFUGACITY]) { configure_specmicp_constraints_fixed_fugacity(constraints, conf_constraints[S_CONSTRAINTS_A_FIXEDFUGACITY], raw_db); } // Fixed molality // -------------- if (conf_constraints[S_CONSTRAINTS_A_FIXEDMOLALITY]) { configure_specmicp_constraints_fixed_molality(constraints, conf_constraints[S_CONSTRAINTS_A_FIXEDMOLALITY], raw_db); } // Water // ===== if (conf_constraints[S_CONSTRAINTS_A_CONSERVATION_WATER]) { if (conf_constraints[S_CONSTRAINTS_A_SATURATED_SYSTEM] and conf_constraints[S_CONSTRAINTS_A_SATURATED_SYSTEM].as()) { throw std::invalid_argument("Options '" S_CONSTRAINTS_A_CONSERVATION_WATER "' and '" S_CONSTRAINTS_A_SATURATED_SYSTEM "' cannot be used at the same time"); } const bool value = conf_constraints[S_CONSTRAINTS_A_CONSERVATION_WATER].as(); if (value) constraints.enable_conservation_water(); else constraints.disable_conservation_water(); } if (conf_constraints[S_CONSTRAINTS_A_SATURATED_SYSTEM]) { const bool value = conf_constraints[S_CONSTRAINTS_A_SATURATED_SYSTEM].as(); if (value) constraints.set_saturated_system(); } // Surface model // ============= if (conf_constraints[S_CONSTRAINTS_A_SURFACE_MODEL]) { const bool is_enabled = conf_constraints[S_CONSTRAINTS_A_SURFACE_MODEL].as(); if (is_enabled) { check_mandatory_yaml_node(conf_constraints, S_CONSTRAINTS_A_SURFACE_CONCENTRATION, S_CONSTRAINTS); const scalar_t value = conf_constraints[S_CONSTRAINTS_A_SURFACE_CONCENTRATION].as(); constraints.enable_surface_model(value); } else { constraints.disable_surface_model(); } } } void configure_specmicp_constraints_fixed_activity( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_activity, const RawDatabasePtr& raw_db ) { for (auto fixact_conf: conf_constraints_fixed_activity) { check_mandatory_yaml_node(fixact_conf, S_CONSTRAINTS_A_LABEL, S_CONSTRAINTS_A_FIXEDACTIVITY); const std::string label = fixact_conf[S_CONSTRAINTS_A_LABEL].as(); const index_t id = raw_db->get_id_component(label); if (id == no_species) { throw std::invalid_argument("'"+label+"' is not a valid component (fixed_activity)."); } scalar_t value; if (fixact_conf[S_CONSTRAINTS_A_AMOUNT]) { value = std::log10(fixact_conf[S_CONSTRAINTS_A_AMOUNT].as()); } else if (fixact_conf[S_CONSTRAINTS_A_AMOUNTLOG]) { value = fixact_conf[S_CONSTRAINTS_A_AMOUNTLOG].as(); } else { throw std::invalid_argument("Either '" S_CONSTRAINTS_A_AMOUNT "' or '" S_CONSTRAINTS_A_AMOUNTLOG "' are required in section '" S_CONSTRAINTS_A_FIXEDACTIVITY "'."); } constraints.add_fixed_activity_component(id, value); } } void configure_specmicp_constraints_fixed_fugacity( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_fugacity, const RawDatabasePtr& raw_db ) { for(auto fixfug_conf: conf_constraints_fixed_fugacity) { check_mandatory_yaml_node(fixfug_conf, S_CONSTRAINTS_A_LABEL_COMPONENT, S_CONSTRAINTS_A_FIXEDFUGACITY); check_mandatory_yaml_node(fixfug_conf, S_CONSTRAINTS_A_LABEL_GAS, S_CONSTRAINTS_A_FIXEDFUGACITY); const std::string& label_c = fixfug_conf[S_CONSTRAINTS_A_LABEL_COMPONENT].as(); const index_t id_c = raw_db->get_id_component(label_c); if (id_c == no_species) { throw std::invalid_argument("'"+label_c+"' is not a valid component (fixed_fugacity)"); } const std::string& label_g = fixfug_conf[S_CONSTRAINTS_A_LABEL_GAS].as(); const index_t id_g = raw_db->get_id_gas(label_g); if (id_g == no_species) { throw std::invalid_argument("'"+label_g+"' is not a valid gas (fixed_fugacity)"); } scalar_t value; if (fixfug_conf[S_CONSTRAINTS_A_AMOUNT]) { value = std::log10(fixfug_conf[S_CONSTRAINTS_A_AMOUNT].as()); } else if (fixfug_conf[S_CONSTRAINTS_A_AMOUNTLOG]) { value = fixfug_conf[S_CONSTRAINTS_A_AMOUNTLOG].as(); } else { throw std::invalid_argument("Either '" S_CONSTRAINTS_A_AMOUNT "' or '" S_CONSTRAINTS_A_AMOUNTLOG "' are required in section '" S_CONSTRAINTS_A_FIXEDFUGACITY "'."); } constraints.add_fixed_fugacity_gas(id_g, id_c, value); } } void configure_specmicp_constraints_fixed_molality( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints_fixed_molality, const RawDatabasePtr& raw_db ) { for (auto fixmol_conf: conf_constraints_fixed_molality) { check_mandatory_yaml_node(fixmol_conf, S_CONSTRAINTS_A_LABEL, S_CONSTRAINTS_A_FIXEDMOLALITY); const std::string& label = fixmol_conf[S_CONSTRAINTS_A_LABEL].as(); const index_t id = raw_db->get_id_component(label); if (id == no_species) { throw std::invalid_argument("'"+label+"' is not a valid component (fixed_molality)"); } scalar_t value; if (fixmol_conf[S_CONSTRAINTS_A_AMOUNT]) { value = std::log10(fixmol_conf[S_CONSTRAINTS_A_AMOUNT].as()); } else if (fixmol_conf[S_CONSTRAINTS_A_AMOUNTLOG]) { value = fixmol_conf[S_CONSTRAINTS_A_AMOUNTLOG].as(); } else { throw std::invalid_argument("Either '" S_CONSTRAINTS_A_AMOUNT "' or '" S_CONSTRAINTS_A_AMOUNTLOG "' are required in section '" S_CONSTRAINTS_A_FIXEDMOLALITY "'."); } constraints.add_fixed_molality_component(id, value); } } scalar_t molar_mass_aqueous_unknown_class(const std::string& label, const RawDatabasePtr& raw_db) { scalar_t molar_mass; if (raw_db->get_id_component(label) != no_species) { molar_mass = raw_db->molar_mass_basis(raw_db->get_id_component(label), units::MassUnit::kilogram); } else if (raw_db->get_id_aqueous(label) != no_species) { molar_mass = raw_db->molar_mass_aqueous(raw_db->get_id_aqueous(label), units::MassUnit::kilogram); } else if (raw_db->get_id_compound(label) != no_species) { molar_mass = raw_db->molar_mass_compound(raw_db->get_id_compound(label), units::MassUnit::kilogram); } else { throw std::invalid_argument("'"+label+"is not a valid species"); } return molar_mass; } scalar_t molar_mass_solid_unknown_class(const std::string& label, const RawDatabasePtr& raw_db ) { scalar_t molar_mass; if (raw_db->get_id_mineral(label) != no_species) { molar_mass = raw_db->molar_mass_mineral(raw_db->get_id_mineral(label), units::MassUnit::kilogram); } else if (raw_db->get_id_mineral_kinetic(label) != no_species) { molar_mass = raw_db->molar_mass_mineral_kinetic(raw_db->get_id_mineral_kinetic(label), units::MassUnit::kilogram); } else { throw std::invalid_argument("'"+label+"' is not a valid solid phase."); } return molar_mass; } scalar_t molar_volume_solid_unknown_class(const std::string& label, const RawDatabasePtr& raw_db ) { scalar_t molar_volume = -1; if (raw_db->get_id_mineral(label) != no_species) { molar_volume = raw_db->molar_volume_mineral(raw_db->get_id_mineral(label), units::LengthUnit::meter); } else if (raw_db->get_id_mineral_kinetic(label) != no_species) { molar_volume = raw_db->molar_volume_mineral_kinetic(raw_db->get_id_mineral_kinetic(label), units::LengthUnit::meter); } else { throw std::invalid_argument("'"+label+"' is not a valid solid phase."); } if (molar_volume < 0) { throw std::runtime_error("The molar volume for solid phase '"+label+"' is not defined"); } return molar_volume; } } //end namespace io } //end namespace specmicp diff --git a/src/specmicp/io/configuration.hpp b/src/specmicp/io/configuration.hpp index 33365e9..e370c97 100644 --- a/src/specmicp/io/configuration.hpp +++ b/src/specmicp/io/configuration.hpp @@ -1,105 +1,107 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_IO_HPP #define SPECMICP_SPECMICP_IO_HPP #include "../../types.hpp" #include namespace YAML { class Node; } //end namespace YAML namespace specmicp { struct AdimensionalSystemSolverOptions; struct Formulation; struct AdimensionalSystemConstraints; namespace database { struct DataContainer; } using RawDatabasePtr = std::shared_ptr; namespace units { struct UnitsSet; } //end namespace units namespace io { void SPECMICP_DLL_PUBLIC configure_specmicp_options( AdimensionalSystemSolverOptions& options, const YAML::Node& configuration ); void SPECMICP_DLL_PUBLIC configure_specmicp_formulation( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& units_sets ); void SPECMICP_DLL_PUBLIC configure_specmicp_formulation_solution( Formulation& formulation, const YAML::Node& conf_formulation, const units::UnitsSet& units_set ); void SPECMICP_DLL_PUBLIC configure_specmicp_formulation_aqueous( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& _ ); void SPECMICP_DLL_PUBLIC configure_specmicp_formulation_solid( Formulation& formulation, const YAML::Node& conf_formulation, const RawDatabasePtr& raw_db, const units::UnitsSet& _ ); void SPECMICP_DLL_PUBLIC configure_specmicp_constraints( AdimensionalSystemConstraints& constraints, const YAML::Node& conf_constraints, const RawDatabasePtr& raw_db ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_SPECMICP_IO_HPP diff --git a/src/specmicp/io/hdf5_adimensional.cpp b/src/specmicp/io/hdf5_adimensional.cpp index d132c02..667d1d8 100644 --- a/src/specmicp/io/hdf5_adimensional.cpp +++ b/src/specmicp/io/hdf5_adimensional.cpp @@ -1,174 +1,176 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "hdf5_adimensional.hpp" #include "../adimensional/adimensional_system_solution.hpp" #include "../../utils/io/specmicp_hdf5.hpp" #include "../../utils/io/hdf5_eigen.hpp" namespace specmicp { namespace io { //! \brief Implementation class to save a HDF5 file //! //! \internal class SPECMICP_DLL_LOCAL AdimensionalSystemSolutionHDF5Saver { public: AdimensionalSystemSolutionHDF5Saver( const AdimensionalSystemSolution& solution): m_solution(solution) {} //! \brief Save the solution into file (in subgroup section/name) void save( HDF5File& file, const std::string& name, const std::string& section ); private: void save_main_variables(HDF5File& file, const std::string& section); void save_molalities(HDF5File& file, const std::string& section); void save_loggamma(HDF5File& file, const std::string& section); void save_gas_fugacities(HDF5File& file, const std::string& section); void save_sorbed_molalities(HDF5File& file, const std::string& section); const AdimensionalSystemSolution& m_solution; }; void save_adimensional_system_solution( HDF5File& file, const std::string& name, const std::string& section, const AdimensionalSystemSolution& solution ) { AdimensionalSystemSolutionHDF5Saver saver(solution); saver.save(file, name, section); } // Implementation // ============== void AdimensionalSystemSolutionHDF5Saver::save( HDF5File& file, const std::string& name, const std::string& section ) { auto complete_sec = file.complete_name(name, section); auto adim_group = file.create_group(complete_sec); save_main_variables(file, complete_sec); save_molalities(file, complete_sec); save_loggamma(file, complete_sec); if (m_solution.gas_fugacities.rows() > 0) { save_gas_fugacities(file, complete_sec); } if (m_solution.sorbed_molalities.rows() > 0) { save_sorbed_molalities(file, complete_sec); } } void AdimensionalSystemSolutionHDF5Saver::save_main_variables( HDF5File& file, const std::string §ion ) { auto dataset = save_eigen_matrix(file, "main_variables", section, m_solution.main_variables ); hsize_t dims[] = {2}; auto dspace = H5::DataSpace(1, dims); auto attribute = dataset->createAttribute("attribute", H5::PredType::NATIVE_DOUBLE, dspace); scalar_t attribute_values[] = {m_solution.inert_volume_fraction, m_solution.ionic_strength}; attribute.write(H5::PredType::NATIVE_DOUBLE, attribute_values); } void AdimensionalSystemSolutionHDF5Saver::save_molalities( HDF5File& file, const std::string §ion ) { save_eigen_matrix(file, "secondary_molalities", section, m_solution.secondary_molalities ); } void AdimensionalSystemSolutionHDF5Saver::save_loggamma( HDF5File& file, const std::string §ion ) { save_eigen_matrix(file, "log_gamma", section, m_solution.log_gamma ); } void AdimensionalSystemSolutionHDF5Saver::save_gas_fugacities( HDF5File& file, const std::string §ion ) { save_eigen_matrix(file, "gas_fugacities", section, m_solution.gas_fugacities ); } void AdimensionalSystemSolutionHDF5Saver::save_sorbed_molalities( HDF5File& file, const std::string §ion ) { save_eigen_matrix(file, "sorbed_molalities", section, m_solution.sorbed_molalities ); } } //end namespace io } //end namespace specmicp diff --git a/src/specmicp/io/hdf5_adimensional.hpp b/src/specmicp/io/hdf5_adimensional.hpp index ee5a3fa..51d0983 100644 --- a/src/specmicp/io/hdf5_adimensional.hpp +++ b/src/specmicp/io/hdf5_adimensional.hpp @@ -1,57 +1,59 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_HDF5_ADIMENSIONAL_HPP #define SPECMICP_IO_HDF5_ADIMENSIONAL_HPP #include "../../macros.hpp" #include namespace specmicp { struct AdimensionalSystemSolution; namespace io { class HDF5File; void SPECMICP_DLL_PUBLIC save_adimensional_system_solution( HDF5File& file, const std::string& name, const std::string& section, const AdimensionalSystemSolution& solution ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_HDF5_ADIMENSIONAL_HPP diff --git a/src/specmicp/io/print.cpp b/src/specmicp/io/print.cpp index 6a83f0b..fa7d4c7 100644 --- a/src/specmicp/io/print.cpp +++ b/src/specmicp/io/print.cpp @@ -1,84 +1,86 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "print.hpp" #include "../adimensional/adimensional_system_structs.hpp" #include namespace specmicp { namespace io { void print_specmicp_constraints( const RawDatabasePtr& the_database, const AdimensionalSystemConstraints& constraints ) { std::cout << "Constraints \n ---------- \n"; std::cout << "Total concentrations :\n"; for (auto comp: the_database->range_component()) std::cout << the_database->get_label_component(comp) << " - " << constraints.total_concentrations(comp) << std::endl; if (constraints.charge_keeper != no_species) { std::cout << "Charge keeper : " << the_database->get_label_component(constraints.charge_keeper) << std::endl; } if (constraints.fixed_molality_cs.size()) { std::cout << "Fixed molality :\n"; for (auto comp: constraints.fixed_molality_cs) { std::cout << " - " << the_database->get_label_component(comp.id_component) << ": " << comp.log_value << "\n"; } } if (constraints.fixed_activity_cs.size()) { std::cout << "Fixed activity :\n"; for (auto comp: constraints.fixed_activity_cs) { std::cout << " - " << the_database->get_label_component(comp.id_component) << " - " << comp.log_value << "\n"; } } if (constraints.fixed_fugacity_cs.size()) { std::cout << "Fixed fugacity :\n"; for (auto comp: constraints.fixed_fugacity_cs) { std::cout << the_database->get_label_component(comp.id_component) << " - " << comp.log_value << "\n"; } } std::cout << "Inert volume fraction : " << constraints.inert_volume_fraction << "\n"; std::cout << "-------------" << std::endl; } } //end namespace io } //end namespace specmicp diff --git a/src/specmicp/io/print.hpp b/src/specmicp/io/print.hpp index 0808c15..8a90847 100644 --- a/src/specmicp/io/print.hpp +++ b/src/specmicp/io/print.hpp @@ -1,54 +1,56 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_IO_PRINT_HPP #define SPECMICP_SPECMICP_IO_PRINT_HPP #include "../../database.hpp" namespace specmicp { struct AdimensionalSystemConstraints; namespace io { //! \brief Print the constraints in a user-friendly fashion, for inspection void print_specmicp_constraints( const RawDatabasePtr& the_database, const AdimensionalSystemConstraints& constraints ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_SPECMICP_IO_PRINT_HPP diff --git a/src/specmicp/problem_solver/dissolver.cpp b/src/specmicp/problem_solver/dissolver.cpp index 7a50ceb..2a2c23c 100644 --- a/src/specmicp/problem_solver/dissolver.cpp +++ b/src/specmicp/problem_solver/dissolver.cpp @@ -1,201 +1,203 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "dissolver.hpp" #include "formulation.hpp" #include "../../database/database.hpp" #include namespace specmicp { Vector Dissolver::dissolve(const Formulation &the_problem) { return dissolve(the_problem, true); } Vector Dissolver::dissolve(const Formulation& the_problem, bool modify_db) { m_components_to_keep[0] = true; m_components_to_keep[1] = true; for (index_t component: m_database->range_aqueous_component()) { m_components_to_keep[component] = false; } m_total_concentration.setZero(); set_solvent(the_problem.mass_solution); for (auto it=the_problem.concentration_aqueous.begin(); it!=the_problem.concentration_aqueous.end(); ++it) { dissolve_aqueous(it->first, it->second, the_problem.mass_solution); } for (auto it=the_problem.amount_minerals.begin(); it!=the_problem.amount_minerals.end(); ++it) { dissolve_mineral(it->first, it->second); } if (modify_db) { keep_extra_components(the_problem.extra_components_to_keep); reduce_problem(); } // Remove minerals if needed if (the_problem.minerals_to_keep.size() > 0) { database::Database(m_database).minerals_keep_only(the_problem.minerals_to_keep); } return m_total_concentration; } void Dissolver::set_solvent(scalar_t amount) { index_t idw = m_database->water_index(); specmicp_assert(idw != no_species and idw == 0); m_total_concentration(0) += amount/m_database->molar_mass_basis(idw, mass_unit()); m_components_to_keep[0] = true; } void Dissolver::dissolve_aqueous(std::string label, scalar_t concentration, scalar_t mass_solution) { index_t idaq = m_database->get_id_component(label); // component if (idaq != no_species) { m_total_concentration(idaq) += mass_solution*concentration; m_components_to_keep[idaq] = true; } // aqueous else { index_t idsaq = m_database->get_id_aqueous(label); if (idsaq != no_species) { for (index_t component: m_database->range_component()) { if (m_database->nu_aqueous(idsaq, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_aqueous(idsaq, component)*mass_solution*concentration; m_components_to_keep[component] = true; } } // compounds else { index_t idcomp = m_database->get_id_compound(label); if (idcomp == no_species) { throw std::invalid_argument("Unknown species : " + label + "."); } for (index_t component: m_database->range_component()) { if (m_database->nu_compound(idcomp, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_compound(idcomp, component)*mass_solution*concentration; m_components_to_keep[component] = true; } } } } void Dissolver::dissolve_mineral(std::string label, scalar_t amount) { index_t id_mineral = m_database->get_id_mineral(label); if (id_mineral != no_species) { for (index_t component: m_database->range_component()) { if (m_database->nu_mineral(id_mineral, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_mineral(id_mineral, component)*amount; m_components_to_keep[component] = true; } } else { index_t id_minkin = m_database->get_id_mineral_kinetic(label); if (id_minkin == no_species) { throw std::invalid_argument("Unknown mineral : " + label + "."); } for (index_t component: m_database->range_component()) { if (m_database->nu_mineral_kinetic(id_minkin, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_mineral_kinetic(id_minkin, component)*amount; m_components_to_keep[component] = true; } } } void Dissolver::keep_extra_components(const std::vector& list_component_to_keep) { for (auto it:list_component_to_keep) { index_t idc = m_database->get_id_component(it); if (idc == no_species) { throw std::invalid_argument("Species '" + it + "' is not a component"); } m_components_to_keep[idc] = true; } } void Dissolver::reduce_problem() { std::vector to_remove; to_remove.reserve(m_database->nb_component()); index_t new_id = 0; Vector reduced_tot_conc(m_database->nb_component()); const index_t h_component = m_database->get_id_component_from_element("H"); m_components_to_keep[h_component] = true; // do not remove H[+]/HO[-] // Copy information for (index_t component: m_database->range_component()) { if (m_components_to_keep[component]) { reduced_tot_conc(new_id) = m_total_concentration(component); ++new_id; } else { to_remove.push_back(component); } } // Remove components from database database::Database(m_database).remove_components(to_remove); // Resize total concentrations reduced_tot_conc.conservativeResize(m_database->nb_component()); m_total_concentration = reduced_tot_conc; } } // end namespace specmicp diff --git a/src/specmicp/problem_solver/dissolver.hpp b/src/specmicp/problem_solver/dissolver.hpp index 518584e..104c916 100644 --- a/src/specmicp/problem_solver/dissolver.hpp +++ b/src/specmicp/problem_solver/dissolver.hpp @@ -1,82 +1,84 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP #define SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP #include "../../types.hpp" #include "../../database.hpp" #include "../../physics/units.hpp" namespace specmicp { struct Formulation; //! \brief Return the total concentration of a given formulation class SPECMICP_DLL_PUBLIC Dissolver: public units::UnitBaseClass { public: Dissolver(RawDatabasePtr the_database): m_database(the_database), m_total_concentration(Vector::Zero(the_database->nb_component())), m_components_to_keep(the_database->nb_component()) {} //! \brief Dissolve the problem into the components //! //! Also simplify the database Vector dissolve(const Formulation& the_problem); //! \brief Dissolve the sytem into components //! //! If modify db is true then the database is simplified Vector dissolve(const Formulation& the_problem, bool modify_db); //! \brief Return the total concentration vector Vector get_total_concentration() {return m_total_concentration;} private: void SPECMICP_DLL_LOCAL set_solvent(scalar_t amount); void SPECMICP_DLL_LOCAL dissolve_aqueous(std::string label, scalar_t concentration, scalar_t mass_solution); void SPECMICP_DLL_LOCAL dissolve_mineral(std::string label, scalar_t amount); void SPECMICP_DLL_LOCAL keep_extra_components(const std::vector& list_component_to_keep); void SPECMICP_DLL_LOCAL reduce_problem(); RawDatabasePtr m_database; Vector m_total_concentration; std::vector m_components_to_keep; }; } // end namespace specmicp #endif //SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP diff --git a/src/specmicp/problem_solver/formulation.hpp b/src/specmicp/problem_solver/formulation.hpp index 904ef89..24a37cc 100644 --- a/src/specmicp/problem_solver/formulation.hpp +++ b/src/specmicp/problem_solver/formulation.hpp @@ -1,112 +1,114 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP #define SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP #include "../../types.hpp" #include #include #include namespace specmicp { struct Formulation { //! \brief Mass of the solvent scalar_t mass_solution; //! \brief Contains the amount of each solid phase std::map concentration_aqueous; //! \brief Contains the amount of each solid phase //! included in the problem std::map amount_minerals; //! \brief Extra component to leave in the database //! //! All components not present in this list and with //! a total concentration of zero will be removed. std::vector extra_components_to_keep; //! \brief List of solid phase at equilibrium to keep in the computation //! //! Leave empty to keep all solid phases present in the database std::vector minerals_to_keep; //! \brief Set the mass of the solution void set_mass_solution(scalar_t mass) { mass_solution = mass; } //! \brief Add an aqueous species to the system //! //! \param label label of a component or a secondary species or a compounds //! \param concentration in moles per mass unit of water void add_aqueous_species(const std::string& label, scalar_t concentration) { concentration_aqueous.insert(std::pair(label, concentration)); } //! \brief Add an aqueous species to the system //! //! \param label label of a component or a secondary species //! \param concentration in moles per mass unit of water void add_aqueous_species(std::string&& label, scalar_t concentration) { concentration_aqueous.emplace(std::move(label), concentration); } //! \brief Add a mineral to the system //! //! \param label label of a mineral at equilibrium or governed by kinetics //! \param concentration in moles per volume unit void add_mineral(const std::string& label, scalar_t concentration) { amount_minerals.insert(std::pair(label, concentration)); } //! \brief Add a mineral to the system //! //! \param label label of a mineral at equilibrium or governed by kinetics //! \param concentration in moles per volume unit void add_mineral(std::string&& label, scalar_t concentration) { amount_minerals.emplace(std::move(label), concentration); } //! \brief Keep a component in the database even if it doesn't exist in the initial composition void keep_component(const std::string& label) { extra_components_to_keep.push_back(label); } //! \brief Set the list of minerals at equilibrium void set_minerals_list(const std::vector& list_minerals_equilibrium) { minerals_to_keep = std::vector(list_minerals_equilibrium); } //! \brief Set the list of minerals at equilibrium void set_minerals_list(std::vector&& list_minerals_equilibrium) { minerals_to_keep = std::vector(std::move(list_minerals_equilibrium)); } }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP diff --git a/src/types.hpp b/src/types.hpp index e5ed588..88da50c 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -1,149 +1,151 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_TYPES_HPP #define SPECMICP_TYPES_HPP #include "macros.hpp" #include #include #include #include "utils/range_iterator.hpp" //! \file src/types.hpp //! \brief types and initialization //! //! This file is expected to be included by all other files. //! It defines the main types used throughout SpecMiCP // Any change to this file should cause a complete rebuild of the project // ========== // Index Type // ========== // First, we need to define the type of an index, before including Eigen //! \namespace specmicp Main namespace for the SpecMiCP solver namespace specmicp { #ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE using index_t = std::ptrdiff_t; //!< Type of an index in a vector #else using index_t = EIGEN_DEFAULT_DENSE_INDEX_TYPE; #endif using uindex_t = typename std::make_unsigned::type; //!< Unsigned version of the index // scalar using scalar_t = double; //!< Type of a scalar //! \brief Return the maximum value for a scalar constexpr scalar_t scalar_max() { return std::numeric_limits::max(); } //! \brief Return the minimum value for scalar constexpr scalar_t scalar_min() { return std::numeric_limits::min(); } //! \brief Return the machine precision for a scalar constexpr scalar_t scalar_epsilon() { return std::numeric_limits::epsilon(); } //! \brief Return infinity constexpr scalar_t infinity() { return std::numeric_limits::infinity(); } } //! \def EIGEN_DEFAULT_DENSE_INDEX_TYPE //! \brief The default type for an index in a dense matrix //! //! This may be redefined to be consistent. //! For more information see the Eigen documentation. // now we can include Eigen #ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE #define EIGEN_DEFAULT_DENSE_INDEX_TYPE specmicp::index_t #endif // FIXME binder1st and binder2nd in eigen... #if (defined __GNUC__) && (__GNUC__ > 3) #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include #if (defined __GNUC__) && (__GNUC__ > 3) #pragma GCC diagnostic warning "-Wdeprecated-declarations" #endif namespace specmicp { // ============ // Matrix stuff // ============ // linear algebra //! A dense vector using Vector = Eigen::Matrix; //! A dense matrix using Matrix = Eigen::Matrix; // Range // ===== //! \brief Range //! //! used to iterate over species/elements/nodes/... using range_t = RangeIterator; // constants // ========= //! \brief Id of an equation that is not an equation constexpr index_t no_equation = -1; //! \brief Id of a non-existant species constexpr index_t no_species = -1; //! \brief Precision used to compute jacobian constexpr scalar_t eps_jacobian = 1e-8; } // namespace specmicp #endif // SPECMICP_TYPES_HPP diff --git a/src/utils/cli/parser.cpp b/src/utils/cli/parser.cpp index 681b8b0..a71f2a3 100644 --- a/src/utils/cli/parser.cpp +++ b/src/utils/cli/parser.cpp @@ -1,992 +1,994 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "parser.hpp" #include #include #include #include #include "../compat.hpp" namespace specmicp { namespace cli { //! \internal //! \brief The different types that a value can solve //! //! To allow a straigthforward use of the union, only a pointer //! to the string is stored, the actual string must be stored elsewhere union SPECMICP_DLL_LOCAL OptionValue { bool boolean; int integer; double floating_number; std::string* str; OptionValue(): str(nullptr) {} }; //! \internal //! \brief Base class for an option struct SPECMICP_DLL_LOCAL BaseOption { BaseOption( ValueType type_value, const std::string& help): is_required(true), value_type(type_value), help_message(help) {} BaseOption( ValueType type_value, const std::string& help, OptionValue default_value ): is_required(false), value_type(type_value), help_message(help), value(default_value) {} bool is_required; bool is_set {false}; ValueType value_type; std::string help_message; OptionValue value; }; //! \internal //! \brief A positional argument struct SPECMICP_DLL_LOCAL PositionalArgument: public BaseOption { PositionalArgument(const std::string& arg_name, ValueType type_value, const std::string& help ): BaseOption(type_value, help), name(arg_name) {} std::string name; }; //! \internal //! \brief An option //! //! An option value is precedented by a flag (starting with '--' pr '-') //! In case of a boolean, only the flag is necessary, the value is implicetely //! true //! struct SPECMICP_DLL_LOCAL SwitchArgument: public BaseOption { SwitchArgument(char the_short_flag, const std::string& the_long_flag, ValueType value_type, OptionValue default_value, const std::string& help_message ): BaseOption(value_type, help_message, default_value), short_flag(the_short_flag), long_flag(the_long_flag) {} SwitchArgument(char the_short_flag, const std::string& the_long_flag, ValueType value_type, const std::string& help_message ): BaseOption(value_type, help_message), short_flag(the_short_flag), long_flag(the_long_flag) {} char short_flag; std::string long_flag; }; //! \internal //! \brief Implementation details for the Command line parser struct SPECMICP_DLL_LOCAL CommandLineParser::CommandLineParserImpl { //! \brief Option : using str_option = std::pair; //! \brief Type of the list of options using list_switch_option = std::vector; //! \brief Type of the list of positional argument using list_pos_argument = std::vector; //! \brief Type of the index in a list of argument using size_type = list_pos_argument::size_type; //! \brief Type of a list of unparsed options using raw_list_option = std::vector; CommandLineParserImpl() {} //! \brief Set the values of the options void set_list_str_option(const raw_list_option& options); //! \brief Check the values of the options/arguments bool check_values(); //! \brief Check the values of the positional arguments bool check_pos_arguments(); //! \brief Check the values of the options bool check_options(); //! \brief Return the index of a short option //! //! Return -1 if the option does not exist int get_short_option_index(char flag) noexcept; //! \brief Return the index of a long option //! //! Return -1 if the option does not exist int get_long_option_index(const std::string& flag) noexcept; //! \brief Return the index of a long option //! //! \throw runtime_error if the option does not exist size_t get_safe_long_option_index(const std::string& flag); //! \brief Return the index of a positional argument //! //! \throw runtime error if the option does not exist size_t get_safe_pos_argument_index(const std::string& name); //! \brief Parse a boolean option activated by its short flag size_t analyse_boolean_short_option(size_t ind, char opts); //! \brief Parse an option activated by its short flag size_t analyse_short_option(size_t ind, const raw_list_option& options, char opts); //! \brief Parse an option activated by its long flag size_t analyse_long_option(size_t ind, const raw_list_option& options, const std::string& opts); //! \brief Parse a positional argument size_t analyse_pos_argument(size_t ind, const std::string& arg_value); //! \brief Return the index of the next free positional argument //! //! Return -1 if no such argument exists int next_free_pos_arg() noexcept; //! \brief Return a value that can be stored inside an option //! //! \tparam T true C++ type of the type //! \param value the value to set //! \param value_type the type of the option template OptionValue set_value(const T& value, ValueType value_type); //! \brief Set the value of the option template void set_option(BaseOption& arg, const T& value); //! \print the help message void print_help_message(); std::string m_name {""}; //!< Name of the program std::string m_help_msg {""}; //! Global help message list_switch_option m_list_opt; //!< List of options list_pos_argument m_list_args; //!< List of positional argument //! \brief Store the values of the string options //! //! This list will store the values of the options std::vector m_option_string_values; }; //! \name simple_predicator //! \brief simple functions to chech the type of a string in argv //! //! \internal //! @{ inline bool is_non_null(const std::string& option) { return (option.length() > 0); } inline bool is_flag(const std::string& option) { return (is_non_null(option) && option[0] == '-'); } inline bool is_value(const std::string& option) { return (is_non_null(option) && option[0] != '-'); } inline bool is_short_flag(const std::string& option) { return (is_flag(option) && option.length() >= 2 and option[1] != '-'); } inline bool is_unique_short_flag(const std::string& option) { return (is_flag(option) && option.length() == 2 and option[1] != '-'); } inline bool is_same_short_flag(const std::string& option, char flag) { return (is_unique_short_flag(option) and option['1'] == flag); } inline bool is_multiple_short_flags(const std::string& option) { return (is_short_flag(option) and option.length() > 2); } inline bool is_long_flag(const std::string& option) { return (is_flag(option) and option.length() > 2 and option[1] == '-'); } inline bool is_same_long_flag(const std::string& option, const std::string& flag) { return (is_long_flag(option) and (option.length()-2) == flag.length() and option.substr(2, option.length()-2) == flag ); } //! @} //! \brief A pair of for an option using option_value_t = std::pair; //! \brief Split a long option in a pair (if = sign in it) option_value_t SPECMICP_DLL_LOCAL split_long_option(const std::string& opts); //! \brief Split a short option std::vector SPECMICP_DLL_LOCAL split_short_options(const std::string& opts); // Definition of main functions CommandLineParser::CommandLineParser(): m_impl(make_unique()) { } CommandLineParser::~CommandLineParser() {} // Getter / Setter // ============== // /!\ templated code : needs to be in that order to // avoid instanciation of a specialization before we define it // CommandLineParser::get_option // ----------------------------- template <> auto CommandLineParser::get_option( const std::string& long_flag ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_long_option_index(long_flag); auto& opt = m_impl->m_list_opt[ind]; if (opt.value_type != ValueType::boolean) { throw std::runtime_error("Not the right type ! Expected boolean."); } return (opt.value.boolean); } template <> auto CommandLineParser::get_option( const std::string& long_flag ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_long_option_index(long_flag); auto& opt = m_impl->m_list_opt[ind]; if (opt.value_type != ValueType::integer) { throw std::runtime_error("Not the right type ! Expected integer."); } return (opt.value.integer); } template <> auto CommandLineParser::get_option( const std::string& long_flag ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_long_option_index(long_flag); auto& opt = m_impl->m_list_opt[ind]; if (opt.value_type != ValueType::floating) { throw std::runtime_error("Not the right type ! Expected floating number."); } return (opt.value.floating_number); } template <> auto CommandLineParser::get_option( const std::string& long_flag ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_long_option_index(long_flag); auto& opt = m_impl->m_list_opt[ind]; if (opt.value_type != ValueType::string) { throw std::runtime_error("Not the right type ! Expected string."); } std::string* str_ptr = opt.value.str; if (str_ptr == nullptr) { throw std::runtime_error("Value not set !"); } return *(opt.value.str); } // CommandLineParser.get_pos_argument // ----------------------------------- template <> auto CommandLineParser::get_pos_argument( const std::string& name ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_pos_argument_index(name); auto& opt = m_impl->m_list_args[ind]; if (opt.value_type != ValueType::boolean) { throw std::runtime_error("Not the right type ! Expected boolean."); } return (opt.value.boolean); } template <> auto CommandLineParser::get_pos_argument( const std::string& name ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_pos_argument_index(name); auto& opt = m_impl->m_list_args[ind]; if (opt.value_type != ValueType::integer) { throw std::runtime_error("Not the right type ! Expected integer."); } return (opt.value.integer); } template <> auto CommandLineParser::get_pos_argument( const std::string& name ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_pos_argument_index(name); auto& opt = m_impl->m_list_args[ind]; if (opt.value_type != ValueType::floating) { throw std::runtime_error("Not the right type ! Expected floating number."); } return (opt.value.floating_number); } template <> auto CommandLineParser::get_pos_argument( const std::string& name ) -> typename TrueValueType::type { size_t ind = m_impl->get_safe_pos_argument_index(name); auto& opt = m_impl->m_list_args[ind]; if (opt.value_type != ValueType::string) { throw std::runtime_error("Not the right type ! Expected string."); } std::string* str_ptr = opt.value.str; if (str_ptr == nullptr) { throw std::runtime_error("Value not set !"); } return *(opt.value.str); } template T get_value(const OptionValue& u_value, ValueType value_type) { T value; switch (value_type) { case ValueType::boolean: value = T(u_value.boolean); break; case ValueType::integer: value = T(u_value.integer); break; case ValueType::floating: value = T(u_value.floating_number); break; case ValueType::string: value = T(*u_value.str); break; } return value; } template OptionValue CommandLineParser::CommandLineParserImpl::set_value( const T& value, ValueType value_type ) { OptionValue u_value; switch (value_type) { case ValueType::boolean: u_value.boolean = bool(value); break; case ValueType::integer: u_value.integer = int(value); break; case ValueType::floating: u_value.floating_number = double(value); break; case ValueType::string: m_option_string_values.emplace_back(std::to_string(value)); u_value.str = &m_option_string_values.back(); break; } return u_value; } template <> OptionValue CommandLineParser::CommandLineParserImpl::set_value( const std::string& value, ValueType value_type ) { OptionValue u_value; switch (value_type) { case ValueType::boolean: if (value == "True" or value == "true" or value == "ON" or value == "on") u_value.boolean = true; else u_value.boolean = false; break; case ValueType::integer: u_value.integer = std::stoi(value); break; case ValueType::floating: u_value.floating_number = std::stod(value); break; case ValueType::string: m_option_string_values.emplace_back(value); u_value.str = &m_option_string_values.back(); break; } return u_value; } template void CommandLineParser::CommandLineParserImpl::set_option( BaseOption& opt, const T& value ) { opt.value = set_value(value, opt.value_type); opt.is_set = true; } // Add options and positional arguments // ==================================== void CommandLineParser::add_option( char short_flag, const std::string& long_flag, ValueType value_type, const std::string& help_message ) { m_impl->m_list_opt.emplace_back( short_flag, long_flag, value_type, help_message); } void CommandLineParser::add_option( char short_flag, const std::string& long_flag, int default_value, const std::string& help_message ) { m_impl->m_list_opt.emplace_back( short_flag, long_flag, ValueType::integer, m_impl->set_value(default_value, ValueType::integer), help_message); } void CommandLineParser::add_option( char short_flag, const std::string& long_flag, double default_value, const std::string& help_message ) { m_impl->m_list_opt.emplace_back( short_flag, long_flag, ValueType::floating, m_impl->set_value(default_value, ValueType::floating), help_message ); } void CommandLineParser::add_option( char short_flag, const std::string& long_flag, bool default_value, const std::string& help_message ) { m_impl->m_list_opt.emplace_back( short_flag, long_flag, ValueType::boolean, m_impl->set_value(default_value, ValueType::boolean), help_message ); } void CommandLineParser::add_option( char short_flag, const std::string& long_flag, const std::string& default_value, const std::string& help_message ) { m_impl->m_list_opt.emplace_back( short_flag, long_flag, ValueType::string, m_impl->set_value(default_value, ValueType::string), help_message ); } void CommandLineParser::add_pos_argument( const std::string& name, ValueType value_type, const std::string& help_message ) { m_impl->m_list_args.emplace_back(name, value_type, help_message); } // Parsing // ======= int CommandLineParser::parse(const std::vector& opts) { add_option('h', "help", false, "Print the help message"); m_impl->set_list_str_option(opts); if (get_option("help")) { // if help we bypass m_impl->print_help_message(); return 1; } else { m_impl->check_values(); return 0; } } int CommandLineParser::parse(int argc, char* argv[]) { // register program name register_program_name(std::string(argv[0])); // first build the list of options std::vector opts; opts.reserve(argc); for (int i=1; im_name = name; } void CommandLineParser::set_help_message(std::string&& help_msg) { m_impl->m_help_msg = help_msg; } void CommandLineParser::CommandLineParserImpl::print_help_message() { std::stringstream msg; msg << "Usage : " << m_name << " [Options]"; for (auto& arg: m_list_args) { msg << " <" + arg.name + ">"; } msg << "\n\n" << m_help_msg; msg << "\n\n Positional arguments :\n-----------------------\n"; for (auto& arg: m_list_args) { msg << "\t" << arg.name << " : " << arg.help_message << "\n"; } msg << "\n Options :\n----------\n"; for (auto& opt: m_list_opt) { if (opt.value_type == ValueType::boolean) { msg << "\t -" << opt.short_flag << ", --" << opt.long_flag << " : " << opt.help_message << "\n"; } else { msg << "\t -" << opt.short_flag << " " << ", --" << opt.long_flag << "=" << " : " << opt.help_message << "\n"; } } std::cout << msg.str(); } // Check values and options // ======================== bool CommandLineParser::CommandLineParserImpl::check_values() { bool retcode = check_pos_arguments(); retcode = retcode and check_options(); return retcode; } bool CommandLineParser::CommandLineParserImpl::check_pos_arguments() { size_t expected = m_list_args.size(); size_t provided = 0; for (auto& arg: m_list_args) { if (arg.is_set) ++provided; } if (provided != expected) { throw std::runtime_error("Missing (a) positional argument(s) :" "expected : " + std::to_string(expected) + " , provided : " + std::to_string(provided) + "." ); } return true; } bool CommandLineParser::CommandLineParserImpl::check_options() { for (auto& opt: m_list_opt) { if ((opt.is_required) and (not opt.is_set)) { throw std::runtime_error("Missing required option : '" + opt.long_flag + "'."); } } return true; } // Parse the list of argument // ========================== void CommandLineParser::CommandLineParserImpl::set_list_str_option( const std::vector& options ) { if (options.size() < 1) return; m_list_opt.reserve(options.size()); for (size_type ind=0; ind(inda)]; set_option(the_option, arg_value); return ++ind; } size_t CommandLineParser::CommandLineParserImpl::analyse_short_option( size_t ind, const raw_list_option& options, char opt) { int option_index = get_short_option_index(opt); if (option_index < 0) { std::string msg = "Error : unknown option '"; msg.push_back(opt); msg += "'."; throw std::runtime_error(msg); } SwitchArgument& the_option = m_list_opt[option_index]; ValueType vtype = the_option.value_type; if (vtype == ValueType::boolean) { set_option(the_option, true); ++ind; } else { if (ind > 0 and ind >= options.size()-1) { throw std::runtime_error( "Missing an argument for option : " + the_option.long_flag ); } std::string next_value = std::string(options[ind+1]); if (not is_value(next_value)) { throw std::runtime_error ("Missing an argument for option : " + the_option.long_flag ); } ind += 2; set_option(the_option, next_value); } return ind; } size_t CommandLineParser::CommandLineParserImpl::analyse_long_option( size_t ind, const raw_list_option& option, const std::string& opt) { option_value_t pair = split_long_option(opt); int option_index = get_long_option_index(pair.first); SwitchArgument& the_option = m_list_opt[option_index]; ValueType vtype = the_option.value_type; if (pair.second.size() > 0) { set_option(the_option, pair.second); ++ind; return ind; } if (vtype == ValueType::boolean) { if (pair.second.size() > 0) set_option(the_option, pair.second); else set_option(the_option, true); ++ind; } else { if (ind >= option.size()) { throw std::runtime_error( "Missing an argument for option : " + the_option.long_flag ); } std::string next_value = std::string(option[ind+1]); if (not is_value(next_value)) { throw std::runtime_error( "Missing an argument for option : " + the_option.long_flag ); } set_option(the_option, next_value); ind = ind+2; } return ind; } size_t CommandLineParser::CommandLineParserImpl::analyse_boolean_short_option( size_t ind, char option) { int option_index = get_short_option_index(option); if (option_index < 0) { std::string msg = "Error : unknown option '"; msg.push_back(option); msg += "'."; throw std::runtime_error(msg); } SwitchArgument& the_option = m_list_opt[option_index]; ValueType vtype = the_option.value_type; if (vtype != ValueType::boolean) { throw std::runtime_error( "Error, expected boolean for option " + the_option.long_flag ); } set_option(the_option, true); return ind; } // Indexes of options // ================== int CommandLineParser::CommandLineParserImpl::get_short_option_index(char flag) noexcept { int ind = -1; for (auto it=m_list_opt.begin();it!=m_list_opt.end();++it) { if (it->short_flag == flag) { ind = it - m_list_opt.begin(); break; } } return ind; } int CommandLineParser::CommandLineParserImpl::get_long_option_index( const std::string& flag) noexcept { int ind = -1; for (auto it=m_list_opt.begin();it!=m_list_opt.end();++it) { if (it->long_flag == flag) { ind = it - m_list_opt.begin(); break; } } return ind; } size_t CommandLineParser::CommandLineParserImpl::get_safe_long_option_index( const std::string& long_flag) { int ind = get_long_option_index(long_flag); if (ind == -1) { throw std::runtime_error("No such option : " + long_flag); } return static_cast(ind); } int CommandLineParser::CommandLineParserImpl::next_free_pos_arg() noexcept { int ind = -1; for (auto it=m_list_args.begin(); it!=m_list_args.end(); ++it) { if (! (*it).is_set) { ind = it - m_list_args.begin(); break; } } return ind; } size_t CommandLineParser::CommandLineParserImpl::get_safe_pos_argument_index( const std::string& name ) { int ind = -1; for (auto it=m_list_args.begin(); it!=m_list_args.end(); ++it) { if (name == (*it).name) { ind = it - m_list_args.begin(); break; } } if (ind < 0) { throw std::runtime_error("Unknow positional argument : " + name); } return static_cast(ind); } // Split options // ============= // remove '-' for short and '--' for long options // also split long options if they are in the form 'opt=value' option_value_t split_long_option(const std::string& opts) { option_value_t val; auto it = std::find(opts.begin(), opts.end(), '='); // no equal sign if (it == opts.end()) { val.first = opts.substr(2, std::string::npos); } // equal sign else { std::string::size_type len_before = it - opts.begin(); val.first = opts.substr(2, len_before-2); if (opts.size() > len_before) { // if there is something after val.second = opts.substr(len_before+1, std::string::npos); } } return val; } std::vector split_short_options(const std::string& opts) { std::vector shortopts; shortopts.reserve(opts.size()-1); for (size_t i=1; i Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_CLI_PARSER_HPP #define SPECMICP_CLI_PARSER_HPP //! \file cli/parser.hpp //! \brief The option parser #include "../../macros.hpp" #include #include #include namespace specmicp { //! \namespace specmicp::cli //! \brief Namespace for the option parsing module namespace cli { //! \enum ValueType //! \brief Type of the options enum class ValueType { boolean, //!< Boolean string, //!< String of characters integer, //!< Integer floating //!< Floating point number }; //! \brief Type writer to obtain the correct underlying type //! //! \tparam val_type type of the option template struct TrueValueType {}; template <> struct TrueValueType { using type=bool; }; template <> struct TrueValueType { using type=std::string; }; template <> struct TrueValueType { using type=int; }; template <> struct TrueValueType { using type=double; }; /*! \brief The command line parser This class is the interface to the command line parser. It works in 3 steps : - Add options - Parse command line arguments - Obtain value for the options */ class SPECMICP_DLL_PUBLIC CommandLineParser { public: CommandLineParser(); ~CommandLineParser(); //! \brief Add a required option of 'value_type' //! //! The option would need to be provided by the user void add_option( char short_flag, const std::string& long_flag, ValueType value_type, const std::string& help_message ); //! \brief Add an optional integer option //! //! 'default_value' will be used as the default value void add_option( char short_flag, const std::string& long_flag, int default_value, const std::string& help_message ); //! \brief Add an optional floating number option //! //! 'default_value' will be used as the default value void add_option( char short_flag, const std::string& long_flag, double default_value, const std::string& help_message ); //! \brief Add an optional boolean option //! //! 'default_value' will be used as the default value void add_option( char short_flag, const std::string& long_flag, bool default_value, const std::string& help_message ); //! \brief Add an optional string option //! //! 'default_value' will be used as the default value void add_option( char short_flag, const std::string& long_flag, const std::string& default_value, const std::string& help_message ); //! \brief Add a positional argument void add_pos_argument( const std::string& name, ValueType value_type, const std::string& help_message ); //! \brief Register the name of the program void register_program_name(std::string&& name); //! \brief Set the help message of the program void set_help_message(std::string&& help_msg); //! \brief Parse the options int parse(const std::vector& opts); //! \brief Parse the options provided in standard format int parse(int argc, char* argv[]); //! \brief Return the value of an option //! //! \tparam val_type type of the option //! \param long_flag long flag used for the option template auto get_option(const std::string& long_flag) -> typename TrueValueType::type; //! \brief Return the value of a positional argument //! //! \tparam val_type type of the argument //! \param name name of the argument template auto get_pos_argument(const std::string& name) -> typename TrueValueType::type; private: struct SPECMICP_DLL_LOCAL CommandLineParserImpl; //! \brief Implementation details std::unique_ptr m_impl; }; // The following macros define the only template specialization // allowed for the get_option and get_pos_argument values #define spc_def_cli_get_option(x) \ template <> \ auto CommandLineParser::get_option( \ const std::string& long_flag \ ) -> typename TrueValueType::type; spc_def_cli_get_option(ValueType::boolean) spc_def_cli_get_option(ValueType::floating) spc_def_cli_get_option(ValueType::integer) spc_def_cli_get_option(ValueType::string) #undef spc_def_get_option #define spc_def_cli_get_pos_argument(x) \ template <> \ auto CommandLineParser::get_pos_argument( \ const std::string& long_flag \ ) -> typename TrueValueType::type; spc_def_cli_get_pos_argument(ValueType::boolean) spc_def_cli_get_pos_argument(ValueType::floating) spc_def_cli_get_pos_argument(ValueType::integer) spc_def_cli_get_pos_argument(ValueType::string) #undef spc_def_get_pos_argument } //end namespace cli } //end namespace specmicp #endif // SPECMICP_CLI_PARSER_HPP diff --git a/src/utils/compat.hpp b/src/utils/compat.hpp index b9dea74..3c415b0 100644 --- a/src/utils/compat.hpp +++ b/src/utils/compat.hpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_COMPAT_HPP #define SPECMICP_UTILS_COMPAT_HPP #include //! \file compat.hpp //! \brief Compatibility/portability between C++ version namespace specmicp { //! \brief Build a unique_ptr //! if using c++14 use the version in the standard library #if (__cplusplus == 201103L) template std::unique_ptr inline make_unique(Ts&&... params) { return std::unique_ptr(new T(std::forward(params)...)); } #elif (__cplusplus >= 201402L) template std::unique_ptr inline make_unique(Ts&&... params) { return std::make_unique(std::forward(params)...); } #endif } //end namespace specmicp #endif // SPECMICP_UTILS_COMPAT_HPP diff --git a/src/utils/dateandtime.cpp b/src/utils/dateandtime.cpp index 89e6aa3..b80d9c6 100644 --- a/src/utils/dateandtime.cpp +++ b/src/utils/dateandtime.cpp @@ -1,50 +1,83 @@ +/* ============================================================================= + + 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 "dateandtime.hpp" #include namespace specmicp { namespace dateandtime { std::string to_text(std::time_t& time_point) { struct std::tm* timeinfo; char buffer[80]; timeinfo = std::localtime(&time_point); std::strftime(buffer, 80, "%F - %T", timeinfo); return std::string(buffer); } std::string to_text_localized(std::time_t& time_point) { struct std::tm* timeinfo; char buffer[80]; timeinfo = std::localtime(&time_point); std::strftime(buffer, 80, "%x - %X", timeinfo); return std::string(buffer); } std::string now_localized() { std::time_t rawtime; std::time(&rawtime); return to_text_localized(rawtime); } std::string now() { std::time_t rawtime; std::time(&rawtime); return to_text(rawtime); } } //end namespace dateandtime } //end namespace specmicp diff --git a/src/utils/dateandtime.hpp b/src/utils/dateandtime.hpp index 6a83585..1b61e52 100644 --- a/src/utils/dateandtime.hpp +++ b/src/utils/dateandtime.hpp @@ -1,65 +1,67 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_DATEANDTIME_HPP #define SPECMICP_UTILS_DATEANDTIME_HPP //! \file dateandtime.hpp //! \brief Date and time tools #include "../types.hpp" #include #include namespace specmicp { //! \namespace specmicp::dateandtime //! \brief Date and time utilities namespace dateandtime { //! \brief Return a textual representation of time_point std::string SPECMICP_DLL_PUBLIC to_text(std::time_t& time_point); //! \brief Return a localized textual representation of time point std::string SPECMICP_DLL_PUBLIC to_text_localized(std::time_t& time_point); //! \brief Return a textual representation of the current date and time std::string SPECMICP_DLL_PUBLIC now(); //! \brief Return a localized textual representation of the current date and time //! Locali std::string SPECMICP_DLL_PUBLIC now_localized(); } //end namespace dateandtime } //end namespace specmicp #endif // SPECMICP_UTILS_DATEANDTIME_HPP diff --git a/src/utils/io/csv_formatter.cpp b/src/utils/io/csv_formatter.cpp index 051128a..bd75be7 100644 --- a/src/utils/io/csv_formatter.cpp +++ b/src/utils/io/csv_formatter.cpp @@ -1,99 +1,101 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "csv_formatter.hpp" #include "../dateandtime.hpp" #include "format.hpp" #include namespace specmicp { namespace io { OutFile::OutFile(const std::string& filepath): m_stream(new std::ofstream(filepath)) { if (m_stream->fail()) { throw std::runtime_error("Cannot open the file : '"+filepath+"'."); } } void OutFile::open(const std::string& filepath) { if (m_stream == nullptr) { m_stream.reset(new std::ofstream(filepath)); } else { if (m_stream->is_open()) close(); m_stream->open(filepath); } } void OutFile::close() { if (m_stream == nullptr) { return; } if (m_stream->is_open()) m_stream->flush(); m_stream->close(); } void CSVFile::insert_comment_line(const std::string& msg) { comment(); space(); _get() << msg; eol(); } //! \brief insert a comment line with the date void CSVFile::insert_comment_date() { insert_comment_line(dateandtime::now()); } void CSVFile::insert_comment_unit( const std::string& variable_name, const std::string& unit) { comment(); space(); _get() << variable_name << " unit : " << unit; eol(); } CSVFile::CSVFile(const std::string& filepath): OutFile(filepath) {} } //end namespace io } //end namespace specmicp diff --git a/src/utils/io/csv_formatter.hpp b/src/utils/io/csv_formatter.hpp index 8105a94..a9d41d7 100644 --- a/src/utils/io/csv_formatter.hpp +++ b/src/utils/io/csv_formatter.hpp @@ -1,159 +1,161 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_CSV_FORMATTER #define SPECMICP_IO_CSV_FORMATTER #include "../../types.hpp" #include #include #include #include #include "format.hpp" namespace specmicp { namespace io { //! \brief A output file //! //! This is a wrapper around a std::ofstream //! //! The wrapper exists to make the formatting easier class SPECMICP_DLL_PUBLIC OutFile { public: OutFile() {} //! \brief Open a file to write OutFile(const std::string& filepath); //! \brief Close the file ~OutFile() { close(); } // This is needed for GCC OutFile(OutFile&& other) { m_stream.swap(other.m_stream); } //! \brief open a file void open(const std::string& filepath); //! \brief Stream operator std::ofstream& operator<< (const std::string& value) { _get() << value; return _get(); } //! \brief Stream operator std::ofstream& operator<< (scalar_t value) { _get() << value; return _get(); } //! \brief Stream operator std::ofstream& operator<< (index_t value) { _get() << value; return _get(); } //! \brief Close a line and flush the stream void endl() { _get() << std::endl; } //! \brief Flush the stream void flush() { m_stream->flush(); } //! \brief close the stream void close(); //! \brief Return true if a file is open bool is_open() { if (m_stream == nullptr) return false; return m_stream->is_open(); } protected: std::ofstream& _get() {return (*m_stream);} std::unique_ptr m_stream {nullptr}; }; //! \brief A CSV file class SPECMICP_DLL_PUBLIC CSVFile: public OutFile { public: CSVFile() {} CSVFile(const std::string& filepath); //! \brief insert a comment line void insert_comment_line(const std::string& msg); //! \brief insert a comment line with the date void insert_comment_date(); //! \brief insert a comment line with unit information void insert_comment_unit(const std::string& variable_name, const std::string& unit); //! \brief Write an end of line void eol() { _get() << "\n"; } //! \brief Write the space sequence void space() { _get() << " "; } //! \brief Write the separator sequence void separator() { _get() << get_format().get_csv_separator(); } //! \brief Write the comment sequence void comment() { _get() << get_format().get_csv_comment(); } }; } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_CSV_FORMATTER diff --git a/src/utils/io/format.cpp b/src/utils/io/format.cpp index a6c78eb..53dfd87 100644 --- a/src/utils/io/format.cpp +++ b/src/utils/io/format.cpp @@ -1,134 +1,136 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "format.hpp" #include namespace specmicp { namespace io { struct FormatDataContainer { int yaml_indent {2}; int yaml_scalar_precision {6}; int equation_precision {4}; std::string csv_comment {"#"}; std::string csv_separator {"\t"}; }; FormatInformation& FormatInformation::get_format() { static FormatInformation format_info; return format_info; } FormatInformation::FormatInformation() { m_data = new FormatDataContainer; } FormatInformation::~FormatInformation() { delete m_data; } int FormatInformation::get_yaml_scalar_precision() const { return m_data->yaml_scalar_precision; } void FormatInformation::set_yaml_scalar_precision(int n) { specmicp_assert(n > 0); m_data->yaml_scalar_precision = n; } int FormatInformation::get_yaml_indent() const { return m_data->yaml_indent; } void FormatInformation::set_yaml_indent(int n) { specmicp_assert(n > 0); m_data->yaml_indent = n; } int FormatInformation::get_stoichiometric_coefficient_precision() const { return m_data->equation_precision; } void FormatInformation::set_stoichiometric_coefficient_precision(int n) { specmicp_assert(n > 0); m_data->equation_precision = n; } void FormatInformation::format_stoichiometric_coefficient(std::ostream& out, scalar_t coeff) const { format_scalar(&out, coeff, get_stoichiometric_coefficient_precision()); } std::ostream* FormatInformation::format_scalar(std::ostream* out, scalar_t coeff, int precision) const { out->precision(precision); (*out) << coeff; return out; } std::string FormatInformation::get_csv_separator() { return m_data->csv_separator; } void FormatInformation::set_csv_separator(const std::string& sep) { m_data->csv_separator = sep; } std::string FormatInformation::get_csv_comment() { return m_data->csv_comment; } void FormatInformation::set_csv_comment(const std::string& comment_trigger) { m_data->csv_comment = comment_trigger; } } //end namespace io } //end namespace specmicp diff --git a/src/utils/io/format.hpp b/src/utils/io/format.hpp index 4c91ee3..02a024f 100644 --- a/src/utils/io/format.hpp +++ b/src/utils/io/format.hpp @@ -1,109 +1,111 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_IO_FORMAT_HPP #define SPECMICP_UTILS_IO_FORMAT_HPP #include "../../types.hpp" #include namespace specmicp { namespace io { struct FormatDataContainer; //! \brief Information on how to format output //! //! This is a singleton class, //! it should be obtained through the get_format static method class FormatInformation { public: //! \brief Return the format information static FormatInformation& get_format(); //! \brief Return the precision for a scalar in a YAML output int get_yaml_scalar_precision() const; //! \brief Set the precision for a scalar in a YAML output void set_yaml_scalar_precision(int n); //! \brief Return the number of space to use in the indentation of a YAML output int get_yaml_indent() const; //! \brief Set the number of space to use as indentation in a YAML output void set_yaml_indent(int n); //! \brief Return the precision for a stoichiometric coefficient precision int get_stoichiometric_coefficient_precision() const; //! \brief Set the precision for a stoichiometric coefficient precision void set_stoichiometric_coefficient_precision(int n); //! \brief Format a stoichiometric coefficient void format_stoichiometric_coefficient(std::ostream& out, scalar_t coeff) const; //! \brief Format a scalar to the given precision std::ostream* format_scalar(std::ostream* out, scalar_t coeff, int precision) const; //! \brief Return the CSV separator std::string get_csv_separator(); //! \brief Set the CSV separator void set_csv_separator(const std::string& sep); template std::basic_ostream& csv_separator(std::basic_ostream& out) { out << get_csv_separator(); return out; } //! \brief Return the CSV comment trigger std::string get_csv_comment(); //! \brief Set the CSV comment trigger void set_csv_comment(const std::string& comment_trigger); private: FormatInformation(); ~FormatInformation(); FormatInformation(const FormatInformation&) = delete; const FormatInformation &operator=(const FormatInformation&) = delete; FormatDataContainer* m_data; }; inline FormatInformation& get_format() { return FormatInformation::get_format(); } } //end namespace io } //end namespace specmicp #endif // SPECMICP_UTILS_IO_FORMAT_HPP diff --git a/src/utils/io/hdf5_eigen.hpp b/src/utils/io/hdf5_eigen.hpp index cb0da67..aaa4a45 100644 --- a/src/utils/io/hdf5_eigen.hpp +++ b/src/utils/io/hdf5_eigen.hpp @@ -1,67 +1,69 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_HDF5_EIGEN_HPP #define SPECMICP_IO_HDF5_EIGEN_HPP //! \file io/hdf5_eigen.hpp //! \brief Save Eigen matrix to hdf5 format #include "../../types.hpp" namespace H5 { class DataSet; } //end namespace H5 namespace specmicp { namespace io { class HDF5File; //! \brief Save a Eigen matrix as 'name' into 'section' in the HDF5 file 'file' template std::unique_ptr save_eigen_matrix( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& matrix ); } //end namespace io } //end namespace specmicp #include "hdf5_eigen.inl" #endif // SPECMICP_IO_HDF5_EIGEN_HPP diff --git a/src/utils/io/hdf5_eigen.inl b/src/utils/io/hdf5_eigen.inl index fb9ed87..5a559a3 100644 --- a/src/utils/io/hdf5_eigen.inl +++ b/src/utils/io/hdf5_eigen.inl @@ -1,327 +1,329 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "hdf5_eigen.hpp" // for syntax coloring only //! \file hdf5_eigen.inl //! \brief implementation of saving a eigen array into hdf5 file #include "specmicp_hdf5.hpp" #include #include namespace specmicp { namespace io { namespace internal { //! \brief Implementation of how to save an Eigen matrix in HDF5 format //! //! \internal template class SPECMICP_DLL_LOCAL EigenMatrixHDF5Saver { public: EigenMatrixHDF5Saver(const Eigen::DenseBase& matrix); std::unique_ptr save( HDF5File& file, const std::string& name, const std::string& section ); private: //! \brief Algorithms for a column-major matrix struct ColumnDispatcher { static std::unique_ptr save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ); }; //! \brief Algorithms for a row-major matrix struct RowDispatcher { static std::unique_ptr save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ); }; //! \brief Algorithms for a column vector struct VectorDispatcher { static std::unique_ptr save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ); }; // Reference to the matrix const Eigen::DenseBase& m_matrix; }; } //end namespace internal // implementation template std::unique_ptr save_eigen_matrix(HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& matrix ) { internal::EigenMatrixHDF5Saver saver(matrix); return saver.save(file, name, section); } // ======================== // // Implementation // // ======================== namespace internal { template EigenMatrixHDF5Saver::EigenMatrixHDF5Saver( const Eigen::DenseBase& matrix): m_matrix(matrix) { } // HDF5 type // ======== // Return a HDF5 type from the type of the matrix //! \brief Return the HDF5 DataType from a type template struct DataType; template <> struct DataType { static inline H5::PredType get() { return H5::PredType::NATIVE_DOUBLE; } }; template <> struct DataType { static inline H5::PredType get() { return H5::PredType::NATIVE_FLOAT; } }; template <> struct DataType { static inline H5::PredType get() { return H5::PredType::NATIVE_INT; } }; template <> struct DataType { static inline H5::PredType get() { return H5::PredType::NATIVE_LONG; } }; //! \brief Return a HDF5 type from the type of the matrix template H5::PredType get_datatype() { return DataType::Scalar>::get(); } // Save functions // =============== template std::unique_ptr EigenMatrixHDF5Saver::save( HDF5File& file, const std::string& name, const std::string& section ) { // this awful looking line just check the compile-time information of the // matrix and call the correct algorithm (*Dispatcher::save()) // if vector return std::conditional::ColsAtCompileTime == 1, // then VectorDispatcher, // else if row major matrix typename std::conditional::IsRowMajor, // then RowDispatcher, // else (colum major matrix) ColumnDispatcher >::type >::type::save(file, name, section, m_matrix); } template std::unique_ptr EigenMatrixHDF5Saver::ColumnDispatcher::save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ) { H5::DSetCreatPropList plist; H5::PredType scalar_type = get_datatype(); // assume column major for now auto rows = static_cast(m_matrix.rows()); auto cols = static_cast(m_matrix.cols()); auto stride = static_cast(m_matrix.outerStride()); // should be rows for a column major assert(stride == rows); // file space // read a col hsize_t fdim[] = {rows, cols}; H5::DataSpace fspace(2, fdim); hsize_t fstride[] = {1, cols}; hsize_t fcount[] = {1, 1}; hsize_t fblock[] = {1, cols}; // matrix space // write a col hsize_t mdim[] = {cols, stride}; H5::DataSpace mspace(2, mdim); hsize_t mstride[] = {stride, 1}; hsize_t mcount[] = {1, 1}; hsize_t mblock[] = {cols, 1}; // where to write std::unique_ptr dataset = file.create_dataset( name, section, scalar_type, fspace, plist); // column-major to row-major transformation for (hsize_t row=0; rowwrite(m_matrix.derived().data(), scalar_type, mspace, fspace); } return dataset; } template std::unique_ptr EigenMatrixHDF5Saver::RowDispatcher::save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ) { H5::DSetCreatPropList plist; H5::PredType scalar_type = get_datatype(); // assume column major for now auto rows = static_cast(m_matrix.rows()); auto cols = static_cast(m_matrix.cols()); // file space // read a col hsize_t fdim[] = {rows, cols}; H5::DataSpace fspace(2, fdim); // where to write std::unique_ptr dataset = file.create_dataset( name, section, scalar_type, fspace, plist); dataset->write(m_matrix.derived().data(), scalar_type, fspace); return dataset; } template std::unique_ptr EigenMatrixHDF5Saver::VectorDispatcher::save( HDF5File& file, const std::string& name, const std::string& section, const Eigen::DenseBase& m_matrix ) { H5::DSetCreatPropList plist; H5::PredType scalar_type = get_datatype(); // assume column major for now auto rows = static_cast(m_matrix.rows()); // file space // read a col hsize_t fdim[] = {rows}; H5::DataSpace fspace(1, fdim); // where to write std::unique_ptr dataset = file.create_dataset( name, section, scalar_type, fspace, plist); dataset->write(m_matrix.derived().data(), scalar_type, fspace); return dataset; } } //end namespace internal } //end namespace io } //end namespace specmicp diff --git a/src/utils/io/specmicp_hdf5.cpp b/src/utils/io/specmicp_hdf5.cpp index 74db91c..d2ebd4c 100644 --- a/src/utils/io/specmicp_hdf5.cpp +++ b/src/utils/io/specmicp_hdf5.cpp @@ -1,146 +1,148 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "specmicp_hdf5.hpp" #include #include "../compat.hpp" namespace specmicp { namespace io { HDF5File::HDF5File(const std::string& filename, HDF5_OpenMode mode) { open(filename, mode); } HDF5File::~HDF5File() { close(); } bool HDF5File::open( const std::string& filename, HDF5_OpenMode mode ) { if (m_file != nullptr) m_file->close(); unsigned int flag = H5F_ACC_DEFAULT; switch (mode) { case HDF5_OpenMode::CreateTruncate: flag = H5F_ACC_TRUNC; break; case HDF5_OpenMode::CreateFailIfExist: flag = H5F_ACC_EXCL; break; case HDF5_OpenMode::OpenReadOnly: flag = H5F_ACC_RDONLY; break; case HDF5_OpenMode::OpenReadWrite: flag = H5F_ACC_RDWR; break; } m_file = make_unique(filename, flag); return is_open(); } bool HDF5File::is_open() { return (m_file != nullptr); } void HDF5File::close() { if (is_open()) { m_file->close(); m_file.reset(nullptr); } } std::unique_ptr HDF5File::create_dataset( const std::string& name, const H5::DataType& type, const H5::DataSpace& data_space, const H5::DSetCreatPropList& list ) { return make_unique( m_file->createDataSet(name, type, data_space, list)); } std::unique_ptr HDF5File::create_dataset( const std::string& name, const std::string& section, const H5::DataType& type, const H5::DataSpace& data_space, const H5::DSetCreatPropList& list ) { return create_dataset(complete_name(name, section), type, data_space, list); } std::unique_ptr HDF5File::create_group( const std::string& name ) { return make_unique( m_file->createGroup(name) ); } std::string HDF5File::complete_name( const std::string& name, const std::string& section ) { std::string comp = section; if (comp[comp.size()-1] != '/') { comp.reserve(comp.size()+1+name.size()); comp += "/"+name; } else { comp += name; } return comp; } } //end namespace io } //end namespace specmicp diff --git a/src/utils/io/specmicp_hdf5.hpp b/src/utils/io/specmicp_hdf5.hpp index e39dfeb..0fdacdc 100644 --- a/src/utils/io/specmicp_hdf5.hpp +++ b/src/utils/io/specmicp_hdf5.hpp @@ -1,126 +1,128 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTIL_SPECMICPHDF5_HPP #define SPECMICP_UTIL_SPECMICPHDF5_HPP #include "../../macros.hpp" #include // forward declaration namespace H5 { class H5File; class DataSet; class DataSpace; class PredType; class DataType; class DSetCreatPropList; class Group; } //end namespace H5 namespace specmicp { namespace io { //! \brief Mode to open/create a file enum class HDF5_OpenMode { CreateTruncate, //!< Create a file, truncate if it exists CreateFailIfExist, //!< Create a file, fail if it exists OpenReadOnly, //!< Open a file, read only mode OpenReadWrite //!< Open a file, read write mode }; //! \brief A HDF5 file //! //! To be subclassed class SPECMICP_DLL_PUBLIC HDF5File { public: HDF5File(); HDF5File(const std::string& filename, HDF5_OpenMode mode); ~HDF5File(); //! \brief Open a file //! //! \param filename Name of the file to open //! \param mode Opening mode //! \return True if the file was successfully open //! bool open(const std::string& filename, HDF5_OpenMode mode); //! \brief Close the file void close(); //! \brief Return true if the file handle is open bool is_open(); //! \brief Create a dataset in the root ("/") std::unique_ptr create_dataset( const std::string& name, const H5::DataType& type, const H5::DataSpace& data_space, const H5::DSetCreatPropList& list ); //! \brief Create a dataset in 'section' std::unique_ptr create_dataset( const std::string& name, const std::string& section, const H5::DataType& type, const H5::DataSpace& data_space, const H5::DSetCreatPropList& list ); //! \brief Create a new group std::unique_ptr create_group( const std::string& name ); //! \brief Give the complete the name of a dataset std::string complete_name( const std::string& name, const std::string& section ); protected: std::unique_ptr m_file {nullptr}; private: HDF5File(const HDF5File& other) = delete; HDF5File& operator= (const HDF5File& other) = delete; }; } //end namespace io } //end namespace specmicp #endif // SPECMICP_UTIL_SPECMICPHDF5_HPP diff --git a/src/utils/io/yaml.cpp b/src/utils/io/yaml.cpp index ca70cdf..2dc9df4 100644 --- a/src/utils/io/yaml.cpp +++ b/src/utils/io/yaml.cpp @@ -1,169 +1,171 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "yaml.hpp" #include #include #include #include "format.hpp" namespace specmicp { namespace io { void configure_yaml_emitter(YAML::Emitter& emitter) { FormatInformation& format = FormatInformation::get_format(); emitter.SetDoublePrecision(format.get_yaml_scalar_precision()); emitter.SetFloatPrecision(format.get_yaml_scalar_precision()); emitter.SetIndent(format.get_yaml_indent()); } YAML::Node parse_yaml(std::istream& input) { return YAML::Load(input); } YAML::Node parse_yaml_file(const std::string &filepath) { return YAML::LoadFile(filepath); } YAML::Node parse_yaml_string(const std::string& config_string) { return YAML::Load(config_string); } //! \brief Save a YAML emitter into a file void save_yaml(const std::string& filename, YAML::Emitter& yaml_tree) { if (not yaml_tree.good()) { throw std::runtime_error("Invalid YAML stream : " + yaml_tree.GetLastError()); } std::ofstream ofile(filename); if (not ofile.is_open()) { throw std::runtime_error("Could not open file : '"+filename+"'."); } ofile << yaml_tree.c_str(); ofile.close(); } void check_mandatory_yaml_node(const YAML::Node& node, const std::string& child, const std::string& section) { if (not node[child]) throw std::invalid_argument("Node '"+child+"' is required in section '"+section+"'."); } template <> scalar_t get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section) { scalar_t value; try { value = node[attribute].as(); } catch (YAML::BadConversion) { if (node[attribute].as() == "-inf") { value = - INFINITY; } else { throw std::invalid_argument( "Error while converting attribute '"+attribute+"' in section '"+section+"' to scalar"); } } return value; } template <> index_t get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section) { index_t value; try { value = node[attribute].as(); } catch (YAML::BadConversion) { throw std::invalid_argument( "Error while converting attribute '"+attribute+"' in section '"+section+"' to integer"); } return value; } template <> std::string get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section) { std::string value; try { value = node[attribute].as(); } catch (YAML::BadConversion) { throw std::invalid_argument("Error while converting attribute '"+attribute+"' in section '"+section+"' to string"); } return value; } template <> bool get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section) { if (not node[attribute]) throw std::invalid_argument("Attribute '"+attribute+"' is required in section '"+section+"'."); bool value; try { value = node[attribute].as(); } catch (YAML::BadConversion) { try { value = get_yaml_attribute(node, attribute, section); } catch (YAML::BadConversion) { throw std::invalid_argument("Error while converting attribute '"+attribute+"' in section '"+section+"' to boolean"); } } return value; } } //end namespace io } //end namespace spe diff --git a/src/utils/io/yaml.hpp b/src/utils/io/yaml.hpp index cc65a84..f0b380c 100644 --- a/src/utils/io/yaml.hpp +++ b/src/utils/io/yaml.hpp @@ -1,147 +1,149 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_IO_YAML_HPP #define SPECMICP_IO_YAML_HPP #include "../../types.hpp" #include #include #include //! \file utils/io/yaml.hpp //! \brief YAML parsing and emitting namespace specmicp { namespace io { //! \brief Configure the yaml emitter void configure_yaml_emitter(YAML::Emitter& emitter); //! \brief Parse a yaml formatted stream //! //! \param input stream to parse YAML::Node parse_yaml(std::istream& input); //! \brief Parse a yaml formatted file //! //! \param filepath path to the yaml file YAML::Node parse_yaml_file(const std::string& filepath); //! \brief Parse a yaml formatted string //! //! \param config_string string in yaml format YAML::Node parse_yaml_string(const std::string& config_string); //! \brief Save a YAML emitter into a file //! //! \param filepath Path to the file where the YAML tree will be saved //! \param yaml_tree YAML emitter void save_yaml(const std::string& filepath, YAML::Emitter& yaml_tree); //! \brief Check that node[child] exist, if it doesn't throws an exception //! //! \param node Yaml node //! \param child the named attribute to obtain //! \param section the name of the current node void check_mandatory_yaml_node(const YAML::Node& node, const std::string& child, const std::string& section); //! \brief Return node[attribute] //! //! This version do not check if the attribute exists //! //! \tparam T type of the attribute //! \param node Yaml node //! \param attribute the named attribute to obtain //! \param section the name of the current node template T get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section) { T value; try { value = node[attribute].as(); } catch (YAML::BadConversion) { throw std::invalid_argument("Error while reading attribute '"+attribute+"' in section '"+section+"'."); } return value; } // Specialization for scalar template <> scalar_t get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section); // Specialization for integer template <> index_t get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section); // Specialization for string template <> std::string get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section); // Specialization for booleans template <> bool get_yaml_attribute(const YAML::Node& node, const std::string& attribute, const std::string& section); //! \brief Return node[attribute] if it exist else return default_value //! //! \tparam T type of the attribute //! \param node Yaml node //! \param attribute the named attribute to obtain //! \param section the name of the current node //! \param default_value value used if it doesn't exist in the database template T get_yaml_optional(const YAML::Node& node, const std::string& attribute, const std::string& section, T default_value) { if (node[attribute]) return get_yaml_attribute(node, attribute, section); else return default_value; } //! \brief Return node[attribute], if it doesn't exist throws an exception //! //! \tparam T type of the attribute //! \param node Yaml node //! \param attribute the named attribute to obtain //! \param section the name of the current node template T get_yaml_mandatory(const YAML::Node& node, const std::string& attribute, const std::string& section) { if (not node[attribute]) throw std::invalid_argument("Attribute '"+attribute+"' is required in section '"+section+"'."); return get_yaml_attribute(node, attribute, section); } } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_YAML_HPP diff --git a/src/utils/log.cpp b/src/utils/log.cpp index b87183a..9dae0d6 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -1,74 +1,76 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "log.hpp" #include "../macros.hpp" namespace specmicp { namespace logger { // Explicit instanciation template class Log; template <> LogLevel& Log::ReportLevel(){ static LogLevel report_level = Debug; return report_level; } std::ostream*& ErrFile::stream() { static std::ostream* stream = nullptr; return stream; } void ErrFile::output(const std::string &msg) { std::ostream* out = stream(); specmicp_assert(out != nullptr); (*out) << msg << std::endl; out->flush(); } } //end namespace logger void init_logger(std::ostream* out, specmicp::logger::LogLevel level) { logger::ErrFile::stream() = out; stdlog::ReportLevel() = level; } } //end namespace specmicp diff --git a/src/utils/log.hpp b/src/utils/log.hpp index 41b7c61..d90604d 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -1,210 +1,212 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_LOG_HPP #define SPECMICP_UTILS_LOG_HPP #include //! \file log.hpp logger /*! \file utils/log.hpp \brief logger A common logger is shared by all SpecMiCP/ReactMiCP module. The logger contains several level which can be activated (or not) by the user. The user also decides of where the logger output its information. \code{.cpp} // output to std::cerr for Warning and Errors (nmo Debug messages) init_logger(&std::cerr, logger::LogLevel::Warning) // Log an Error ERROR << "Error"; // Log a Warning WARNING << "Warning"; // Log a debug message (no effect); DEBUG << "Debug (disabled message) \endcode This module was inspired by : - http://www.drdobbs.com/cpp/a-lightweight-logger-for-c/240147505 - http://www.drdobbs.com/cpp/logging-in-c/201804215?pgno=1 */ namespace specmicp { //! \namespace specmicp::logger //! \brief The logger used by SpecMiCP/ReactMiCP namespace logger { //! \enum LogLevel the different log level //! //! If changed, the function to_string must also be changed enum LogLevel {Critical, //!< Error that should lead to abortion Error, //!< Error Warning, //!< Warnings Info, //!< May be worth mentionning, not worth listening... Debug, //!< (Relevant) Debugging information Spam //!< How is your life ? ususally contains large debugging information such as the variables vector }; //! \brief Format the log level into a string inline std::string to_string(LogLevel); /*! \brief A log message * * The message is written during the destruction of the Log object. * The stream which contain the message is accessed with the member get(Level) */ template class Log { public: //! Constructor Log() {} //! Destructor - Output the message ~Log(); //! \brief Return the steam so we can write the message //! //! \param level Level of the message std::ostringstream& get(LogLevel level); //! \brief Return the report level static LogLevel& ReportLevel(); protected: std::ostringstream msg; //!< the actual message private: // this are hidden on purpose, no need Log(Log&) = delete; Log& operator=(Log&) = delete; }; //! \brief Standard output Policy to use for logging class ErrFile { public: //! \brief Return a pointer to the stream we want to write in static std::ostream*& stream(); //! \brief Output the message to the stream static void output(const std::string& msg); }; // implementation // -------------- template std::ostringstream& Log::get(LogLevel level) { msg << to_string(level) << " : "; return msg; } template Log::~Log() { outputPolicy::output(msg.str()); } inline std::string to_string(LogLevel level) { static const char* list_level[] = {"CRITICAL", "ERROR", "Warning", "info", "debug", "spam"}; return list_level[static_cast(level)]; } } // end namespace logger //! \brief Standard logger type using stdlog = logger::Log; //! \brief Initialize the logger //! //! \param out the output stream //! \param level the output level void init_logger(std::ostream* out, specmicp::logger::LogLevel level); //! \brief Filter logs to stdlog #define FILTER(level) \ if (level > stdlog::ReportLevel() || logger::ErrFile::stream() == nullptr) ;\ else stdlog().get(level) #define FILTER_NDEBUG \ if (true) ; \ else stdlog().get(logger::Warning) //! \def SPAM //! \brief Output spam-level log to stdlog #ifdef NDEBUG #define SPAM FILTER_NDEBUG #else #define SPAM FILTER(logger::Spam) #endif //! \def DEBUG //! \brief Output debug-level log to stdlog #ifdef NDEBUG #define DEBUG FILTER_NDEBUG #else #define DEBUG FILTER(logger::Debug) #endif //! \def INFO //! \brief Ooutput info-level log to stdlog #ifdef INFO #undef INFO // jsoncpp is also using this, remove compiler warnings #endif #ifdef NDEBUG #define INFO FILTER_NDEBUG #else #undef INFO #define INFO FILTER(logger::Info) #endif //! \def WARNING //! \brief Output warning-level log to stdlog #define WARNING FILTER(logger::Warning) //! \def ERROR //! \brief Output error-level log to stdlog #define ERROR FILTER(logger::Error) //! \def CRITICAL //! \brief Output critical-level log to stdlog #define CRITICAL FILTER(logger::Critical) } // end namespace specmicp #endif // SPECMICP_UTILS_LOG_HPP diff --git a/src/utils/moving_average.cpp b/src/utils/moving_average.cpp index f1d877f..b16e0e3 100644 --- a/src/utils/moving_average.cpp +++ b/src/utils/moving_average.cpp @@ -1,46 +1,48 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "moving_average.hpp" namespace specmicp { namespace utils { scalar_t ExponentialMovingAverage::add_point(scalar_t value) { m_current_value *= (1.0-m_alpha); m_current_value += m_alpha*value; return m_current_value; } } // end namespace utils } // end namespace specmicp diff --git a/src/utils/moving_average.hpp b/src/utils/moving_average.hpp index 57d2054..ade1f47 100644 --- a/src/utils/moving_average.hpp +++ b/src/utils/moving_average.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_MOVINGAVERAGE_HPP #define SPECMICP_UTILS_MOVINGAVERAGE_HPP /*! \file utils/moving_average.hpp \brief Exponential moving average The moving average allows to take a weighted average of the last x points in the data series. It is used in particular in the adaptive timestepping algorithm. \code{.cpp} ExponentialMovingAverage moving_average(0.1, 1.0); for (int i=0; i<10; ++i) { std::cout << "Current value : " << moving_average.add_point(i); } // reset to 1.0 moving_average.reset(1.0); \endcode */ #include "../types.hpp" namespace specmicp { //! \namespace specmicp::utils //! \brief misc and others used in different places namespace utils { //! \brief Exponential moving average //! //! https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average //! //! @param alpha coefficient between 0 and 1 //! @param init initial value of the average class SPECMICP_DLL_PUBLIC ExponentialMovingAverage { public: ExponentialMovingAverage(scalar_t alpha, scalar_t init): m_alpha(alpha), m_current_value(init) { } //! \brief Add a point in the series, return current average value scalar_t add_point(scalar_t value); //! \brief Return the current average value scalar_t current_value() { return m_current_value; } //! \brief Reset the average to 'value' void reset(scalar_t value) { m_current_value = value; } //! \brief Set the average parameter value void set_alpha(scalar_t alpha) {m_alpha = alpha;} private: scalar_t m_alpha; scalar_t m_current_value; }; } // end namespace utils } // end namespace specmicp #endif // SPECMICP_UTILS_MOVINGAVERAGE_HPP diff --git a/src/utils/options_handler.hpp b/src/utils/options_handler.hpp index 837a300..d0695de 100644 --- a/src/utils/options_handler.hpp +++ b/src/utils/options_handler.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_OPTIONSHANDLER_HPP #define SPECMICP_UTILS_OPTIONSHANDLER_HPP /*! \file utils/options_handler.hpp \brief Base class for handling options in a solver Options are contained in a struct. Example : \code{.cpp} struct MyOptions { // define stuff }; class MySolver: public OptionsHandler { // do stuff }; \endcode */ #include namespace specmicp { //! \brief Base class that handles an option struct. //! //! \tparam OptionsClass A structure containing options template class OptionsHandler { public: //! \brief Initialize with the default options OptionsHandler() {} //! \brief Initialise the options struct using the arguments provided //! //! It will call the OptionsClass(args...) constructor template OptionsHandler(Args... args): m_options(args...) {} //! \brief Initialize the options by copying them from the argument OptionsHandler(const OptionsClass& options): m_options(options) {} //! \brief Return a reference to the options OptionsClass& get_options() {return m_options;} //! \brief Return a const reference to the options const OptionsClass& get_options() const {return m_options;} //! \brief Set the options void set_options(const OptionsClass& options) {m_options = options;} //! \brief Swap the options with another set //! //! May be useful for temporary change void swap(OptionsClass& options) {std::swap(m_options, options);} //! \brief Reset to default options void reset_to_default() {m_options = OptionsClass();} private: OptionsClass m_options; //!< The options }; } // end namespace specmicp #endif // SPECMICP_UTILS_OPTIONSHANDLER_HPP diff --git a/src/utils/perfs_handler.hpp b/src/utils/perfs_handler.hpp index 6de6e04..bce96ee 100644 --- a/src/utils/perfs_handler.hpp +++ b/src/utils/perfs_handler.hpp @@ -1,87 +1,89 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_PERFSHANDLER_HPP #define SPECMICP_UTILS_PERFSHANDLER_HPP /*! \file perfs_handler.hpp \brief BaseClass for a class managing performance struct A performance struct containts information such as the number of iterations, the return code and any relevant information provided by a solver. It is used like this : \code{.cpp} struct MyPerf { // define iterations }; class MySolver: public PerformanceHandler { // blah blah }; \endcode */ #include namespace specmicp { //! \brief Handle a performance struct for the algorithms //! //! Like options handler but for the performance template class PerformanceHandler { public: //! \brief Return the performance (read-only) const PerformanceStruct& get_perfs() const {return m_perfs;} //! \brief Reset the performance void reset_perfs() {m_perfs = PerformanceStruct();} //! \brief Return a reference to the performance PerformanceStruct& get_perfs() {return m_perfs;} protected: //! \brief Swap the performance with another void swap(PerformanceStruct& other) {std::swap(m_perfs, other);} private: PerformanceStruct m_perfs; }; } // end namespace specmicp #endif // SPECMICP_UTILS_PERFSHANDLER_HPP diff --git a/src/utils/pimpl_ptr.hpp b/src/utils/pimpl_ptr.hpp index 862350d..17437f3 100644 --- a/src/utils/pimpl_ptr.hpp +++ b/src/utils/pimpl_ptr.hpp @@ -1,106 +1,108 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_PIMPLPTR_HPP #define SPECMICP_UTILS_PIMPLPTR_HPP //! \file utils/pimpl_ptr.hpp //! \brief Pointer to implementation interface with deep const-correctness //! //! The main point of this interface is to forward the constness //! of the operations. #include namespace specmicp { namespace utils { //! \brief Pointer to implementation interface with deep const-correctness //! //! This is a 'unique_ptr' like class to contain a pointer //! but it forwards the constness. template class pimpl_ptr { public: //! \brief Create an empty implementation pimpl_ptr(): m_ptr(nullptr) {} //! \brief Create a new pimpl from a pointer pimpl_ptr(T* pointer): m_ptr(pointer) {} //! \brief Move constructor pimpl_ptr(pimpl_ptr&& other): m_ptr(other.m_ptr) { other.m_ptr = nullptr; } //! \brief No copy constructor pimpl_ptr(const pimpl_ptr& other) = delete; //! \brief No assignement operator pimpl_ptr& operator=(const pimpl_ptr& other) = delete; ~pimpl_ptr() {delete m_ptr;} //! \brief Mutable dereference T& operator* () {return *m_ptr;} //! \brief Const dereference const T& operator* () const {return m_ptr;} //! \brief Mutable call to member T * operator-> () {return m_ptr;} //! \brief Const call to member const T* operator-> () const {return m_ptr;} private: T* m_ptr; }; //! \brief Make a new pimpl ptr template pimpl_ptr make_pimpl(Args&&...args) { return pimpl_ptr(new T(std::forward(args)...)); } } //end namespace utils } //end namespace specmicp #endif // SPECMICP_UTILS_PIMPLPTR_HPP diff --git a/src/utils/plugins/dynamic_library.cpp b/src/utils/plugins/dynamic_library.cpp index ce94aa7..f999443 100644 --- a/src/utils/plugins/dynamic_library.cpp +++ b/src/utils/plugins/dynamic_library.cpp @@ -1,105 +1,107 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "dynamic_library.hpp" #include #include "../compat.hpp" #include "../log.hpp" namespace specmicp { namespace plugins { DynamicLibraryPtr DynamicLibrary::load(const std::string& path, std::string& error) { void* handle = dlopen(path.c_str(), RTLD_LAZY); if (not handle) { error = "Error when loading dynamic library : " + path + ".\n"; const char* str_error = dlerror(); if (str_error != NULL) { error += str_error; } ERROR << error; return nullptr; } return std::unique_ptr(new DynamicLibrary(handle)); } DynamicLibrary::DynamicLibrary(void *handle): m_handle(handle) { } DynamicLibrary::~DynamicLibrary() { if (m_handle) { int ret = dlclose(m_handle); if (ret > 0) { ERROR << dlerror(); } } } void* DynamicLibrary::get_symbol( const std::string& name, std::string& error) { if (not m_handle) { error = "The library is not open !"; return nullptr; } void* symbol = dlsym(m_handle, name.c_str()); const char* str_error = dlerror(); if (str_error != NULL) { error = "Failed to load symbol '" + name + "'\n"; error += str_error; return nullptr; } return symbol; } } //end namespace plugins } //end namespace specmicp diff --git a/src/utils/plugins/dynamic_library.hpp b/src/utils/plugins/dynamic_library.hpp index bb2ed49..50d46e9 100644 --- a/src/utils/plugins/dynamic_library.hpp +++ b/src/utils/plugins/dynamic_library.hpp @@ -1,102 +1,104 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_COMMON_PLUGIN_DYNAMICLIBRARY_HPP #define SPECMICP_COMMON_PLUGIN_DYNAMICLIBRARY_HPP #include #include /*! \file dynamic_library.hpp \brief Dynamic library loader Load the libraries and the symbols within. \warning Only implemented for POSIX platforms \code{.cpp} std::string error_str; auto lib = DynamicLibraryPtr::load(, error_str); if (lib == nullptr) { ERROR << error_str; } void* symbol = lib.get_symbol("func_name", error_str) if (symbol == nullptr) { ERROR << error_str; } \endcode */ namespace specmicp { namespace plugins { class DynamicLibrary; //! \brief Pointer to a dynamic library //! //! All this stuff should be managed in only one place //! //! \internal using DynamicLibraryPtr = std::unique_ptr; //! \brief A dynamic library //! //! Open a dynamic library. It is closed at the destruction of the object. //! //! \internal class DynamicLibrary { public: //! \brief Create a dynamic library static DynamicLibraryPtr load(const std::string& path, std::string& error); ~DynamicLibrary(); //! \brief Return a symbol void* get_symbol(const std::string& name, std::string& error); private: // Cannot be created directly DynamicLibrary(void* handle); // Non copyable DynamicLibrary(const DynamicLibrary& other) = delete; DynamicLibrary& operator=(const DynamicLibrary& other) = delete; void* m_handle; //!< The library handle }; } //end namespace plugins } //end namespace specmicp #endif // SPECMICP_COMMON_PLUGIN_DYNAMICLIBRARY_HPP diff --git a/src/utils/plugins/module_base.cpp b/src/utils/plugins/module_base.cpp index 4fbd6ee..9fd3a3c 100644 --- a/src/utils/plugins/module_base.cpp +++ b/src/utils/plugins/module_base.cpp @@ -1,72 +1,74 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "module_base.hpp" #include "../compat.hpp" namespace specmicp { namespace plugins { struct ModuleBase::ModuleBaseImpl { std::unordered_map m_objects; }; ModuleBase::ModuleBase(): m_impl(make_unique()) { } ModuleBase::~ModuleBase() = default; std::unique_ptr ModuleBase::create_module() { auto module = make_unique(); return module; } bool ModuleBase::register_object( const std::string& name, object_factory_f func ) { m_impl->m_objects.insert({name, func}); return true; } void* ModuleBase::get_object(const std::string& name) { return m_impl->m_objects.at(name)(); } } //end namespace plugins } //end namespace specmicp diff --git a/src/utils/plugins/module_base.hpp b/src/utils/plugins/module_base.hpp index f90b71f..f47184c 100644 --- a/src/utils/plugins/module_base.hpp +++ b/src/utils/plugins/module_base.hpp @@ -1,79 +1,81 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGINS_MODULEBASE_HPP #define SPECMICP_PLUGINS_MODULEBASE_HPP //! \file module_base.hpp //! \brief Base class for a module #include "plugin_types.hpp" #include #include namespace specmicp { namespace plugins { //! \brief A module is a set of objects of the same type //! //! The module class can be subclassed if needed class SPECMICP_DLL_PUBLIC ModuleBase { public: ModuleBase(); ~ModuleBase(); static std::unique_ptr create_module(); //! \brief Return an object of type T template std::unique_ptr get_object(const std::string& name) { return std::unique_ptr(dynamic_cast(get_object(name))); } //! \brief Register an object type virtual bool register_object(const std::string& name, object_factory_f func); //! \brief Return a generic object virtual void* get_object(const std::string& name); private: struct ModuleBaseImpl; std::unique_ptr m_impl; }; } //end namespace plugins } //end namespace specmicp #endif // SPECMICP_PLUGINS_MODULEBASE_HPP diff --git a/src/utils/plugins/plugin_api_version.h b/src/utils/plugins/plugin_api_version.h index e8154f2..db0d710 100644 --- a/src/utils/plugins/plugin_api_version.h +++ b/src/utils/plugins/plugin_api_version.h @@ -1,52 +1,54 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGINS_API_VERSION #define SPECMICP_PLUGINS_API_VERSION //! \file plugin_api_version.h //! \brief Define the version of the API //! //! The version is defined as 3 macros : SPECMICP_API_VERSION_\ //! where \ is one of MAJOR, MINOR or PATCH //! \def SPECMICP_API_VERSION_MAJOR //! \brief Major version of the API #define SPECMICP_API_VERSION_MAJOR 0 //! \def SPECMICP_API_VERSION_MINOR //! \brief Minor version of the API #define SPECMICP_API_VERSION_MINOR 1 //! \def SPECMICP_API_VERSION_PATCH //! \brief Patch version of the API #define SPECMICP_API_VERSION_PATCH 0 #endif // SPECMICP_PLUGINS_API_VERSION diff --git a/src/utils/plugins/plugin_base.cpp b/src/utils/plugins/plugin_base.cpp index c68b670..adf9ffb 100644 --- a/src/utils/plugins/plugin_base.cpp +++ b/src/utils/plugins/plugin_base.cpp @@ -1,50 +1,52 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "plugin_base.hpp" namespace specmicp { namespace plugins { void PluginBase::set_api_version( api_version_t major, api_version_t minor, api_version_t patch) { m_version.v_major = major; m_version.v_minor = minor; m_version.v_patch = patch; } } //end namespace plugins } //end namespace specmicp diff --git a/src/utils/plugins/plugin_base.hpp b/src/utils/plugins/plugin_base.hpp index 5188f64..7391be6 100644 --- a/src/utils/plugins/plugin_base.hpp +++ b/src/utils/plugins/plugin_base.hpp @@ -1,121 +1,123 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGIN_PLUGINBASE_HPP #define SPECMICP_PLUGIN_PLUGINBASE_HPP /*! \file plugin_base.hpp \brief Base class for a plugin Example of how to declare a new plugin : \code{.cpp} // necessary headers #include "utils/plugins/plugin_interface.h" #include "utils/plugins/plugin_base.hpp" #include "utils/plugins/module_base.hpp" // First declare the plugin class ExamplePlugin: public specmicp::plugins::PluginBase { public: ExamplePlugin(): PluginBase() { // set required version set_api_version(0, 1, 0); } ~ExamplePlugin() = default // The destructor can be used to free memory if needed bool initialize(const specmicp::plugins::PluginManagerServices& services) override { // register a new module auto test_module = specmicp::plugins::ModuleBase::create_module(); auto retcode = services.register_module("test_module", std::move(test_module)); if (not retcode) { return false; } // register a new object auto factory = []() {return new TestObject(); }; retcode = services.register_object("test_module", "test_object", factory); if (not retcode) { return false; } return true; } }; // Then we register the plugin SPECMICP_PLUGIN(BasicPlugin); \endcode */ #include "plugin_types.hpp" namespace specmicp { namespace plugins { //! \brief Base class for a plugin class SPECMICP_DLL_PUBLIC PluginBase { public: PluginBase() {} virtual bool initialize(const PluginManagerServices& services) = 0; //! \brief Return the API version used by the plugin PluginAPIVersion get_api_version() { return m_version; } virtual ~PluginBase() = default; protected: //! \brief Set the API version void set_api_version( api_version_t major, api_version_t minor, api_version_t patch); private: //! \brief The API version PluginAPIVersion m_version; }; } //end namespace plugins } //end namespace specmicp #endif // SPECMICP_PLUGIN_PLUGINBASE_HPP diff --git a/src/utils/plugins/plugin_interface.h b/src/utils/plugins/plugin_interface.h index a4e7479..b641c9f 100644 --- a/src/utils/plugins/plugin_interface.h +++ b/src/utils/plugins/plugin_interface.h @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGINS_PLUGININTERFACE_H #define SPECMICP_PLUGINS_PLUGININTERFACE_H /*! \file plugin_interface.h \brief C interface for the plugin system */ #include "../../macros.hpp" //! \def SPECMICP_PLUGIN //! \brief Register a plugin //! //! \param PluginType type of the plugin definition //! //! PluginType must be a subclass of the specmicp::plugins::PluginBase class. #define SPECMICP_PLUGIN(PluginType) \ void* create_plugin() { \ void* plugin = static_cast(new PluginType()); \ return plugin; \ } \ \ extern "C" {\ void* SPC_plugin_init() { \ return create_plugin(); \ } \ } #endif // SPECMICP_PLUGINS_PLUGININTERFACE_H diff --git a/src/utils/plugins/plugin_manager.cpp b/src/utils/plugins/plugin_manager.cpp index a2f93ea..df094b0 100644 --- a/src/utils/plugins/plugin_manager.cpp +++ b/src/utils/plugins/plugin_manager.cpp @@ -1,204 +1,206 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "plugin_manager.hpp" #include #include #include "plugin_api_version.h" #include "module_base.hpp" #include "dynamic_library.hpp" #include "plugin_base.hpp" #include "../compat.hpp" #include "../log.hpp" #include namespace specmicp { namespace plugins { PluginManager& get_plugin_manager() { static PluginManager manager; return manager; } struct PluginManager::PluginManagerImpl { PluginManagerImpl() {}; void set_services(PluginManager* parent); std::vector m_libraries; std::vector> m_plugins; std::unordered_map> m_modules; PluginManagerServices m_services; }; PluginManager::PluginManager(): m_impl(make_unique()) { m_impl->set_services(this); } PluginManager::~PluginManager() = default; ModuleBase* PluginManager::get_module(const std::string& name) { ModuleBase* mod = m_impl->m_modules[name].get(); return mod; } void* PluginManager::get_object( const std::string& module, const std::string& name ) { ModuleBase* mod = get_module(module); if (mod == nullptr) { throw std::runtime_error("No such plugin module : " + module + "."); } return mod->get_object(name); } bool PluginManager::load_plugin(const std::string& filepath) { std::string error; DynamicLibraryPtr lib = DynamicLibrary::load(filepath, error); if (lib == nullptr) { ERROR << "Error while loading shared library :\n" << error; return false; } void* initter = lib->get_symbol("SPC_plugin_init", error); if (initter == nullptr) { ERROR << "Error while loading shared library :\n" << error; return false; } void* plugin = ((void* (*)())(initter))(); if (plugin == nullptr) { ERROR << "Error while loading shared library :\n" << "Failed to initialize plugin."; return false; } auto plugin_base_ptr = std::unique_ptr(static_cast(plugin)); auto retcode = check_version(plugin_base_ptr->get_api_version()); if (not retcode) {return false;} retcode = plugin_base_ptr->initialize(m_impl->m_services); if (not retcode) {return false;} // only register if no problem was detected m_impl->m_libraries.emplace_back(nullptr); auto ind = m_impl->m_libraries.size()-1; m_impl->m_libraries[ind].swap(lib); m_impl->m_plugins.emplace_back(plugin_base_ptr.release()); return true; } bool PluginManager::check_version(const PluginAPIVersion& api_version) { if ( (api_version.v_major == 0) and (api_version.v_minor == 0) and (api_version.v_patch == 0) ) { ERROR << "API version of the plugin was not initialized"; return false; } return true; } bool PluginManager::register_object( const std::string& module, const std::string& name, object_factory_f func ) { auto* mod = get_module(module); return mod->register_object(name, func); } bool PluginManager::register_module( const std::string& module_name, std::unique_ptr&& module ) { m_impl->m_modules.emplace(module_name, std::unique_ptr(module.release())); return true; } void PluginManager::PluginManagerImpl::set_services(PluginManager* parent) { m_services.api_version = PluginAPIVersion( SPECMICP_API_VERSION_MAJOR, SPECMICP_API_VERSION_MINOR, SPECMICP_API_VERSION_PATCH ); m_services.register_module = [parent]( const std::string& module_name, std::unique_ptr&& module_ptr ) { return parent->register_module( module_name, std::forward>(module_ptr) ); }; m_services.register_object = [parent](const std::string& module, const std::string& object_name, object_factory_f factory) { return parent->register_object(module, object_name, factory); }; } } //end namespace plugins } //end namespace specmicp diff --git a/src/utils/plugins/plugin_manager.hpp b/src/utils/plugins/plugin_manager.hpp index fe216ec..91523b3 100644 --- a/src/utils/plugins/plugin_manager.hpp +++ b/src/utils/plugins/plugin_manager.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGINS_PLUGINMANAGER_HPP #define SPECMICP_PLUGINS_PLUGINMANAGER_HPP //! \file plugins/plugin_manager.hpp //! \brief The plugin manager //! //! Use the method specmicp::plugins::get_plugin_manager() //! to obtain the instance of the plugin manager. #include "module_base.hpp" #include namespace specmicp { namespace plugins { //! \brief The plugin manager //! //! It registers the plugins and return their objects //! //! \sa get_plugin_manager class SPECMICP_DLL_PUBLIC PluginManager { public: PluginManager(); ~PluginManager(); //! \brief Return a module ModuleBase* get_module(const std::string& name); //! \brief Return an object void* get_object(const std::string& module, const std::string& name); //! \brief Return a type object template std::unique_ptr get_object(const std::string& module, const std::string& name) { return std::unique_ptr(static_cast(get_object(module, name))); } //! \brief Load a plugin //! //! \param filepath path to the shared library //! \return True if the loading was successful bool load_plugin(const std::string& filepath); //! \brief Register an object bool register_object( const std::string& module, const std::string& name, object_factory_f func ); //! \brief Register a module bool register_module( const std::string& module_name, std::unique_ptr&& module ); bool check_version(const PluginAPIVersion& api_version); private: struct SPECMICP_DLL_LOCAL PluginManagerImpl; std::unique_ptr m_impl; }; //! \brief Return the plugin manager PluginManager& get_plugin_manager(); } //end namespace plugins } //end namespace specmicp #endif // SPECMICP_PLUGINS_PLUGINMANAGER_HPP diff --git a/src/utils/plugins/plugin_types.hpp b/src/utils/plugins/plugin_types.hpp index 1ecaa32..5c2f511 100644 --- a/src/utils/plugins/plugin_types.hpp +++ b/src/utils/plugins/plugin_types.hpp @@ -1,101 +1,103 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_PLUGINS_PLUGINTYPES_HPP #define SPECMICP_PLUGINS_PLUGINTYPES_HPP //! \file plugins/plugin_types.hpp //! \brief Common types and struct used in the plugins system #include "../../macros.hpp" #include #include #include namespace specmicp { //! \namespace specmicp::plugins //! \brief Plugin framework namespace plugins { //! \brief type used in the version using api_version_t = unsigned int; //! \brief Version of the plugin API struct SPECMICP_DLL_PUBLIC PluginAPIVersion { api_version_t v_major {0}; api_version_t v_minor {0}; api_version_t v_patch {0}; PluginAPIVersion() {} PluginAPIVersion( api_version_t maj, api_version_t min, api_version_t pat): v_major(maj), v_minor(min), v_patch(pat) {} }; //! \brief Type of an object factory function using object_factory_f = std::function; class ModuleBase; //! \brief Services offered by the PluginManager to a plugin struct SPECMICP_DLL_PUBLIC PluginManagerServices { //! \brief Type of a label using label_t = const std::string&; //! \brief Type of a function to register a module using register_module_f = std::function< bool (label_t, std::unique_ptr&&)>; //! \brief Type of a function to register an object using register_object_f = std::function< bool (label_t, label_t, object_factory_f)>; PluginAPIVersion api_version; //! \brief Function to register a module register_module_f register_module; //! \brief Function to register an object register_object_f register_object; }; } //end namespace plugins } //end namespace specmicp #endif // SPECMICP_PLUGINS_PLUGINTYPES_HPP diff --git a/src/utils/range_iterator.hpp b/src/utils/range_iterator.hpp index 9c0ec55..4cfbd6e 100644 --- a/src/utils/range_iterator.hpp +++ b/src/utils/range_iterator.hpp @@ -1,109 +1,111 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_RANGEITERATOR_HPP #define SPECMICP_UTILS_RANGEITERATOR_HPP // /!\ this file is included in types.hpp /*! \file range_iterator.hpp \brief Iterator over a range */ namespace specmicp { //! \namespace specmicp::interator_impl //! \brief Implementation of the iterator //! \internal namespace iterator_impl { template class IntegralIterator; template class ConstIntegralIterator; } //end namespace iterator_impl //! \brief An iterator over a range //! //! \tparam T an integral type template class RangeIterator { public: using iterator = iterator_impl::IntegralIterator; using const_iterator = const iterator_impl::ConstIntegralIterator; //! \brief Construct a range iterator RangeIterator(T start, T end): m_start(start), m_end(end) {} //! \brief Construct a range iterator RangeIterator(T end): m_start(0), m_end(end) {} //! \brief Construct a range iterator from two iterators RangeIterator(const iterator& start, const iterator& end): m_start(*start), m_end(*end) {} //! \brief Construct a range iterator from an iterator RangeIterator(const iterator& end): m_start(0), m_end(*end) {} iterator begin() const; iterator end() const; const_iterator cbegin() const; const_iterator cend() const; private: T m_start; T m_end; }; } // end namespace specmicp // implementation #include "range_iterator.inl" #endif // SPECMICP_UTILS_RANGEITERATOR_HPP diff --git a/src/utils/range_iterator.inl b/src/utils/range_iterator.inl index 6be07d8..88863da 100644 --- a/src/utils/range_iterator.inl +++ b/src/utils/range_iterator.inl @@ -1,147 +1,149 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #include "range_iterator.hpp" // syntaxic coloration only... namespace specmicp { namespace iterator_impl { //! \brief Iterator over a range of integers //! //! \internal template class IntegralBaseIterator { public: using value_type = T; using reference = T&; explicit IntegralBaseIterator(T value): m_value(value) {} bool operator< (const IntegralBaseIterator& other) { return (m_value < other.m_value); } bool operator<= (const IntegralBaseIterator& other) { return (m_value <= other.m_value); } bool operator> (const IntegralBaseIterator& other) { return (m_value > other.m_value); } bool operator>= (const IntegralBaseIterator& other) { return (m_value >= other.m_value); } bool operator== (const IntegralBaseIterator& other) { return (m_value == other.m_value); } bool operator!= (const IntegralBaseIterator& other) { return (m_value != other.m_value); } value_type operator++ (int) { T tmp = m_value; ++m_value; return tmp; } protected: value_type m_value; }; template class IntegralIterator: public IntegralBaseIterator { public: explicit IntegralIterator(T value): IntegralBaseIterator(value) {} T& operator* () { return IntegralBaseIterator::m_value; } IntegralIterator& operator++ () { ++(IntegralBaseIterator::m_value); return *this; } }; template class ConstIntegralIterator: public IntegralBaseIterator { public: explicit ConstIntegralIterator(T value): IntegralBaseIterator(value) {} T operator* () const { return IntegralBaseIterator::m_value; } ConstIntegralIterator& operator++ () { ++(IntegralBaseIterator::m_value); return *this; } }; } //end namespace iterator_impl template typename RangeIterator::iterator RangeIterator::begin() const { return RangeIterator::iterator(m_start); } template typename RangeIterator::iterator RangeIterator::end() const { return RangeIterator::iterator(m_end); } template typename RangeIterator::const_iterator RangeIterator::cbegin() const { return RangeIterator::iterator(m_start); } template typename RangeIterator::const_iterator RangeIterator::cend() const { return RangeIterator::iterator(m_end); } } // end namespace specmicp diff --git a/src/utils/scope_guard.hpp b/src/utils/scope_guard.hpp index 0ee6e68..80b3bcf 100644 --- a/src/utils/scope_guard.hpp +++ b/src/utils/scope_guard.hpp @@ -1,102 +1,104 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_SCOPEGUARD_HPP #define SPECMICP_UTILS_SCOPEGUARD_HPP //! \file utils/scope_guard.hpp //! \brief Scope guard tools #include namespace specmicp { namespace utils { //! \brief Base class for a scope guard class ScopeGuardBase { public: //! \param on_failure True if the scope guard is active on failure ScopeGuardBase(bool on_failure=true): m_active(on_failure) {} //! \brief Return true if the scope guard is active bool is_active() {return m_active;} //! \brief Release the scope guard void release() {m_active = false;} //! \brief Engage the scope guard void engage() {m_active = true;} private: bool m_active; }; //! \brief Scope guard with a function //! //! If the scope guard is still engaged, //! it will call the function template class ScopeGuardFunc: public ScopeGuardBase { public: //! \param func A function that will be called if the guard is active //! \param on_failure True if the scope guard is active on failure ScopeGuardFunc(F&& func, bool on_failure=true): ScopeGuardBase(on_failure), m_func(func) {} ~ScopeGuardFunc() { if (is_active()) m_func(); } private: F m_func; }; //! \brief Create a scope guard taking a function //! //! \param func A function that will be called if the guard is active //! \param on_failure True if the scope guard is active on failure template ScopeGuardFunc make_scope_guard(F&& func, bool on_failure=true) { return ScopeGuardFunc(std::forward(func), on_failure); } } //end namespace utils } //end namespace specmicp #endif // SPECMICP_UTILS_SCOPEGUARD_HPP diff --git a/src/utils/sparse_solvers/sparse_bicgstab.hpp b/src/utils/sparse_solvers/sparse_bicgstab.hpp index 2a9046e..0316ce7 100644 --- a/src/utils/sparse_solvers/sparse_bicgstab.hpp +++ b/src/utils/sparse_solvers/sparse_bicgstab.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP #define SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP /*! \file sparse_solvers/sparse_bicgstab.hpp \brief Wrapper around the Eigen BiCGStab solver */ #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { //! \brief Wrapper around the Eigen BiCGStab solver template class SparseSolverBiCGSTAB: public SparseSolverBase { using SolverT = Eigen::BiCGSTAB>; public: // has an effect void analyse_pattern(MatrixT& jacobian) override { m_solver.analyzePattern(jacobian); } SparseSolverReturnCode decompose(MatrixT& jacobian) override { m_solver.compute(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) override { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) override { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP diff --git a/src/utils/sparse_solvers/sparse_gmres.hpp b/src/utils/sparse_solvers/sparse_gmres.hpp index d62162d..8645aa5 100644 --- a/src/utils/sparse_solvers/sparse_gmres.hpp +++ b/src/utils/sparse_solvers/sparse_gmres.hpp @@ -1,112 +1,114 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP #define SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP /*! \file sparse_solvers/sparse_gmres.hpp \brief Wrapper around the Eigen/Unsupported GMRES solver The Eigen unsupported module are of course needed. If they are detected, the preprocessor constant EIGEN_UNSUPPORTED_FOUND is set. */ #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" // needed for eigen 3.2.2 #include // from eigen unsupported #include namespace specmicp { namespace sparse_solvers { //! \brief Wrapper around the Eigen/Unsupported GMRES solver template class SparseSolverGMRES: public SparseSolverBase { using SolverT = Eigen::GMRES> ; public: // no effect for the GMRES solver void analyse_pattern(MatrixT& jacobian) override { } SparseSolverReturnCode decompose(MatrixT& jacobian) override { m_solver.compute(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) override { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) override { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP diff --git a/src/utils/sparse_solvers/sparse_lu.hpp b/src/utils/sparse_solvers/sparse_lu.hpp index 5394682..fe8ea77 100644 --- a/src/utils/sparse_solvers/sparse_lu.hpp +++ b/src/utils/sparse_solvers/sparse_lu.hpp @@ -1,106 +1,108 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSELU_HPP #define SPECMICP_SPARSESOLVERS_SPARSELU_HPP /*! \file sparse_solvers/sparse_lu.hpp \brief Wrapper around the Eigen SparseLU algorithm */ #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { //! \brief Wrapper aroung the Eigen SparseLU algorithm template class SparseSolverLU: public SparseSolverBase { using SolverT = Eigen::SparseLU>; public: // Has an effect for the sparse LU algorithm void analyse_pattern(MatrixT& jacobian) override { m_solver.analyzePattern(jacobian); } SparseSolverReturnCode decompose(MatrixT& jacobian) override { m_solver.factorize(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) override { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) override { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSELU_HPP diff --git a/src/utils/sparse_solvers/sparse_qr.hpp b/src/utils/sparse_solvers/sparse_qr.hpp index f214266..70d7ad6 100644 --- a/src/utils/sparse_solvers/sparse_qr.hpp +++ b/src/utils/sparse_solvers/sparse_qr.hpp @@ -1,107 +1,109 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSEQR_HPP #define SPECMICP_SPARSESOLVERS_SPARSEQR_HPP /*! \file sparse_solvers/sparse_qr.hpp \brief Wrapper around the Eigen SparseQR algorithm */ #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { //! \brief Wrapper aroung the Eigen SparseQR algorithm template class SparseSolverQR: public SparseSolverBase { using SolverT = Eigen::SparseQR>; public: // Has an effect for the QR algorithm void analyse_pattern(MatrixT& jacobian) override { m_solver.analyzePattern(jacobian); } SparseSolverReturnCode decompose(MatrixT& jacobian) override { m_solver.factorize(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) override { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) override { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEQR_HPP diff --git a/src/utils/sparse_solvers/sparse_solver.hpp b/src/utils/sparse_solvers/sparse_solver.hpp index 9541058..25c80d4 100644 --- a/src/utils/sparse_solvers/sparse_solver.hpp +++ b/src/utils/sparse_solvers/sparse_solver.hpp @@ -1,122 +1,124 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP #define SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP /*! \file sparse_solvers/sparse_solver.hpp \brief Wrapper around Eigen sparse solvers The wrapper allow to choose the solver at runtime \code{.cpp} auto solver = get_sparse_solver(SparseSolver::SparseLU); auto retcode = solver.decompose(Jacobian); if (retcode != Success) { throw std::runtime_error("Error during the decomposition"); } retcode = solver.solver(residuals, solution); if (retcode != Success) { throw std::runtime_error("Error : can't solve the system"); } \endcode */ #include "../../types.hpp" #include #include "../compat.hpp" // The main solvers available #include "sparse_qr.hpp" #include "sparse_lu.hpp" #include "sparse_bicgstab.hpp" // only include gmres if it is available // from the Eigen library unsuported modules #ifdef EIGEN_UNSUPPORTED_FOUND #include "sparse_gmres.hpp" #endif namespace specmicp { //! \namespace specmicp::sparse_solvers //! \brief Wrappers around the Eigen sparse solver namespace sparse_solvers { //! \brief A pointer to a sparse solver //! //! \tparam MatrixT type of the matrix //! \tparam DerivedR type of the residuals //! \tparam DerivedS type of the solution template using SparseSolverPtr = std::unique_ptr< SparseSolverBase>; //! \brief Return a sparse solver of type 'solver_type' //! //! \tparam MatrixT type of the matrix //! \tparam DerivedR type of the residuals //! \tparam DerivedS type of the solution template SparseSolverPtr get_sparse_solver(SparseSolver solver_type) { SparseSolverPtr sparse_solver; switch (solver_type) { case SparseSolver::SparseQR: sparse_solver = make_unique>(); break; #ifdef EIGEN_UNSUPPORTED_FOUND case SparseSolver::GMRES: sparse_solver = make_unique>(); break; #endif case SparseSolver::SparseLU: sparse_solver = make_unique>(); break; case SparseSolver::BiCGSTAB: sparse_solver = make_unique>(); break; } return sparse_solver; } } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP diff --git a/src/utils/sparse_solvers/sparse_solver_base.hpp b/src/utils/sparse_solvers/sparse_solver_base.hpp index c142086..eebaeec 100644 --- a/src/utils/sparse_solvers/sparse_solver_base.hpp +++ b/src/utils/sparse_solvers/sparse_solver_base.hpp @@ -1,80 +1,82 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP #define SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP /*! \file sparse_solvers/sparse_solver_base.hpp \brief Interface of a sparse solver */ namespace specmicp { namespace sparse_solvers { enum class SparseSolverReturnCode; //! \brief Abstract Base Class for a sparse solver //! //! \tparam MatrixT type of the matrix //! \tparam DerivedR type of the residuals //! \tparam DerivedS type of the solution template class SparseSolverBase { public: virtual ~SparseSolverBase() {} //! \brief Analyse the pattern of a matrix to speed up further decomposition //! //! May not have an effect in all sparse solver, //! but have a non negligible effect on some virtual void analyse_pattern(MatrixT& jacobian) = 0; //! \brief Decompose the jacboian virtual SparseSolverReturnCode decompose(MatrixT& jacobian) = 0; //! \brief Solve the problem virtual SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) = 0; //! \brief Solve the problem with scaling factors for the residuals virtual SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) = 0; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP diff --git a/src/utils/sparse_solvers/sparse_solver_structs.hpp b/src/utils/sparse_solvers/sparse_solver_structs.hpp index 5381f77..7dadd95 100644 --- a/src/utils/sparse_solvers/sparse_solver_structs.hpp +++ b/src/utils/sparse_solvers/sparse_solver_structs.hpp @@ -1,74 +1,76 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_SPARSESOLVERSTRUCT_HPP #define SPECMICP_UTILS_SPARSESOLVERSTRUCT_HPP /*! \file sparse_solvers/sparse_solver_structs.hpp \brief Structs use in the sparse solvers wrappers */ namespace specmicp { namespace sparse_solvers { //! \brief Available sparse solvers enum class SparseSolver { SparseLU //!< Eigen Sparse LU solver , SparseQR //!< Eigen Sparse QR solver , BiCGSTAB //!< Eigen BiCGSTAB solver #ifdef EIGEN_UNSUPPORTED_FOUND // only include GMRES if supported , GMRES //!< Eigen unsupported GMRES solver #endif }; //! \brief Return code of the sparse solver enum class SparseSolverReturnCode { FailedDecomposition =-2, //!< Decomposition has failed FailedSystemSolving =-1, //!< Solving linear system has failed Success = 0 //!< Success }; } // end namespace sparse_solvers // move the SparseSolver enum in the main namespace using SparseSolver = sparse_solvers::SparseSolver; } // end namespace specmicp #endif //SPECMICP_DFPMSOLVER_SPARSESOLVERSTRUCT_HPP diff --git a/src/utils/timer.cpp b/src/utils/timer.cpp index 765cca6..f5ab4da 100644 --- a/src/utils/timer.cpp +++ b/src/utils/timer.cpp @@ -1,61 +1,63 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #include "timer.hpp" #include namespace specmicp { char* Timer::get_ctime_start() const { std::time_t start_time = get_start(); return std::ctime(&start_time); } char* Timer::get_ctime_stop() const { std::time_t stop_time = get_stop(); return std::ctime(&stop_time); } scalar_t Timer::elapsed_time() const { std::chrono::duration elapsed_seconds = m_end-m_start; return elapsed_seconds.count(); } std::time_t Timer::get_start() const { return std::chrono::system_clock::to_time_t(m_start); } std::time_t Timer::get_stop() const { return std::chrono::system_clock::to_time_t(m_end); } } //end namespace specmicp diff --git a/src/utils/timer.hpp b/src/utils/timer.hpp index a35456f..4d6f2b3 100644 --- a/src/utils/timer.hpp +++ b/src/utils/timer.hpp @@ -1,98 +1,100 @@ -/*------------------------------------------------------------------------------- +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_TIMER_HPP #define SPECMICP_UTILS_TIMER_HPP /*! \file utils/timer.hpp \brief Timer and related tools Implements a simple timer using std::chrono. \code{.cpp} Timer timer; // do stuff; timer.stop(); std::cout << "Elapsed time : " << timer.elapsed_time() << "\n"; \endcode */ #include "../types.hpp" #include namespace specmicp { //! \brief A simple timer class SPECMICP_DLL_PUBLIC Timer { public: //! \brief Initialize the timer and start it Timer() { start(); } //! \brief Start the timer void start() { m_start = std::chrono::system_clock::now(); } //! \brief Stop the timer void stop() { m_end = std::chrono::system_clock::now(); } //! \brief Return the time of the starting point std::time_t get_start() const; //! \brief Return the time of the ending point std::time_t get_stop() const; //! \brief Return a textual representation (ctime) of the starting point char* get_ctime_start() const; //! \brief Return a textual representation (ctime) of the ending point char* get_ctime_stop() const; //! \brief Return the elapsed time (in seconds) scalar_t elapsed_time() const; private: using time_point = std::chrono::time_point; time_point m_start; time_point m_end; }; } // end namespace specmicp #endif // SPECMICP_UTILS_TIMER_HPP diff --git a/src/utils/tmp.cpp b/src/utils/tmp.cpp index 939ebae..dae3e5f 100644 --- a/src/utils/tmp.cpp +++ b/src/utils/tmp.cpp @@ -1 +1,34 @@ +/* ============================================================================= + + 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 "vector_checker.hpp" diff --git a/src/utils/value_checker.hpp b/src/utils/value_checker.hpp index ece674d..15f25f0 100644 --- a/src/utils/value_checker.hpp +++ b/src/utils/value_checker.hpp @@ -1,358 +1,360 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_VALUECHECKER_HPP #define SPECMICP_UTILS_VALUECHECKER_HPP /*! \file value_checker.hpp \brief Framework to check and validate vectors The user uses and/or define checker and predicates to validates the vector. This is a header-only module using template metaprogramming. Each checker and predicates are defined as types wich allows us to compose them easily. Example : The following example check that : - every value in the vector is finite and in the range [0.0, 1.0] - at least one value is non-zero \code{.cpp} specmicp_upper_bound_predicate(LessOrEqualThanOne, 1.0); bool check_vector(const Vector& vector) { using predicate_all = PredicateAnd< PredicateAnd, LessOrEqualThanOne >; using predicate_one = IsNonZero; using checker = Composer< TrueForAll, TrueForAtLeastOne >; auto value = checker::check(vector); if (value >= IsValidVector::error) { ERROR << "Vector is incorrecct"; return false; } return true } \endcode */ #include "../types.hpp" #include "functional" namespace specmicp { //! \brief namespace dedicated to functions and types used to validate vectors namespace value_checker { //! \brief Return code Of the checker enum class IsValidVector { good, //!< Nothing to report warning, //!< Something smells fishy error, //!< Error, please correct critical //!< Mayde, Mayde, abort the computation }; //! \brief Return the maximum error level between two error levels constexpr IsValidVector max_error_level(IsValidVector err1, IsValidVector err2) { return (err1>err2)?err1:err2; } /*! \brief Base class for a checker \tparam Derived derived class Derived class must implement the static check_impl method. \code{.cpp} struct DerivedValueChecker: public ValueChecker { static IsValidVector check_impl(const Vector& vector) { // check vector return IsValidVector::good; } }; \endcode */ template struct ValueChecker { //! \brief Check the vector static IsValidVector check(const Vector& vector) { return Derived::check_impl(vector); } }; //! \brief Compose two checkers together //! //! The composer will run the two checks and return the maximum error. //! If Checker1 return a critical error, checker2 will not be run. template struct Composer: public ValueChecker> { static IsValidVector check_impl(const Vector& vector) { auto val1 = Checker1::check(vector); if (val1 < IsValidVector::critical) { const auto val2 = Checker2::check(vector); val1 = max_error_level(val1, val2); }; return val1; } }; //! \brief Check if Predicate is true for every value in the vector template struct TrueForAll: public ValueChecker> { static IsValidVector check_impl(const Vector& vector) { bool flag = false; for (index_t ind=0; ind struct TrueForAtLeastOne: public ValueChecker> { static IsValidVector check_impl(const Vector& vector) { bool flag = false; for (index_t ind=0; ind; auto retcode = validator::check(vector); \endcode */ template struct NormChecker: public ValueChecker> { static IsValidVector check_impl(const Vector& vector) { const scalar_t norm = vector.lpNorm

(); if (not Predicate::run(norm)) return error_level; return IsValidVector::good; } }; /*! \brief Base class for a Predicate The derived class must implement the `bool function_impl(const scalar_t& value)' method. Example \code{cpp} struct BiggerThan2: public Predicate { static bool functor_impl(const scalar_t& value) { return (value > 2); } }; \endcode Macros and common composer are defined to ease the process of creating predicates. \sa PredicateNot, PredicateAnd, PredicateOr, PredicateXOr, specmicp_create_value_predicate, specmicp_lower_bound_predicate, specmicp_strict_lower_bound_predicate. specmicp_upper_bound_predicate, specmicp_strict_upper_bound_predicate */ template struct Predicate { static bool run(const scalar_t& value) { return Derived::run_impl(value); } }; //! \brief Negate a predicate template struct PredicateNot: public Predicate> { static bool run_impl(const scalar_t& value) { return (not PredicateT::run(value)); } }; /*! \brief And operation on two predicates Check that the two predicates are true \code{.cpp} using and_predicate = PredicateAnd; using checker = TrueForAll; auto retcode = checker::check(vector); \endcode */ template struct PredicateAnd: public Predicate> { static bool run_impl(const scalar_t& value) { return (Predicate1::run(value) and Predicate2::run(value)); } }; //! \brief Or operation on two predicates //! //! Performs the or operation on two predicates template struct PredicateOr: public Predicate> { static bool run_impl(const scalar_t& value) { return (Predicate1::run(value) or Predicate2::run(value)); } }; //! \brief XOr operation on two predicates //! //! Performs the exclusive or operation on two predicates template struct PredicateXOr: public Predicate> { static bool run_impl(const scalar_t& value) { return (Predicate1::run(value) != Predicate2::run(value)); } }; } //end namespace value_checker } //end namespace specmicp /*! \def specmicp_create_value_predicate \brief Create a predicate with name 'name' The expression must test 'value' Example : \code{.cpp} specmicp_create_value_predicate(LowerThan5, (value < 5)); // { using checker = TrueForAll; auto return_code = checker::check(vector); } \endcode */ #define specmicp_create_value_predicate(name, expression) \ struct name: public specmicp::value_checker::Predicate { \ static bool run_impl(const scalar_t& value) { \ return (expression); \ } \ } //! \def specmicp_lower_bound_predicate //! \brief Create a predicate that check the lower bound #define specmicp_lower_bound_predicate(name, bound) \ specmicp_create_value_predicate(name, (value >= bound)) //! \def specmicp_strict_lower_bound_predicate //! \brief Create a predicate that check the lower bound #define specmicp_strict_lower_bound_predicate(name, bound) \ specmicp_create_value_predicate(name, (value > bound)) //! \def specmicp_upper_bound_predicate //! \brief Create a predicate that check the upper bound #define specmicp_upper_bound_predicate(name, bound) \ specmicp_create_value_predicate(name, (value <= bound)) //! \def specmicp_strict_upper_bound_predicate //! \brief Create a predicate that check the upper bound #define specmicp_strict_upper_bound_predicate(name, bound) \ specmicp_create_value_predicate(name, (value < bound)) namespace specmicp { namespace value_checker { //! \class IsNonNegative //! \brief Test if a value is non negative specmicp_lower_bound_predicate(IsNonNegative, (0.0)); //! \class IsNonZero //! \brief Test if a value is non zero specmicp_create_value_predicate(IsNonZero, (value != 0)); //! \class IsFinite //! \brief Test if a value is finite specmicp_create_value_predicate(IsFinite, (std::isfinite(value))); } //end namespace value_checker } //end namespace specmicp #endif // SPECMICP_UTILS_VALUECHECKER_HPP diff --git a/src/utils/vector_checker.hpp b/src/utils/vector_checker.hpp index b54a10d..c8e76fc 100644 --- a/src/utils/vector_checker.hpp +++ b/src/utils/vector_checker.hpp @@ -1,403 +1,405 @@ -/*------------------------------------------------------------------------------ +/* ============================================================================= + + Copyright (c) 2014 - 2016 + F. Georget Princeton University + All rights reserved. -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. + 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. + 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. + 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 +* 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. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------------------*/ +============================================================================= */ #ifndef SPECMICP_UTILS_VECTORCHECKER_HPP #define SPECMICP_UTILS_VECTORCHECKER_HPP #include "../types.hpp" #include #include #include namespace specmicp { //! \namespace specmicp::vector_checker //! \brief Check values in a vector namespace vector_checker { //! \brief Type for the template using VectorT = Eigen::template Matrix; //! \brief The base class of an expression template struct BaseBoolExpr { //! \brief Return the Derived class const Derived& self() const {return static_cast(*this);} //! \brief Evaluate the expression bool operator() () const {return self().out_impl();} //! \brief Evalute the expression when assigned to a boolean operator bool() const {return self().out_impl();} }; //! \brief Evaluate a logical AND expression template class AndBoolExpr: public BaseBoolExpr> { using Child0 = Derived0; using Child1 = Derived1; public: AndBoolExpr(const Child0& child_0, const Child1& child_1): m_child_0(child_0), m_child_1(child_1) {} AndBoolExpr( BaseBoolExpr&& child_0, BaseBoolExpr&& child_1 ): m_child_0(std::move(child_0.self())), m_child_1(std::move(child_1.self())) {} bool out_impl() const { if (m_child_0()) return m_child_1(); return false; } private: Child0 m_child_0; Child1 m_child_1; }; //! \brief Evaluate a logical OR Expression template class OrBoolExpr: public BaseBoolExpr> { using Child0 = Derived0; using Child1 = Derived1; public: OrBoolExpr(const Child0& child_0, const Child1& child_1): m_child_0(child_0), m_child_1(child_1) {} OrBoolExpr( BaseBoolExpr&& child_0, BaseBoolExpr&& child_1 ): m_child_0(std::move(child_0.self())), m_child_1(std::move(child_1.self())) {} bool out_impl() const { if (m_child_0()) return true; return m_child_1(); } private: Child0 m_child_0; Child1 m_child_1; }; //! \brief True if the underlying condition is true for all element //! //! Evaluate a condition for all element in a vector, //! check if the condition formed by 'element BinaryOpTag rhs' is true //! for all element template class AllExpr: public BaseBoolExpr> { public: AllExpr(const VectorT& vector, ScalarT rhs): m_vector(vector), m_rhs(rhs) {} bool out_impl() const { bool is_true = true; for (typename VectorT::Index id=0; id< m_vector.rows(); ++id) { if (not op(m_vector(id), m_rhs)) { is_true = false; break; } } return is_true; } private: BinaryOpTag op; const VectorT& m_vector; ScalarT m_rhs; }; //! \brief Wrapper around a vector for creating a 'All' condition template class All { public: All(const VectorT& vector): m_vector(vector) {} const VectorT& operator() () const {return m_vector;} private: const VectorT& m_vector; }; //! \brief Create a 'All' wrapper from a vector template All all(const VectorT& vector) { return All(vector); } //! \brief True if the underlying condition is true for at least one element //! //! Evaluate the condition 'element BinaryOpTag rhs' to see if it is true for //! at least one element template class AnyExpr: public BaseBoolExpr> { public: AnyExpr(const VectorT& vector, ScalarT rhs): m_vector(vector), m_rhs(rhs) {} bool out_impl() const { bool is_true = false; for (typename VectorT::Index id=0; id< m_vector.rows(); ++id) { if (op(m_vector(id), m_rhs)) { is_true = true; break; } } return is_true; } private: BinaryOpTag op; const VectorT& m_vector; ScalarT m_rhs; }; //! \brief Wrapper around a vector to create a 'Any' condition template class Any { public: Any(const VectorT& vector): m_vector(vector) {} const VectorT& operator() () const {return m_vector;} private: const VectorT& m_vector; }; //! \brief create a 'Any' wrapper template Any any(const VectorT& vector) { return Any(vector); } //! \brief True if all elements of a vector are bounded //! //! Bounds must be finite template class BoundedExpr: public BaseBoolExpr> { public: BoundedExpr( const VectorT& vector, ScalarT lower_bound, ScalarT upper_bound ): m_vector(vector), m_lower(lower_bound), m_upper(upper_bound) {} bool out_impl() const { bool is_true = true; for (typename VectorT::Index id=0; id< m_vector.rows(); ++id) { const ScalarT& value = m_vector(id); if (not (std::isfinite(value) && value >= m_lower && value <= m_upper) ) { is_true = false; break; } } return is_true; } private: const VectorT& m_vector; ScalarT m_lower; ScalarT m_upper; }; //! \brief create a 'Bounded' expression template BoundedExpr is_bounded( const VectorT& vector, ScalarT lower, ScalarT upper ) { return BoundedExpr(vector, lower, upper); } // Logical Operators // ================= //! \brief Evaluate the logical AND between two expressions template AndBoolExpr operator&& ( BaseBoolExpr&& child_0, BaseBoolExpr&& child_1) { return AndBoolExpr( std::forward>(child_0), std::forward>(child_1) ); } //! \brief Evaluate the logical AND between two expressions template OrBoolExpr operator|| ( BaseBoolExpr&& child_0, BaseBoolExpr&& child_1) { return OrBoolExpr( std::forward>(child_0), std::forward>(child_1) ); } // Comparison Operator // =================== #define make_tag_operator(name, op) \ struct name \ { \ template \ bool operator() (const ScalarT& lhs, const ScalarT& rhs) const { \ return (lhs op rhs); \ } \ }; #define make_operator_overloading_class(name, op, class_name) \ template \ class_name ## Expr operator op (class_name&& lhs, ScalarT rhs) \ { \ return class_name ## Expr(lhs(), rhs); \ } #define make_operator_overloading_all(name, op) \ make_operator_overloading_class(name, op, All) #define make_operator_overloading_any(name, op) \ make_operator_overloading_class(name, op, Any) #define make_operator(name, op) \ make_tag_operator(name, op) \ make_operator_overloading_all(name, op) \ make_operator_overloading_any(name, op) make_operator(DifferentThan, !=) make_operator(EqualTo, ==) make_operator(GreaterThan, >) make_operator(GreaterThanOrEqualTo, >=) make_operator(LessThan, <) make_operator(LessThanOrEqualTo, <=) #undef make_operator #undef make_operator_overloading_any #undef make_operator_overloading_all #undef make_operator_overloading_class #undef make_tag_operator // special operator struct IsFinite { template bool operator() (const ScalarT& lhs, const ScalarT& _) const { return (std::isfinite(lhs)); } }; //! \brief check that all element of a vector is finite template AllExpr is_finite(const VectorT& vector) { return AllExpr(vector, 0.0); } //! \brief create a 'LowerBounded' expression template AllExpr is_lower_bounded( const VectorT& vector, ScalarT lower ) { return AllExpr(vector, lower); } //! \brief create a 'UpperBounded' expression template AllExpr is_upper_bounded( const VectorT& vector, ScalarT upper ) { return AllExpr(vector, upper); } } //end namespace vector_checker } //end namespace specmicp #endif // SPECMICP_UTILS_VECTORCHECKER_HPP