diff --git a/examples/reactmicp/saturated_react/momas_benchmark.cpp b/examples/reactmicp/saturated_react/momas_benchmark.cpp index 2f3ea83..70a8d45 100644 --- a/examples/reactmicp/saturated_react/momas_benchmark.cpp +++ b/examples/reactmicp/saturated_react/momas_benchmark.cpp @@ -1,590 +1,590 @@ #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "reactmicp/solver/staggers_base/upscaling_stagger_base.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #include "reactmicp/solver/reactive_transport_solver.hpp" #include "reactmicp/systems/saturated_react/variables.hpp" #include "reactmicp/systems/saturated_react/transport_stagger.hpp" #include "reactmicp/systems/saturated_react/equilibrium_stagger.hpp" #include "reactmicp/systems/saturated_react/init_variables.hpp" #include "dfpm/meshes/axisymmetric_uniform_mesh1d.hpp" #include "dfpm/meshes/axisymmetric_mesh1d.hpp" #include "dfpm/meshes/uniform_mesh1d.hpp" #include "utils/log.hpp" #include #include #include #include #include "database/database.hpp" -#include "database/selector.hpp" +#include "database/aqueous_selector.hpp" #include "reactmicp/solver/timestepper.hpp" #include "utils/io/reactive_transport.hpp" #include "utils/timer.hpp" // parameters #define DX 0.01 #define IS_ADVECTIVE true #define MIN_DT 0.01 #define MAX_DT 100.0 #define RESTART_DT MIN_DT using namespace specmicp; RawDatabasePtr get_momas_db() { database::Database thedatabase("../data/momas_benchmark.js"); return thedatabase.get_database(); } void prepare_db_for_easy_case(RawDatabasePtr raw_data) { database::Database db_handler(raw_data); db_handler.remove_components({raw_data->get_id_component("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::DatabaseSelector selector(raw_data); + 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) { SaturatedVariablesPtr true_var = cast_var_from_base(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 void initialize_timestep(scalar_t dt, VariablesBasePtr var) { } //! \brief Solve the equation for the timestep StaggerReturnCode restart_timestep(VariablesBasePtr var) { return StaggerReturnCode::ResidualMinimized; } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; 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(); std::ofstream output_gen("out_momas_out.txt"); io::print_reactmicp_header(&output_gen); specmicp::logger::ErrFile::stream() = &output_gen; //&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 std::ofstream output_mesh; output_mesh.open("out_momas_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)-dx/2.0 << std::endl; } output_mesh.close(); //std::cout << variables->displacement() << std::endl; std::ofstream 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/src/database/CMakeLists.txt b/src/database/CMakeLists.txt index ffa9e9b..fa38469 100644 --- a/src/database/CMakeLists.txt +++ b/src/database/CMakeLists.txt @@ -1,94 +1,103 @@ # The database # ============ # database libraries # ------------------ add_custom_target(database_incl SOURCES species/ionic_parameters.hpp species/component_list.hpp species/aqueous_list.hpp errors.hpp module.hpp ) set(DATABASE_LIBFILE species/species.cpp species/base_wrapper.cpp species/mineral_list.cpp species/gas_list.cpp species/sorbed_list.cpp data_container.cpp database.cpp reader.cpp selector.cpp appender.cpp mineral_selector.cpp aqueous_selector.cpp oxydo_selector.cpp switch_basis.cpp ${JSONCPP_DIR}/jsoncpp.cpp ) +foreach(file ${DATABASE_LIBFILE}) + set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS -fvisibility=hidden) +endforeach() + add_library(specmicp_database SHARED ${DATABASE_LIBFILE}) add_dependencies(specmicp_database database_incl) install(TARGETS specmicp_database LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} ) # export includes # ---------------- set(DATABASE_SPECIES_INCLUDE_LIST species/species.hpp species/base_wrapper.hpp species/ionic_parameters.hpp species/component_list.hpp species/aqueous_list.hpp species/mineral_list.hpp species/gas_list.hpp species/sorbed_list.hpp ) set(DATABASE_INCLUDE_LIST errors.hpp module.hpp data_container.hpp database.hpp reader.hpp selector.hpp appender.hpp mineral_selector.hpp aqueous_selector.hpp oxydo_selector.hpp switch_basis.hpp ) install(FILES ${DATABASE_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/database/ ) install(FILES ${DATABASE_SPECIES_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/database/species/ ) # static libraries # ---------------- if(SPECMICP_BUILD_STATIC) add_library(specmicp_database_static STATIC ${DATABASE_LIBFILE}) - set_target_properties(specmicp_database_static PROPERTIES OUTPUT_NAME specmicp_database) - add_dependencies(specmicp_database_static database_incl) install(TARGETS specmicp_database_static ARCHIVE DESTINATION ${STATIC_LIBRARY_INSTALL_DIR} ) +else() + add_library(specmicp_database_static EXCLUDE_FROM_ALL STATIC ${DATABASE_LIBFILE}) endif() + + set_target_properties(specmicp_database_static PROPERTIES OUTPUT_NAME specmicp_database) + add_dependencies(specmicp_database_static database_incl) + + diff --git a/src/database/aqueous_selector.hpp b/src/database/aqueous_selector.hpp index 6313992..ae69ba0 100644 --- a/src/database/aqueous_selector.hpp +++ b/src/database/aqueous_selector.hpp @@ -1,67 +1,67 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef 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 AqueousSelector: public DatabaseModule +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/data_container.hpp b/src/database/data_container.hpp index 63b8b20..21b534f 100644 --- a/src/database/data_container.hpp +++ b/src/database/data_container.hpp @@ -1,355 +1,355 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef 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/component_list.hpp" #include "species/aqueous_list.hpp" #include "species/mineral_list.hpp" #include "species/gas_list.hpp" #include "species/sorbed_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 Metadata +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 DataContainer +struct SPECMICP_DLL_PUBLIC DataContainer { DataContainer() {} Metadata metadata; //!< Metada, name path and version of the database //! \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 g/mol scalar_t molar_mass_basis(index_t component) const NOEXCEPT {return components.molar_mass(component);} //! \brief Return the molar mass of 'component' in kg/mol scalar_t molar_mass_basis_si(index_t component) const NOEXCEPT {return 1e-3*molar_mass_basis(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 boost::irange(static_cast(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();} //! @} //! \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 boost::irange((index_t) 0, nb_sorbed());} //! \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); } //! @} //! \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 (m^3/mol) of a mineral scalar_t molar_volume_mineral(index_t m) const; //! \brief Return the molar volume (m^3/mol) of a mineral governed by kinetic scalar_t molar_volume_mineral_kinetic(index_t m) const; //! \brief Return the molar volume of a mineral in mol/(length_unit)^3 scalar_t molar_volume_mineral(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 boost::irange((index_t) 0, nb_gas());} //! @} //! \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 #endif // SPECMICP_DATABASE_DATACONTAINER_HPP diff --git a/src/database/database.hpp b/src/database/database.hpp index c95d2c3..fc016d6 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -1,144 +1,144 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_DATABASE_HPP #define SPECMICP_DATABASE_DATABASE_HPP //! \file src/database/database.hpp //! \brief Database management #include "module.hpp" #include namespace specmicp { //! \namespace database 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 Database: public DatabaseModule +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) { parse_database(filepath); } //! \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); //! \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 void remove_components(const std::vector& id_components_to_remove); //! \brief Keep only components in the id_components to keep void keep_only_components(const std::vector& id_components_to_keep); //! \brief Keep only components in the id_components to keep 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); //! \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); //! \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); //! \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); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_DATABASE_HPP diff --git a/src/database/species/base_wrapper.hpp b/src/database/species/base_wrapper.hpp index bb3b65c..1b76afd 100644 --- a/src/database/species/base_wrapper.hpp +++ b/src/database/species/base_wrapper.hpp @@ -1,266 +1,266 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef 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 MatrixSpeciesWrapper +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 add_to_row(index_t k, const Eigen::MatrixBase& other) { + 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 multiply_by(const Eigen::MatrixBase& multiplier) { + 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 set_matrix(const Eigen::MatrixBase& init_matrix) { + void SPECMICP_DLL_LOCAL set_matrix(const Eigen::MatrixBase& init_matrix) { m_matrix = init_matrix; } //! \brief Set the element ['row','col'] to 'value' - void set_value(index_t row, index_t col, scalar_t 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 reset_row(index_t 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 VectorSpeciesWrapper +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 add(const Eigen::MatrixBase& vector) { + void SPECMICP_DLL_LOCAL add(const Eigen::MatrixBase& vector) { m_vector += vector; } //! \brief Multiply the vector by 'multiplier' template - void multiply_by(const Eigen::MatrixBase& multiplier) { + void SPECMICP_DLL_LOCAL multiply_by(const Eigen::MatrixBase& multiplier) { m_vector = m_vector*multiplier; } //! \brief Set the value at index k - void set_value(index_t k, scalar_t value) { + void SPECMICP_DLL_LOCAL set_value(index_t k, scalar_t value) { m_vector(k) = value; } //! \brief Copy 'vector' to the vector template - void set_vector(const Eigen::MatrixBase& vector) { + 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/species.hpp b/src/database/species/species.hpp index 5fcb200..46aea0e 100644 --- a/src/database/species/species.hpp +++ b/src/database/species/species.hpp @@ -1,393 +1,393 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef 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 SpeciesList +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 {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 boost::irange((index_t) 0, 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 - void set_valid() {m_is_valid = true;} + 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 ReactiveSpeciesList: public SpeciesList +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 switch_basis( + 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 add_logk_alien_species_to( + 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 add_logk_species_to( + 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 add_nu_alien_species_to( + 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 add_nu_species_to( + 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/types.hpp b/src/types.hpp index 9811b91..5f13082 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -1,144 +1,152 @@ /*------------------------------------------------------------------------------- Copyright (c) 2014,2015 F. Georget , Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -----------------------------------------------------------------------------*/ #ifndef SPECMICP_TYPES_HPP #define SPECMICP_TYPES_HPP #include #include "boost/range/irange.hpp" //! \file 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 } // now we can include Eigen #ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE #define EIGEN_DEFAULT_DENSE_INDEX_TYPE specmicp::index_t #endif #include // ============ // Matrix stuff // ============ namespace specmicp { using scalar_t = double; //!< Type of a scalar // 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 = boost::iterator_range>; // 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 // macros // ------ // 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) // in case I need to add other stuff // also, can be used to disable specmic_assert but keep the Eigen stuff #ifdef SPECMICP_NO_DEBUG #define specmicp_assert #else #define specmicp_assert(x) assert(x) #endif // SPECMICP_NO_DEBUG // deprecation +// ----------- // For a feaure that is going to be removed #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 +// ---------- +#define SPECMICP_DLL_PUBLIC __attribute__ ((visibility("default"))) +#define SPECMICP_DLL_LOCAL __attribute__ ((visibility("hidden"))) + + #endif // SPECMICP_TYPES_HPP diff --git a/tests/database/CMakeLists.txt b/tests/database/CMakeLists.txt index c087c52..47f74a9 100644 --- a/tests/database/CMakeLists.txt +++ b/tests/database/CMakeLists.txt @@ -1,18 +1,18 @@ # test for the database add_custom_target(test_database_inc SOURCES str_database.hpp ) add_catch_test(NAME database SOURCES test_database.cpp database_species.cpp database_reader.cpp database_selector.cpp database_switch.cpp database_cemdata.cpp database_appender.cpp - LINK_LIBRARIES specmicp_database + LINK_LIBRARIES specmicp_database_static ) set(TEST_CEMDATA_PATH \\"../../data/cemdata.js\\") set_target_properties(test_database PROPERTIES COMPILE_FLAGS -DTEST_CEMDATA_PATH=${TEST_CEMDATA_PATH})