From 813fc93e6391aacf44667e7fa8ea66388761bbb1 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 19 Oct 2023 10:30:35 -0500 Subject: [PATCH 01/30] decoupling solver stats --- include/micm/solver/rosenbrock.hpp | 5 ++-- include/micm/solver/rosenbrock.inl | 40 +++++++++++++++--------------- test/integration/e5.hpp | 2 -- test/integration/hires.hpp | 2 -- test/integration/oregonator.hpp | 2 -- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index b692d1151..767c69ec3 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -171,7 +171,7 @@ namespace micm uint64_t rejected{}; /// @brief The number of LU decompositions uint64_t decompositions{}; - /// @brief The number of linear solvers + /// @brief The number of linear solves uint64_t solves{}; /// @brief The number of times a singular matrix is detected. For now, this will always be zero as we assume the matrix is never singular uint64_t singular{}; @@ -205,7 +205,6 @@ namespace micm RosenbrockSolverParameters parameters_; std::function& variables, const std::size_t i)> state_reordering_; ProcessSet process_set_; - SolverStats stats_; SparseMatrixPolicy jacobian_; LinearSolverPolicy linear_solver_; std::vector jacobian_diagonal_elements_; @@ -285,7 +284,7 @@ namespace micm /// @param singular indicates if the matrix is singular /// @param number_densities constituent concentration (molec/cm^3) /// @param rate_constants Rate constants for each process (molecule/cm3)^(n-1) s-1 - void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities); + void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities, SolverStats& stats); protected: /// @brief Computes the scaled norm of the vector errors diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 7d1cc6f9b..c56edf041 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -418,7 +418,6 @@ namespace micm parameters_(RosenbrockSolverParameters::three_stage_rosenbrock_parameters()), state_reordering_(), process_set_(), - stats_(), jacobian_(), linear_solver_(), jacobian_diagonal_elements_(), @@ -452,7 +451,6 @@ namespace micm parameters_(parameters), state_reordering_(), process_set_(), - stats_(), jacobian_(), linear_solver_(), jacobian_diagonal_elements_(), @@ -521,7 +519,7 @@ namespace micm parameters_.h_max_ = time_step; parameters_.h_start_ = std::max(parameters_.h_min_, delta_min_); - stats_.Reset(); + SolverStats stats; UpdateState(state); for (std::size_t i = 0; i < parameters_.stages_; ++i) @@ -539,7 +537,7 @@ namespace micm while ((present_time - time_step + parameters_.round_off_) <= 0 && (result.state_ == SolverState::Running)) { - if (stats_.number_of_steps > parameters_.max_number_of_steps_) + if (stats.number_of_steps > parameters_.max_number_of_steps_) { result.state_ = SolverState::ConvergenceExceededMaxSteps; break; @@ -555,10 +553,12 @@ namespace micm H = std::min(H, std::abs(time_step - present_time)); // compute the forcing at the beginning of the current time - TIMED_METHOD(stats_.total_forcing_time, time_it, CalculateForcing, state.rate_constants_, Y, initial_forcing); + TIMED_METHOD(stats.total_forcing_time, time_it, CalculateForcing, state.rate_constants_, Y, initial_forcing); + stats.function_calls += 1; // compute the jacobian at the beginning of the current time - TIMED_METHOD(stats_.total_jacobian_time, time_it, CalculateJacobian, state.rate_constants_, Y, jacobian_); + TIMED_METHOD(stats.total_jacobian_time, time_it, CalculateJacobian, state.rate_constants_, Y, jacobian_); + stats.jacobian_updates += 1; bool accepted = false; // Repeat step calculation until current step accepted @@ -566,7 +566,7 @@ namespace micm { bool is_singular{ false }; // Form and factor the rosenbrock ode jacobian - TIMED_METHOD(stats_.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y); + TIMED_METHOD(stats.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y, stats); if (is_singular) { result.state_ = SolverState::RepeatedlySingularMatrix; @@ -591,7 +591,8 @@ namespace micm auto a = parameters_.a_[stage_combinations + j]; Ynew.ForEach([&](double& iYnew, double& iKj) { iYnew += a * iKj; }, K[j]); } - TIMED_METHOD(stats_.total_forcing_time, time_it, CalculateForcing, state.rate_constants_, Ynew, forcing); + TIMED_METHOD(stats.total_forcing_time, time_it, CalculateForcing, state.rate_constants_, Ynew, forcing); + stats.function_calls += 1; } } K[stage].AsVector().assign(forcing.AsVector().begin(), forcing.AsVector().end()); @@ -601,8 +602,8 @@ namespace micm K[stage].ForEach([&](double& iKstage, double& iKj) { iKstage += HC * iKj; }, K[j]); } temp.AsVector().assign(K[stage].AsVector().begin(), K[stage].AsVector().end()); - TIMED_METHOD(stats_.total_linear_solve_time, time_it, linear_solver_.template Solve, temp, K[stage]); - stats_.solves += 1; + TIMED_METHOD(stats.total_linear_solve_time, time_it, linear_solver_.template Solve, temp, K[stage]); + stats.solves += 1; } // Compute the new solution @@ -625,7 +626,7 @@ namespace micm parameters_.safety_factor_ / std::pow(error, 1 / parameters_.estimator_of_local_order_))); double Hnew = H * fac; - stats_.number_of_steps += 1; + stats.number_of_steps += 1; // Check the error magnitude and adjust step size if (std::isnan(error)) @@ -636,7 +637,7 @@ namespace micm } else if ((error < 1) || (H < parameters_.h_min_)) { - stats_.accepted += 1; + stats.accepted += 1; present_time = present_time + H; Y.AsVector().assign(Ynew.AsVector().begin(), Ynew.AsVector().end()); Hnew = std::max(parameters_.h_min_, std::min(Hnew, parameters_.h_max_)); @@ -660,9 +661,9 @@ namespace micm reject_more_h = reject_last_h; reject_last_h = true; H = Hnew; - if (stats_.accepted >= 1) + if (stats.accepted >= 1) { - stats_.rejected += 1; + stats.rejected += 1; } } } @@ -674,7 +675,7 @@ namespace micm } result.final_time_ = present_time; - result.stats_ = stats_; + result.stats_ = stats; result.result_ = Y; return result; } @@ -687,7 +688,6 @@ namespace micm { std::fill(forcing.AsVector().begin(), forcing.AsVector().end(), 0.0); process_set_.AddForcingTerms(rate_constants, number_densities, forcing); - stats_.function_calls += 1; } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> @@ -732,7 +732,6 @@ namespace micm { std::fill(jacobian.AsVector().begin(), jacobian.AsVector().end(), 0.0); process_set_.AddJacobianTerms(rate_constants, number_densities, jacobian); - stats_.jacobian_updates += 1; } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> @@ -746,7 +745,8 @@ namespace micm double& H, const double gamma, bool& singular, - const MatrixPolicy& number_densities) + const MatrixPolicy& number_densities, + SolverStats& stats) { // TODO: invesitage this function. The fortran equivalent appears to have a bug. // From my understanding the fortran do loop would only ever do one iteration and is equivalent to what's below @@ -759,10 +759,10 @@ namespace micm AlphaMinusJacobian(jacobian, alpha); linear_solver_.Factor(jacobian); singular = false; // TODO This should be evaluated in some way - stats_.decompositions += 1; + stats.decompositions += 1; if (!singular) break; - stats_.singular += 1; + stats.singular += 1; if (++n_consecutive > 5) break; H /= 2; diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 098895121..bbf2e6b45 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -46,7 +46,6 @@ class E5 : public micm::RosenbrockSolver& forcing) override { std::fill(forcing.AsVector().begin(), forcing.AsVector().end(), 0.0); - this->stats_.function_calls += 1; auto data = number_densities.AsVector(); @@ -71,7 +70,6 @@ class E5 : public micm::RosenbrockSolverstats_.jacobian_updates += 1; double A = 7.89e-10; double B = 1.1e7; diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 59db5712f..5b682cafc 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -47,7 +47,6 @@ class HIRES : public micm::RosenbrockSolver& forcing) override { std::fill(forcing.AsVector().begin(), forcing.AsVector().end(), 0.0); - this->stats_.function_calls += 1; auto data = number_densities.AsVector(); @@ -72,7 +71,6 @@ class HIRES : public micm::RosenbrockSolverstats_.jacobian_updates += 1; jacobian[0][0][0] = -1.71; jacobian[0][0][1] = 0.43; diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index be6619d57..27b74f69f 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -47,7 +47,6 @@ class Oregonator : public micm::RosenbrockSolver& forcing) override { std::fill(forcing.AsVector().begin(), forcing.AsVector().end(), 0.0); - this->stats_.function_calls += 1; auto data = number_densities.AsVector(); @@ -66,7 +65,6 @@ class Oregonator : public micm::RosenbrockSolver& jacobian) override { auto data = number_densities.AsVector(); - this->stats_.jacobian_updates += 1; jacobian[0][0][0] = 77.27 * (1. - 2. * 8.375e-6 * data[0] - data[1]); jacobian[0][0][1] = 77.27 * (1. - data[0]); From ddeaaa36123d1c03208b22baf60bada065968003 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Fri, 20 Oct 2023 10:59:29 -0500 Subject: [PATCH 02/30] put the jacobian on the state --- docs/source/conf.py | 2 + .../user_defined_rate_constant_tutorial.rst | 4 +- include/micm/process/process.hpp | 16 +- include/micm/process/process_set.hpp | 12 +- include/micm/solver/rosenbrock.hpp | 72 +- include/micm/solver/rosenbrock.inl | 145 +- include/micm/solver/state.hpp | 27 +- include/micm/solver/state.inl | 55 +- test/integration/analytical_rosenbrock.cpp | 1254 ++++++++--------- test/integration/chapman.cpp | 2 +- test/integration/e5.hpp | 15 +- test/integration/hires.hpp | 15 +- test/integration/oregonator.hpp | 15 +- test/kpp/test_kpp_to_micm.cpp | 4 +- .../regression_test_dforce_dy_policy.hpp | 2 +- test/tutorial/test_but_how_fast_is_it.cpp | 2 +- test/tutorial/test_multiple_grid_cells.cpp | 6 +- ...st_rate_constants_user_defined_by_hand.cpp | 4 +- ...ate_constants_user_defined_with_config.cpp | 4 +- test/tutorial/test_solver_configuration.cpp | 8 +- test/unit/process/test_process_set.cpp | 16 +- test/unit/process/test_process_set_policy.hpp | 4 +- test/unit/solver/test_rosenbrock.cpp | 2 +- test/unit/solver/test_state.cpp | 20 +- 24 files changed, 891 insertions(+), 815 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 15a34ab77..68a05905a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -66,6 +66,8 @@ "json_url": "https://ncar.github.io/micm/_static/switcher.json", "version_match": release, }, + "pygment_light_style": "tango", + "pygment_dark_style": "monokai" } html_css_files = [ diff --git a/docs/source/user_guide/user_defined_rate_constant_tutorial.rst b/docs/source/user_guide/user_defined_rate_constant_tutorial.rst index 089f6aa12..339dd2c86 100644 --- a/docs/source/user_guide/user_defined_rate_constant_tutorial.rst +++ b/docs/source/user_guide/user_defined_rate_constant_tutorial.rst @@ -194,7 +194,7 @@ Finally, set and upate the rate constants as needed: // so we need to track how much time the solver was able to integrate for and continue // solving until we finish double elapsed_solve_time = 0; - + state.SetCustomRateParameter("PHOTO.my photolysis rate", photo_rate); + +state.SetCustomRateParameter("PHOTO.my photolysis rate", photo_rate); while (elapsed_solve_time < time_step) { @@ -205,7 +205,7 @@ Finally, set and upate the rate constants as needed: } print_state(time_step * (i + 1), state); - + photo_rate *= 1.5; + +photo_rate *= 1.5; } And this is final output. Notice that the concentration of G ends up much higher than in diff --git a/include/micm/process/process.hpp b/include/micm/process/process.hpp index 92c0c5250..48d338718 100644 --- a/include/micm/process/process.hpp +++ b/include/micm/process/process.hpp @@ -43,14 +43,14 @@ namespace micm /// @brief Update the solver state rate constants /// @param processes The set of processes being solved /// @param state The solver state to update - template class MatrixPolicy> + template class MatrixPolicy, template class SparseMatrixPolicy> requires(!VectorizableDense>) static void UpdateState( const std::vector& processes, - State& state); - template class MatrixPolicy> + State& state); + template class MatrixPolicy, template class SparseMatrixPolicy> requires(VectorizableDense>) static void UpdateState( const std::vector& processes, - State& state); + State& state); friend class ProcessBuilder; static ProcessBuilder create(); @@ -104,10 +104,10 @@ namespace micm ProcessBuilder& phase(const Phase& phase); }; - template class MatrixPolicy> + template class MatrixPolicy, template class SparseMatrixPolicy> requires(!VectorizableDense>) void Process::UpdateState( const std::vector& processes, - State& state) + State& state) { for (std::size_t i{}; i < state.custom_rate_parameters_.size(); ++i) { @@ -123,10 +123,10 @@ namespace micm } } - template class MatrixPolicy> + template class MatrixPolicy, template class SparseMatrixPolicy> requires(VectorizableDense>) void Process::UpdateState( const std::vector& processes, - State& state) + State& state) { const auto& v_custom_parameters = state.custom_rate_parameters_.AsVector(); auto& v_rate_constants = state.rate_constants_.AsVector(); diff --git a/include/micm/process/process_set.hpp b/include/micm/process/process_set.hpp index 74e04eb64..63d7f114a 100644 --- a/include/micm/process/process_set.hpp +++ b/include/micm/process/process_set.hpp @@ -29,9 +29,8 @@ namespace micm /// @brief Create a process set calculator for a given set of processes /// @param processes Processes to create calculator for - /// @param state Solver state - template class MatrixPolicy> - ProcessSet(const std::vector& processes, const State& state); + /// @param StateParameters Solver state + ProcessSet(const std::vector& processes, std::map variable_map); /// @brief Return the full set of non-zero Jacobian elements for the set of processes /// @return Jacobian elements as a set of index pairs @@ -74,8 +73,7 @@ namespace micm SparseMatrixPolicy& jacobian) const; }; - template class MatrixPolicy> - inline ProcessSet::ProcessSet(const std::vector& processes, const State& state) + inline ProcessSet::ProcessSet(const std::vector& processes, std::map variable_map) : number_of_reactants_(), reactant_ids_(), number_of_products_(), @@ -88,11 +86,11 @@ namespace micm number_of_products_.push_back(process.products_.size()); for (auto& reactant : process.reactants_) { - reactant_ids_.push_back(state.variable_map_.at(reactant.name_)); + reactant_ids_.push_back(variable_map.at(reactant.name_)); } for (auto& product : process.products_) { - product_ids_.push_back(state.variable_map_.at(product.first.name_)); + product_ids_.push_back(variable_map.at(product.first.name_)); yields_.push_back(product.second); } } diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 767c69ec3..dc30f5887 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -147,6 +147,37 @@ namespace micm std::string StateToString(const SolverState& state); + struct SolverStats + { + /// @brief The number of forcing function calls + uint64_t function_calls{}; + /// @brief The number of jacobian function calls + uint64_t jacobian_updates{}; + /// @brief The total number of internal time steps taken + uint64_t number_of_steps{}; + /// @brief The number of accepted integrations + uint64_t accepted{}; + /// @brief The number of rejected integrations + uint64_t rejected{}; + /// @brief The number of LU decompositions + uint64_t decompositions{}; + /// @brief The number of linear solves + uint64_t solves{}; + /// @brief The number of times a singular matrix is detected. For now, this will always be zero as we assume the matrix is never singular + uint64_t singular{}; + /// @brief The cumulative amount of time spent calculating the forcing function + std::chrono::duration total_forcing_time{}; + /// @brief The cumulative amount of time spent calculating the jacobian + std::chrono::duration total_jacobian_time{}; + /// @brief The cumulative amount of time spent calculating the linear factorization + std::chrono::duration total_linear_factor_time{}; + /// @brief The cumulative amount of time spent calculating the linear solve + std::chrono::duration total_linear_solve_time{}; + + /// @brief Set all member variables to zero + void Reset(); + }; + /// @brief An implementation of the Rosenbrock ODE solver /// /// The template parameter is the type of matrix to use @@ -157,36 +188,6 @@ namespace micm class RosenbrockSolver { public: - struct SolverStats - { - /// @brief The number of forcing function calls - uint64_t function_calls{}; - /// @brief The number of jacobian function calls - uint64_t jacobian_updates{}; - /// @brief The total number of internal time steps taken - uint64_t number_of_steps{}; - /// @brief The number of accepted integrations - uint64_t accepted{}; - /// @brief The number of rejected integrations - uint64_t rejected{}; - /// @brief The number of LU decompositions - uint64_t decompositions{}; - /// @brief The number of linear solves - uint64_t solves{}; - /// @brief The number of times a singular matrix is detected. For now, this will always be zero as we assume the matrix is never singular - uint64_t singular{}; - /// @brief The cumulative amount of time spent calculating the forcing function - std::chrono::duration total_forcing_time{}; - /// @brief The cumulative amount of time spent calculating the jacobian - std::chrono::duration total_jacobian_time{}; - /// @brief The cumulative amount of time spent calculating the linear factorization - std::chrono::duration total_linear_factor_time{}; - /// @brief The cumulative amount of time spent calculating the linear solve - std::chrono::duration total_linear_solve_time{}; - - /// @brief Set all member variables to zero - void Reset(); - }; struct [[nodiscard]] SolverResult { @@ -203,11 +204,10 @@ namespace micm System system_; std::vector processes_; RosenbrockSolverParameters parameters_; + StateParameters state_parameters_; std::function& variables, const std::size_t i)> state_reordering_; ProcessSet process_set_; - SparseMatrixPolicy jacobian_; LinearSolverPolicy linear_solver_; - std::vector jacobian_diagonal_elements_; size_t N_{}; static constexpr double delta_min_ = 1.0e-6; @@ -240,13 +240,13 @@ namespace micm /// @brief Returns a state object for use with the solver /// @return A object that can hold the full state of the chemical system - State GetState() const; + State GetState() const; /// @brief Advances the given step over the specified time step /// @param time_step Time [s] to advance the state by /// @return A struct containing results and a status code template - SolverResult Solve(double time_step, State& state) noexcept; + SolverResult Solve(double time_step, State& state) noexcept; /// @brief Calculate a chemical forcing /// @param rate_constants List of rate constants for each needed species @@ -267,7 +267,7 @@ namespace micm /// @brief Update the rate constants for the environment state /// @param state The current state of the chemical system - void UpdateState(State& state); + void UpdateState(State& state); /// @brief Compute the derivative of the forcing w.r.t. each chemical, the jacobian /// @param rate_constants List of rate constants for each needed species @@ -284,7 +284,7 @@ namespace micm /// @param singular indicates if the matrix is singular /// @param number_densities constituent concentration (molec/cm^3) /// @param rate_constants Rate constants for each process (molecule/cm3)^(n-1) s-1 - void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities, SolverStats& stats); + void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities, SolverStats& stats, SparseMatrixPolicy jacobian); protected: /// @brief Computes the scaled norm of the vector errors diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index c56edf041..7c20f2afa 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -1,20 +1,42 @@ // Copyright (C) 2023 National Center for Atmospheric Research // SPDX-License-Identifier: Apache-2.0 -#define TIMED_METHOD(assigned_increment, time_it, method, ...) \ - { \ - if constexpr (time_it) { \ - auto start = std::chrono::high_resolution_clock::now(); \ - method(__VA_ARGS__); \ - auto end = std::chrono::high_resolution_clock::now(); \ - assigned_increment += std::chrono::duration_cast(end - start); \ - } else { \ - method(__VA_ARGS__); \ - } \ - } \ +#define TIMED_METHOD(assigned_increment, time_it, method, ...) \ + { \ + if constexpr (time_it) \ + { \ + auto start = std::chrono::high_resolution_clock::now(); \ + method(__VA_ARGS__); \ + auto end = std::chrono::high_resolution_clock::now(); \ + assigned_increment += std::chrono::duration_cast(end - start); \ + } \ + else \ + { \ + method(__VA_ARGS__); \ + } \ + } namespace micm { + // annonymous namespace to hide jacobian builder + namespace { + template class SparseMatrixPolicy> + SparseMatrixPolicy build_jacobian( + std::set> nonzero_jacobian_elements, + size_t number_of_grid_cells, + size_t state_size + ) + { + auto builder = SparseMatrixPolicy::create(state_size).number_of_blocks(number_of_grid_cells); + for (auto& elem : nonzero_jacobian_elements) + builder = builder.with_element(elem.first, elem.second); + // Always include diagonal elements + for (std::size_t i = 0; i < state_size; ++i) + builder = builder.with_element(i, i); + + return SparseMatrixPolicy(builder); + } + } // // RosenbrockSolverParameters // @@ -378,8 +400,7 @@ namespace micm // // RosenbrockSolver // - template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> - inline void RosenbrockSolver::SolverStats::Reset() + inline void SolverStats::Reset() { function_calls = 0; jacobian_updates = 0; @@ -416,11 +437,10 @@ namespace micm : system_(), processes_(), parameters_(RosenbrockSolverParameters::three_stage_rosenbrock_parameters()), + state_parameters_(), state_reordering_(), process_set_(), - jacobian_(), linear_solver_(), - jacobian_diagonal_elements_(), N_(system_.StateSize() * parameters_.number_of_grid_cells_) { } @@ -449,18 +469,23 @@ namespace micm : system_(system), processes_(processes), parameters_(parameters), + state_parameters_(), state_reordering_(), process_set_(), - jacobian_(), linear_solver_(), - jacobian_diagonal_elements_(), N_(system_.StateSize() * parameters_.number_of_grid_cells_) { + std::map variable_map; + + std::size_t index = 0; + for (auto& name : system_.UniqueNames(state_reordering_)) + variable_map[name] = index++; + // generate a state-vector reordering function to reduce fill-in in linear solver if (parameters_.reorder_state_) { // get unsorted Jacobian non-zero elements - auto unsorted_process_set = ProcessSet(processes, GetState()); + auto unsorted_process_set = ProcessSet(processes, variable_map); auto unsorted_jac_elements = unsorted_process_set.NonZeroJacobianElements(); MatrixPolicy unsorted_jac_non_zeros(system_.StateSize(), system_.StateSize(), 0); for (auto& elem : unsorted_jac_elements) @@ -468,36 +493,56 @@ namespace micm auto reorder_map = DiagonalMarkowitzReorder(unsorted_jac_non_zeros); state_reordering_ = [=](const std::vector& variables, const std::size_t i) { return variables[reorder_map[i]]; }; - } - process_set_ = ProcessSet(processes, GetState()); - auto builder = - SparseMatrixPolicy::create(system_.StateSize()).number_of_blocks(parameters_.number_of_grid_cells_); - auto jac_elements = process_set_.NonZeroJacobianElements(); - for (auto& elem : jac_elements) - builder = builder.with_element(elem.first, elem.second); - // Always include diagonal elements - for (std::size_t i = 0; i < system_.StateSize(); ++i) - builder = builder.with_element(i, i); - - jacobian_ = builder; - linear_solver_ = std::move(create_linear_solver(jacobian_, 1.0e-30)); - process_set_.SetJacobianFlatIds(jacobian_); - for (std::size_t i = 0; i < jacobian_[0].size(); ++i) - jacobian_diagonal_elements_.push_back(jacobian_.VectorIndex(0, i, i)); - } - template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> - inline State RosenbrockSolver::GetState() const - { + variable_map.clear(); + std::size_t index = 0; + for (auto& name : system_.UniqueNames(state_reordering_)) + variable_map[name] = index++; + } + + // setup the state_parameters std::vector param_labels{}; for (const auto& process : processes_) if (process.rate_constant_) for (auto& label : process.rate_constant_->CustomParameters()) param_labels.push_back(label); - return State{ micm::StateParameters{ .state_variable_names_ = system_.UniqueNames(state_reordering_), - .custom_rate_parameter_labels_ = param_labels, - .number_of_grid_cells_ = parameters_.number_of_grid_cells_, - .number_of_rate_constants_ = processes_.size() } }; + + process_set_ = ProcessSet(processes, variable_map); + + auto jacobian = build_jacobian( + process_set_.NonZeroJacobianElements(), + parameters_.number_of_grid_cells_, + system_.StateSize() + ); + + std::vector jacobian_diagonal_elements; + for (std::size_t i = 0; i < jacobian[0].size(); ++i) + jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); + + state_parameters_ = { + .variable_names_ = system_.UniqueNames(state_reordering_), + .custom_rate_parameter_labels_ = param_labels, + .number_of_grid_cells_ = parameters_.number_of_grid_cells_, + .number_of_rate_constants_ = processes_.size(), + .nonzero_jacobian_elements_ = process_set_.NonZeroJacobianElements(), + .jacobian_diagonal_elements_ = jacobian_diagonal_elements + }; + + process_set_.SetJacobianFlatIds(jacobian); + linear_solver_ = std::move(create_linear_solver(jacobian, 1.0e-30)); + } + + template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> + inline State RosenbrockSolver::GetState() const + { + auto state = State{ state_parameters_ }; + state.jacobian_ = build_jacobian( + state_parameters_.nonzero_jacobian_elements_, + state_parameters_.number_of_grid_cells_, + system_.StateSize() + ); + + return state; } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> @@ -505,7 +550,7 @@ namespace micm inline typename RosenbrockSolver::SolverResult RosenbrockSolver::Solve( double time_step, - State& state) noexcept + State& state) noexcept { typename RosenbrockSolver::SolverResult result{}; result.state_ = SolverState::Running; @@ -557,7 +602,7 @@ namespace micm stats.function_calls += 1; // compute the jacobian at the beginning of the current time - TIMED_METHOD(stats.total_jacobian_time, time_it, CalculateJacobian, state.rate_constants_, Y, jacobian_); + TIMED_METHOD(stats.total_jacobian_time, time_it, CalculateJacobian, state.rate_constants_, Y, state.jacobian_); stats.jacobian_updates += 1; bool accepted = false; @@ -566,7 +611,7 @@ namespace micm { bool is_singular{ false }; // Form and factor the rosenbrock ode jacobian - TIMED_METHOD(stats.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y, stats); + TIMED_METHOD(stats.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y, stats, state.jacobian_); if (is_singular) { result.state_ = SolverState::RepeatedlySingularMatrix; @@ -701,7 +746,7 @@ namespace micm for (std::size_t i_block = 0; i_block < jacobian.size(); ++i_block) { auto jacobian_vector = std::next(jacobian.AsVector().begin(), i_block * jacobian.FlatBlockSize()); - for (const auto& i_elem : jacobian_diagonal_elements_) + for (const auto& i_elem : state_parameters_.jacobian_diagonal_elements_) jacobian_vector[i_elem] += alpha; } } @@ -718,7 +763,7 @@ namespace micm for (std::size_t i_group = 0; i_group < jacobian.NumberOfGroups(jacobian.size()); ++i_group) { auto jacobian_vector = std::next(jacobian.AsVector().begin(), i_group * jacobian.GroupSize(jacobian.FlatBlockSize())); - for (const auto& i_elem : jacobian_diagonal_elements_) + for (const auto& i_elem : state_parameters_.jacobian_diagonal_elements_) for (std::size_t i_cell = 0; i_cell < n_cells; ++i_cell) jacobian_vector[i_elem + i_cell] += alpha; } @@ -735,7 +780,7 @@ namespace micm } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> - inline void RosenbrockSolver::UpdateState(State& state) + inline void RosenbrockSolver::UpdateState(State& state) { Process::UpdateState(processes_, state); } @@ -746,11 +791,11 @@ namespace micm const double gamma, bool& singular, const MatrixPolicy& number_densities, - SolverStats& stats) + SolverStats& stats, + SparseMatrixPolicy jacobian) { // TODO: invesitage this function. The fortran equivalent appears to have a bug. // From my understanding the fortran do loop would only ever do one iteration and is equivalent to what's below - SparseMatrixPolicy jacobian = jacobian_; uint64_t n_consecutive = 0; singular = true; while (true) diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index da59c2fa0..96072af7d 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -14,24 +15,38 @@ namespace micm { + /// @brief Invariants that can be used to construct a state struct StateParameters { - std::vector state_variable_names_{}; - std::vector custom_rate_parameter_labels_{}; std::size_t number_of_grid_cells_{ 1 }; std::size_t number_of_rate_constants_{ 0 }; + std::map variable_map_; + std::map custom_rate_parameter_map_; + std::vector variable_names_{}; + std::vector custom_rate_parameter_labels_{}; + std::set> nonzero_jacobian_elements_; + std::vector jacobian_diagonal_elements_; }; - template class MatrixPolicy = Matrix> + template< + template class MatrixPolicy = Matrix, + template class SparseMatrixPolicy = StandardSparseMatrix> struct State { + /// @brief The concentration of chemicals, varies through time + MatrixPolicy variables_; + /// @brief Rate paramters particular to user-defined rate constants, may vary in time + MatrixPolicy custom_rate_parameters_; + /// @brief The reaction rates, may vary in time + MatrixPolicy rate_constants_; + /// @brief Atmospheric conditions, varies in time std::vector conditions_; + /// @brief The jacobian structure, varies for each solve + SparseMatrixPolicy jacobian_; + /// @brief Immutable data required for the state std::map variable_map_; std::map custom_rate_parameter_map_; std::vector variable_names_{}; - MatrixPolicy variables_; - MatrixPolicy custom_rate_parameters_; - MatrixPolicy rate_constants_; /// @brief State(); diff --git a/include/micm/solver/state.inl b/include/micm/solver/state.inl index dbd2c2321..5e8d7346f 100644 --- a/include/micm/solver/state.inl +++ b/include/micm/solver/state.inl @@ -4,53 +4,48 @@ namespace micm { - template class MatrixPolicy> - inline State::State() + template class MatrixPolicy, template class SparseMatrixPolicy> + inline State::State() : conditions_(), - variable_map_(), - custom_rate_parameter_map_(), - variable_names_(), variables_(), custom_rate_parameters_(), rate_constants_() { } - template class MatrixPolicy> - inline State::State( + template class MatrixPolicy, template class SparseMatrixPolicy> + inline State::State( const std::size_t state_size, const std::size_t custom_parameters_size, const std::size_t process_size) : conditions_(1), - variable_map_(), - custom_rate_parameter_map_(), - variable_names_(), variables_(1, state_size, 0.0), custom_rate_parameters_(1, custom_parameters_size, 0.0), - rate_constants_(1, process_size, 0.0) + rate_constants_(1, process_size, 0.0), + jacobian_() { } - template class MatrixPolicy> - inline State::State(const StateParameters& parameters) + template class MatrixPolicy, template class SparseMatrixPolicy> + inline State::State(const StateParameters& parameters) : conditions_(parameters.number_of_grid_cells_), + variables_(parameters.number_of_grid_cells_, parameters.variable_names_.size(), 0.0), + custom_rate_parameters_(parameters.number_of_grid_cells_, parameters.custom_rate_parameter_labels_.size(), 0.0), + rate_constants_(parameters.number_of_grid_cells_, parameters.number_of_rate_constants_, 0.0), variable_map_(), custom_rate_parameter_map_(), - variable_names_(parameters.state_variable_names_), - variables_(parameters.number_of_grid_cells_, parameters.state_variable_names_.size(), 0.0), - custom_rate_parameters_(parameters.number_of_grid_cells_, parameters.custom_rate_parameter_labels_.size(), 0.0), - rate_constants_(parameters.number_of_grid_cells_, parameters.number_of_rate_constants_, 0.0) + variable_names_(parameters.variable_names_) { std::size_t index = 0; - for (auto& name : parameters.state_variable_names_) + for (auto& name : variable_names_) variable_map_[name] = index++; index = 0; for (auto& label : parameters.custom_rate_parameter_labels_) custom_rate_parameter_map_[label] = index++; } - template class MatrixPolicy> - inline void State::SetConcentrations( + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetConcentrations( const std::unordered_map>& species_to_concentration) { const int num_grid_cells = conditions_.size(); @@ -58,8 +53,8 @@ namespace micm SetConcentration({ pair.first }, pair.second); } - template class MatrixPolicy> - inline void State::SetConcentration(const Species& species, double concentration) + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetConcentration(const Species& species, double concentration) { auto var = variable_map_.find(species.name_); if (var == variable_map_.end()) @@ -69,8 +64,8 @@ namespace micm variables_[0][variable_map_[species.name_]] = concentration; } - template class MatrixPolicy> - inline void State::SetConcentration(const Species& species, const std::vector& concentration) + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetConcentration(const Species& species, const std::vector& concentration) { auto var = variable_map_.find(species.name_); if (var == variable_map_.end()) @@ -82,16 +77,16 @@ namespace micm variables_[i][i_species] = concentration[i]; } - template class MatrixPolicy> - inline void State::SetCustomRateParameters( + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetCustomRateParameters( const std::unordered_map>& parameters) { for (auto& pair : parameters) SetCustomRateParameter(pair.first, pair.second); } - template class MatrixPolicy> - inline void State::SetCustomRateParameter(const std::string& label, double value) + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetCustomRateParameter(const std::string& label, double value) { auto param = custom_rate_parameter_map_.find(label); if (param == custom_rate_parameter_map_.end()) @@ -101,8 +96,8 @@ namespace micm custom_rate_parameters_[0][param->second] = value; } - template class MatrixPolicy> - inline void State::SetCustomRateParameter(const std::string& label, const std::vector& values) + template class MatrixPolicy, template class SparseMatrixPolicy> + inline void State::SetCustomRateParameter(const std::string& label, const std::vector& values) { auto param = custom_rate_parameter_map_.find(label); if (param == custom_rate_parameter_map_.end()) diff --git a/test/integration/analytical_rosenbrock.cpp b/test/integration/analytical_rosenbrock.cpp index 83dae3188..66d51e5e6 100644 --- a/test/integration/analytical_rosenbrock.cpp +++ b/test/integration/analytical_rosenbrock.cpp @@ -35,630 +35,630 @@ TEST(AnalyticalExamples, TroeSuperStiffButAnalytical) }); } -TEST(AnalyticalExamples, Photolysis) -{ - test_analytical_photolysis>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, PhotolysisSuperStiffButAnalytical) -{ - test_analytical_stiff_photolysis>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, TernaryChemicalActivation) -{ - test_analytical_ternary_chemical_activation>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, TernaryChemicalActivationSuperStiffButAnalytical) -{ - test_analytical_stiff_ternary_chemical_activation>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, Tunneling) -{ - test_analytical_tunneling>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, TunnelingSuperStiffButAnalytical) -{ - test_analytical_stiff_tunneling>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, Arrhenius) -{ - test_analytical_arrhenius>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, ArrheniusSuperStiffButAnalytical) -{ - test_analytical_stiff_arrhenius>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, Branched) -{ - test_analytical_branched>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, BranchedSuperStiffButAnalytical) -{ - test_analytical_stiff_branched>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, Robertson) -{ - test_analytical_robertson>( - [](const micm::System& s, - const std::vector& p) -> micm::RosenbrockSolver - { - return micm::RosenbrockSolver{ - s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() - }; - }); -} - -TEST(AnalyticalExamples, Oregonator) -{ - /* - * I think these are the equations, but I'm really not sure. I don't know how this translates to the jacobian - * and forcing functions used by the ODE book: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f - * A+Y -> X+P - * X+Y -> 2P - * A+X -> 2X+2Z - * 2X -> A+P - * B+Z -> 1/2fY - * - * this problem is described in - * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd - * edition. ed. Springer, Berlin ; New York. Page 3 - * - * solutions are provided here - * https://www.unige.ch/~hairer/testset/testset.html - */ - - auto a = micm::Species("A"); - auto b = micm::Species("B"); - auto c = micm::Species("C"); - - micm::Phase gas_phase{ std::vector{ a, b, c } }; - - micm::Process r1 = micm::Process::create() - .reactants({ a }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) - .phase(gas_phase); - - micm::Process r2 = micm::Process::create() - .reactants({ b }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) - .phase(gas_phase); - - micm::Process r3 = micm::Process::create() - .reactants({ b }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) - .phase(gas_phase); - - auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); - params.relative_tolerance_ = 1e-4; - params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; - Oregonator solver( - micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3 }, params); - - double end = 360; - double time_step = 30; - size_t N = static_cast(end / time_step); - - std::vector> model_concentrations(N + 1, std::vector(3)); - std::vector> analytical_concentrations(13, std::vector(3)); - - model_concentrations[0] = { 1, 2, 3 }; - - analytical_concentrations = { - { 1, 2, 3 }, - { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, - { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, - { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, - { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, - { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, - { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, - { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, - { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, - { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, - { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, - { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, - { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, - }; - - micm::State state = solver.GetState(); - - state.variables_[0] = model_concentrations[0]; - - std::vector times; - times.push_back(0); - for (size_t i_time = 0; i_time < N; ++i_time) - { - double solve_time = time_step + i_time * time_step; - times.push_back(solve_time); - // Model results - double actual_solve = 0; - while (actual_solve < time_step) - { - auto result = solver.Solve(time_step - actual_solve, state); - state.variables_[0] = result.result_.AsVector(); - actual_solve += result.final_time_; - } - model_concentrations[i_time + 1] = state.variables_[0]; - } - - std::vector header = { "time", "A", "B", "C" }; - writeCSV("model_concentrations.csv", header, model_concentrations, times); - std::vector an_times; - an_times.push_back(0); - for (int i = 1; i <= 12; ++i) - { - an_times.push_back(30 * i); - } - writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); - - auto map = state.variable_map_; - - size_t _a = map.at("A"); - size_t _b = map.at("B"); - size_t _c = map.at("C"); - - double tol = 1e-3; - for (size_t i = 0; i < model_concentrations.size(); ++i) - { - double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; - rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; - rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; - } -} - -TEST(AnalyticalExamples, Oregonator2) -{ - /* Equations derived from the forcing function here: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f - * a + b -> ( 1 - (1/77.27)^2 ) b k = 77.27 - * c -> ( 1 / (0.161 * 77.27) ) b k = 0.161 - * b -> ( 77.27 )^2 a k = 1/77.27 - * a -> 2 a + ( 0.161/77.27 ) c k = 77.27 - * a + a -> NULL k = 77.27 * 8.375e-6 - * - * this problem is described in - * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd - * edition. ed. Springer, Berlin ; New York. Page 3 - * - * solutions are provided here - * https://www.unige.ch/~hairer/testset/testset.html - */ - - auto a = micm::Species("A"); - auto b = micm::Species("B"); - auto c = micm::Species("C"); - - micm::Phase gas_phase{ std::vector{ a, b, c } }; - - micm::Process r1 = micm::Process::create() - .reactants({ a, b }) - .products({ yields(b, 1 - std::pow((1 / 77.27), 2)) }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) - .phase(gas_phase); - - micm::Process r2 = micm::Process::create() - .reactants({ c }) - .products({ yields(b, 1 / (0.161 * 77.27)) }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) - .phase(gas_phase); - - micm::Process r3 = micm::Process::create() - .reactants({ b }) - .products({ yields(a, std::pow(77.27, 2)) }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) - .phase(gas_phase); - - micm::Process r4 = micm::Process::create() - .reactants({ a }) - .products({ yields(a, 2), yields(c, 0.161 / 77.27) }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) - .phase(gas_phase); - - micm::Process r5 = micm::Process::create() - .reactants({ a, a }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) - .phase(gas_phase); - - auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); - params.relative_tolerance_ = 1e-4; - params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; - Oregonator solver( - micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), - std::vector{ r1, r2, r3, r4, r5 }, - params); - - double end = 360; - double time_step = 30; - size_t N = static_cast(end / time_step); - - std::vector> model_concentrations(N + 1, std::vector(3)); - std::vector> analytical_concentrations(13, std::vector(3)); - - model_concentrations[0] = { 1, 2, 3 }; - - analytical_concentrations = { - { 1, 2, 3 }, - { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, - { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, - { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, - { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, - { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, - { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, - { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, - { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, - { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, - { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, - { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, - { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, - }; - - micm::State state = solver.GetState(); - - double k1 = 77.27; - double k2 = 0.161; - double k3 = 1 / 77.27; - double k4 = 77.27; - double k5 = 77.27 * 8.375e-6; - - state.SetCustomRateParameter("r1", k1); - state.SetCustomRateParameter("r2", k2); - state.SetCustomRateParameter("r3", k3); - state.SetCustomRateParameter("r4", k4); - state.SetCustomRateParameter("r5", k5); - - state.variables_[0] = model_concentrations[0]; - - std::vector times; - times.push_back(0); - for (size_t i_time = 0; i_time < N; ++i_time) - { - double solve_time = time_step + i_time * time_step; - times.push_back(solve_time); - // Model results - double actual_solve = 0; - while (actual_solve < time_step) - { - auto result = solver.Solve(time_step - actual_solve, state); - state.variables_[0] = result.result_.AsVector(); - actual_solve += result.final_time_; - } - model_concentrations[i_time + 1] = state.variables_[0]; - } - - std::vector header = { "time", "A", "B", "C" }; - writeCSV("model_concentrations.csv", header, model_concentrations, times); - std::vector an_times; - an_times.push_back(0); - for (int i = 1; i <= 12; ++i) - { - an_times.push_back(30 * i); - } - writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); - - auto map = state.variable_map_; - - size_t _a = map.at("A"); - size_t _b = map.at("B"); - size_t _c = map.at("C"); - - double tol = 1e-3; - for (size_t i = 0; i < model_concentrations.size(); ++i) - { - double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; - rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; - rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); - EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; - } -} - -TEST(AnalyticalExamples, HIRES) -{ - /* - * No idea what these equations are - * - * this problem is described in - * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd - * edition. ed. Springer, Berlin ; New York. Page 3 - * - * solutions are provided here - * https://www.unige.ch/~hairer/testset/testset.html - */ - - auto y1 = micm::Species("y1"); - auto y2 = micm::Species("y2"); - auto y3 = micm::Species("y3"); - auto y4 = micm::Species("y4"); - auto y5 = micm::Species("y5"); - auto y6 = micm::Species("y6"); - auto y7 = micm::Species("y7"); - auto y8 = micm::Species("y8"); - - micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4, y5, y6, y7, y8 } }; - - micm::Process r1 = micm::Process::create() - .reactants({ y1 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) - .phase(gas_phase); - micm::Process r2 = micm::Process::create() - .reactants({ y2 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) - .phase(gas_phase); - micm::Process r3 = micm::Process::create() - .reactants({ y3 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) - .phase(gas_phase); - micm::Process r4 = micm::Process::create() - .reactants({ y4 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) - .phase(gas_phase); - micm::Process r5 = micm::Process::create() - .reactants({ y5 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) - .phase(gas_phase); - micm::Process r6 = micm::Process::create() - .reactants({ y6 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r6" })) - .phase(gas_phase); - micm::Process r7 = micm::Process::create() - .reactants({ y7 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r7" })) - .phase(gas_phase); - micm::Process r8 = micm::Process::create() - .reactants({ y8 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r8" })) - .phase(gas_phase); - - auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); - params.relative_tolerance_ = 1e-3; - params.absolute_tolerance_ = params.relative_tolerance_ * 1e-4; - HIRES solver( - micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), - std::vector{ r1, r2, r3, r4, r5, r6, r7, r8 }, - params); - - size_t N = 2; - - std::vector> model_concentrations(N + 1, std::vector(8)); - std::vector> analytical_concentrations(3, std::vector(8)); - - model_concentrations[0] = { 1, 0, 0, 0, 0, 0, 0, 0.0057 }; - - analytical_concentrations = { - { 1, 0, 0, 0, 0, 0, 0, 0.0057 }, - { 0.000737131257332567, - 0.000144248572631618, - 0.000058887297409676, - 0.001175651343283149, - 0.002386356198831330, - 0.006238968252742796, - 0.002849998395185769, - 0.002850001604814231 }, - { 0.000670305503581864, - 0.000130996846986347, - 0.000046862231597733, - 0.001044668020551705, - 0.000594883830951485, - 0.001399628833942774, - 0.001014492757718480, - 0.004685507242281520 }, - }; - - micm::State state = solver.GetState(); - - state.variables_[0] = model_concentrations[0]; - - std::vector times; - times.push_back(0); - double time_step = 321.8122; - for (size_t i_time = 0; i_time < N; ++i_time) - { - double solve_time = time_step + i_time * time_step; - times.push_back(solve_time); - // Model results - double actual_solve = 0; - while (actual_solve < time_step) - { - auto result = solver.Solve(time_step - actual_solve, state); - state.variables_[0] = result.result_.AsVector(); - actual_solve += result.final_time_; - } - model_concentrations[i_time + 1] = state.variables_[0]; - time_step += 100; - } - - std::vector header = { "time", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8" }; - writeCSV("model_concentrations.csv", header, model_concentrations, times); - writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); - - double tol = 1e-5; - for (size_t i = 0; i < model_concentrations.size(); ++i) - { - for (size_t j = 0; j < model_concentrations[0].size(); ++j) - { - double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); - EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol); - } - } -} - -TEST(AnalyticalExamples, E5) -{ - /* - * No idea what these equations are - * - * this problem is described in - * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd - * edition. ed. Springer, Berlin ; New York. Page 3 - * - * solutions are provided here - * https://www.unige.ch/~hairer/testset/testset.html - */ - - auto y1 = micm::Species("y1"); - auto y2 = micm::Species("y2"); - auto y3 = micm::Species("y3"); - auto y4 = micm::Species("y4"); - - micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4 } }; - - micm::Process r1 = micm::Process::create() - .reactants({ y1 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) - .phase(gas_phase); - micm::Process r2 = micm::Process::create() - .reactants({ y2 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) - .phase(gas_phase); - micm::Process r3 = micm::Process::create() - .reactants({ y3 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) - .phase(gas_phase); - micm::Process r4 = micm::Process::create() - .reactants({ y4 }) - .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) - .phase(gas_phase); - - auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); - params.relative_tolerance_ = 1e-2; - params.absolute_tolerance_ = 1.7e-24; - E5 solver( - micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3, r4 }, params); - - size_t N = 7; - - std::vector> model_concentrations(N + 1, std::vector(4)); - std::vector> analytical_concentrations(N + 1, std::vector(4)); - - model_concentrations[0] = { 1.76e-3, 0, 0, 0 }; - - analytical_concentrations = { - { 1.76e-3, 0, 0, 0 }, - { 1.7599259497677897058e-003, 1.3846281519376516449e-011, 7.6370038530073911180e-013, 1.3082581134075777338e-011 }, - { 1.6180769999072942552e-003, 1.3822370304983735443e-010, 8.2515735006838336088e-012, 1.2997212954915352082e-010 }, - { 7.4813208224292220114e-006, 2.3734781561205975019e-012, 2.2123586689581663654e-012, 1.6111948716243113653e-013 }, - { 4.7150333630401632232e-010, 1.8188895860807021729e-014, 1.8188812376786725407e-014, 8.3484020296321693074e-020 }, - { 3.1317148329356996037e-014, 1.4840957952870064294e-016, 1.4840957948345691466e-016, 4.5243728279782625194e-026 }, - { 3.8139035189787091771e-049, 1.0192582567660293322e-020, 1.0192582567660293322e-020, 3.7844935507486221171e-065 }, - { 0.0000000000000000000e-000, 8.8612334976263783420e-023, 8.8612334976263783421e-023, 0.0000000000000000000e-000 } - }; - - micm::State state = solver.GetState(); - - state.variables_[0] = model_concentrations[0]; - - std::vector times; - times.push_back(0); - double time_step = 10; - for (size_t i_time = 0; i_time < N; ++i_time) - { - double solve_time = time_step + i_time * time_step; - times.push_back(solve_time); - // Model results - double actual_solve = 0; - while (actual_solve < time_step) - { - auto result = solver.Solve(time_step - actual_solve, state); - state.variables_[0] = result.result_.AsVector(); - actual_solve += result.final_time_; - } - model_concentrations[i_time + 1] = state.variables_[0]; - time_step *= 100; - } - - std::vector header = { "time", "y1", "y2", "y3", "y4" }; - writeCSV("model_concentrations.csv", header, model_concentrations, times); - writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); - - double tol = 1e-5; - for (size_t i = 0; i < model_concentrations.size(); ++i) - { - for (size_t j = 0; j < model_concentrations[0].size(); ++j) - { - double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); - EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol) - << "difference at (" << i << ", " << j << ")"; - } - } -} \ No newline at end of file +// TEST(AnalyticalExamples, Photolysis) +// { +// test_analytical_photolysis>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, PhotolysisSuperStiffButAnalytical) +// { +// test_analytical_stiff_photolysis>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, TernaryChemicalActivation) +// { +// test_analytical_ternary_chemical_activation>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, TernaryChemicalActivationSuperStiffButAnalytical) +// { +// test_analytical_stiff_ternary_chemical_activation>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, Tunneling) +// { +// test_analytical_tunneling>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, TunnelingSuperStiffButAnalytical) +// { +// test_analytical_stiff_tunneling>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, Arrhenius) +// { +// test_analytical_arrhenius>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, ArrheniusSuperStiffButAnalytical) +// { +// test_analytical_stiff_arrhenius>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, Branched) +// { +// test_analytical_branched>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, BranchedSuperStiffButAnalytical) +// { +// test_analytical_stiff_branched>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, Robertson) +// { +// test_analytical_robertson>( +// [](const micm::System& s, +// const std::vector& p) -> micm::RosenbrockSolver +// { +// return micm::RosenbrockSolver{ +// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() +// }; +// }); +// } + +// TEST(AnalyticalExamples, Oregonator) +// { +// /* +// * I think these are the equations, but I'm really not sure. I don't know how this translates to the jacobian +// * and forcing functions used by the ODE book: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f +// * A+Y -> X+P +// * X+Y -> 2P +// * A+X -> 2X+2Z +// * 2X -> A+P +// * B+Z -> 1/2fY +// * +// * this problem is described in +// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd +// * edition. ed. Springer, Berlin ; New York. Page 3 +// * +// * solutions are provided here +// * https://www.unige.ch/~hairer/testset/testset.html +// */ + +// auto a = micm::Species("A"); +// auto b = micm::Species("B"); +// auto c = micm::Species("C"); + +// micm::Phase gas_phase{ std::vector{ a, b, c } }; + +// micm::Process r1 = micm::Process::create() +// .reactants({ a }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) +// .phase(gas_phase); + +// micm::Process r2 = micm::Process::create() +// .reactants({ b }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) +// .phase(gas_phase); + +// micm::Process r3 = micm::Process::create() +// .reactants({ b }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) +// .phase(gas_phase); + +// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); +// params.relative_tolerance_ = 1e-4; +// params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; +// Oregonator solver( +// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3 }, params); + +// double end = 360; +// double time_step = 30; +// size_t N = static_cast(end / time_step); + +// std::vector> model_concentrations(N + 1, std::vector(3)); +// std::vector> analytical_concentrations(13, std::vector(3)); + +// model_concentrations[0] = { 1, 2, 3 }; + +// analytical_concentrations = { +// { 1, 2, 3 }, +// { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, +// { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, +// { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, +// { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, +// { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, +// { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, +// { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, +// { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, +// { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, +// { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, +// { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, +// { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, +// }; + +// auto state = solver.GetState(); + +// state.variables_[0] = model_concentrations[0]; + +// std::vector times; +// times.push_back(0); +// for (size_t i_time = 0; i_time < N; ++i_time) +// { +// double solve_time = time_step + i_time * time_step; +// times.push_back(solve_time); +// // Model results +// double actual_solve = 0; +// while (actual_solve < time_step) +// { +// auto result = solver.Solve(time_step - actual_solve, state); +// state.variables_[0] = result.result_.AsVector(); +// actual_solve += result.final_time_; +// } +// model_concentrations[i_time + 1] = state.variables_[0]; +// } + +// std::vector header = { "time", "A", "B", "C" }; +// writeCSV("model_concentrations.csv", header, model_concentrations, times); +// std::vector an_times; +// an_times.push_back(0); +// for (int i = 1; i <= 12; ++i) +// { +// an_times.push_back(30 * i); +// } +// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); + +// auto map = state.variable_map_; + +// size_t _a = map.at("A"); +// size_t _b = map.at("B"); +// size_t _c = map.at("C"); + +// double tol = 1e-3; +// for (size_t i = 0; i < model_concentrations.size(); ++i) +// { +// double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; +// rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; +// rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; +// } +// } + +// TEST(AnalyticalExamples, Oregonator2) +// { +// /* Equations derived from the forcing function here: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f +// * a + b -> ( 1 - (1/77.27)^2 ) b k = 77.27 +// * c -> ( 1 / (0.161 * 77.27) ) b k = 0.161 +// * b -> ( 77.27 )^2 a k = 1/77.27 +// * a -> 2 a + ( 0.161/77.27 ) c k = 77.27 +// * a + a -> NULL k = 77.27 * 8.375e-6 +// * +// * this problem is described in +// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd +// * edition. ed. Springer, Berlin ; New York. Page 3 +// * +// * solutions are provided here +// * https://www.unige.ch/~hairer/testset/testset.html +// */ + +// auto a = micm::Species("A"); +// auto b = micm::Species("B"); +// auto c = micm::Species("C"); + +// micm::Phase gas_phase{ std::vector{ a, b, c } }; + +// micm::Process r1 = micm::Process::create() +// .reactants({ a, b }) +// .products({ yields(b, 1 - std::pow((1 / 77.27), 2)) }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) +// .phase(gas_phase); + +// micm::Process r2 = micm::Process::create() +// .reactants({ c }) +// .products({ yields(b, 1 / (0.161 * 77.27)) }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) +// .phase(gas_phase); + +// micm::Process r3 = micm::Process::create() +// .reactants({ b }) +// .products({ yields(a, std::pow(77.27, 2)) }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) +// .phase(gas_phase); + +// micm::Process r4 = micm::Process::create() +// .reactants({ a }) +// .products({ yields(a, 2), yields(c, 0.161 / 77.27) }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) +// .phase(gas_phase); + +// micm::Process r5 = micm::Process::create() +// .reactants({ a, a }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) +// .phase(gas_phase); + +// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); +// params.relative_tolerance_ = 1e-4; +// params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; +// Oregonator solver( +// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), +// std::vector{ r1, r2, r3, r4, r5 }, +// params); + +// double end = 360; +// double time_step = 30; +// size_t N = static_cast(end / time_step); + +// std::vector> model_concentrations(N + 1, std::vector(3)); +// std::vector> analytical_concentrations(13, std::vector(3)); + +// model_concentrations[0] = { 1, 2, 3 }; + +// analytical_concentrations = { +// { 1, 2, 3 }, +// { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, +// { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, +// { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, +// { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, +// { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, +// { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, +// { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, +// { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, +// { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, +// { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, +// { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, +// { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, +// }; + +// auto state = solver.GetState(); + +// double k1 = 77.27; +// double k2 = 0.161; +// double k3 = 1 / 77.27; +// double k4 = 77.27; +// double k5 = 77.27 * 8.375e-6; + +// state.SetCustomRateParameter("r1", k1); +// state.SetCustomRateParameter("r2", k2); +// state.SetCustomRateParameter("r3", k3); +// state.SetCustomRateParameter("r4", k4); +// state.SetCustomRateParameter("r5", k5); + +// state.variables_[0] = model_concentrations[0]; + +// std::vector times; +// times.push_back(0); +// for (size_t i_time = 0; i_time < N; ++i_time) +// { +// double solve_time = time_step + i_time * time_step; +// times.push_back(solve_time); +// // Model results +// double actual_solve = 0; +// while (actual_solve < time_step) +// { +// auto result = solver.Solve(time_step - actual_solve, state); +// state.variables_[0] = result.result_.AsVector(); +// actual_solve += result.final_time_; +// } +// model_concentrations[i_time + 1] = state.variables_[0]; +// } + +// std::vector header = { "time", "A", "B", "C" }; +// writeCSV("model_concentrations.csv", header, model_concentrations, times); +// std::vector an_times; +// an_times.push_back(0); +// for (int i = 1; i <= 12; ++i) +// { +// an_times.push_back(30 * i); +// } +// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); + +// auto map = state.variable_map_; + +// size_t _a = map.at("A"); +// size_t _b = map.at("B"); +// size_t _c = map.at("C"); + +// double tol = 1e-3; +// for (size_t i = 0; i < model_concentrations.size(); ++i) +// { +// double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; +// rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; +// rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); +// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; +// } +// } + +// TEST(AnalyticalExamples, HIRES) +// { +// /* +// * No idea what these equations are +// * +// * this problem is described in +// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd +// * edition. ed. Springer, Berlin ; New York. Page 3 +// * +// * solutions are provided here +// * https://www.unige.ch/~hairer/testset/testset.html +// */ + +// auto y1 = micm::Species("y1"); +// auto y2 = micm::Species("y2"); +// auto y3 = micm::Species("y3"); +// auto y4 = micm::Species("y4"); +// auto y5 = micm::Species("y5"); +// auto y6 = micm::Species("y6"); +// auto y7 = micm::Species("y7"); +// auto y8 = micm::Species("y8"); + +// micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4, y5, y6, y7, y8 } }; + +// micm::Process r1 = micm::Process::create() +// .reactants({ y1 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) +// .phase(gas_phase); +// micm::Process r2 = micm::Process::create() +// .reactants({ y2 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) +// .phase(gas_phase); +// micm::Process r3 = micm::Process::create() +// .reactants({ y3 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) +// .phase(gas_phase); +// micm::Process r4 = micm::Process::create() +// .reactants({ y4 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) +// .phase(gas_phase); +// micm::Process r5 = micm::Process::create() +// .reactants({ y5 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) +// .phase(gas_phase); +// micm::Process r6 = micm::Process::create() +// .reactants({ y6 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r6" })) +// .phase(gas_phase); +// micm::Process r7 = micm::Process::create() +// .reactants({ y7 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r7" })) +// .phase(gas_phase); +// micm::Process r8 = micm::Process::create() +// .reactants({ y8 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r8" })) +// .phase(gas_phase); + +// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); +// params.relative_tolerance_ = 1e-3; +// params.absolute_tolerance_ = params.relative_tolerance_ * 1e-4; +// HIRES solver( +// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), +// std::vector{ r1, r2, r3, r4, r5, r6, r7, r8 }, +// params); + +// size_t N = 2; + +// std::vector> model_concentrations(N + 1, std::vector(8)); +// std::vector> analytical_concentrations(3, std::vector(8)); + +// model_concentrations[0] = { 1, 0, 0, 0, 0, 0, 0, 0.0057 }; + +// analytical_concentrations = { +// { 1, 0, 0, 0, 0, 0, 0, 0.0057 }, +// { 0.000737131257332567, +// 0.000144248572631618, +// 0.000058887297409676, +// 0.001175651343283149, +// 0.002386356198831330, +// 0.006238968252742796, +// 0.002849998395185769, +// 0.002850001604814231 }, +// { 0.000670305503581864, +// 0.000130996846986347, +// 0.000046862231597733, +// 0.001044668020551705, +// 0.000594883830951485, +// 0.001399628833942774, +// 0.001014492757718480, +// 0.004685507242281520 }, +// }; + +// auto state = solver.GetState(); + +// state.variables_[0] = model_concentrations[0]; + +// std::vector times; +// times.push_back(0); +// double time_step = 321.8122; +// for (size_t i_time = 0; i_time < N; ++i_time) +// { +// double solve_time = time_step + i_time * time_step; +// times.push_back(solve_time); +// // Model results +// double actual_solve = 0; +// while (actual_solve < time_step) +// { +// auto result = solver.Solve(time_step - actual_solve, state); +// state.variables_[0] = result.result_.AsVector(); +// actual_solve += result.final_time_; +// } +// model_concentrations[i_time + 1] = state.variables_[0]; +// time_step += 100; +// } + +// std::vector header = { "time", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8" }; +// writeCSV("model_concentrations.csv", header, model_concentrations, times); +// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); + +// double tol = 1e-5; +// for (size_t i = 0; i < model_concentrations.size(); ++i) +// { +// for (size_t j = 0; j < model_concentrations[0].size(); ++j) +// { +// double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); +// EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol); +// } +// } +// } + +// TEST(AnalyticalExamples, E5) +// { +// /* +// * No idea what these equations are +// * +// * this problem is described in +// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd +// * edition. ed. Springer, Berlin ; New York. Page 3 +// * +// * solutions are provided here +// * https://www.unige.ch/~hairer/testset/testset.html +// */ + +// auto y1 = micm::Species("y1"); +// auto y2 = micm::Species("y2"); +// auto y3 = micm::Species("y3"); +// auto y4 = micm::Species("y4"); + +// micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4 } }; + +// micm::Process r1 = micm::Process::create() +// .reactants({ y1 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) +// .phase(gas_phase); +// micm::Process r2 = micm::Process::create() +// .reactants({ y2 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) +// .phase(gas_phase); +// micm::Process r3 = micm::Process::create() +// .reactants({ y3 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) +// .phase(gas_phase); +// micm::Process r4 = micm::Process::create() +// .reactants({ y4 }) +// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) +// .phase(gas_phase); + +// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); +// params.relative_tolerance_ = 1e-2; +// params.absolute_tolerance_ = 1.7e-24; +// E5 solver( +// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3, r4 }, params); + +// size_t N = 7; + +// std::vector> model_concentrations(N + 1, std::vector(4)); +// std::vector> analytical_concentrations(N + 1, std::vector(4)); + +// model_concentrations[0] = { 1.76e-3, 0, 0, 0 }; + +// analytical_concentrations = { +// { 1.76e-3, 0, 0, 0 }, +// { 1.7599259497677897058e-003, 1.3846281519376516449e-011, 7.6370038530073911180e-013, 1.3082581134075777338e-011 }, +// { 1.6180769999072942552e-003, 1.3822370304983735443e-010, 8.2515735006838336088e-012, 1.2997212954915352082e-010 }, +// { 7.4813208224292220114e-006, 2.3734781561205975019e-012, 2.2123586689581663654e-012, 1.6111948716243113653e-013 }, +// { 4.7150333630401632232e-010, 1.8188895860807021729e-014, 1.8188812376786725407e-014, 8.3484020296321693074e-020 }, +// { 3.1317148329356996037e-014, 1.4840957952870064294e-016, 1.4840957948345691466e-016, 4.5243728279782625194e-026 }, +// { 3.8139035189787091771e-049, 1.0192582567660293322e-020, 1.0192582567660293322e-020, 3.7844935507486221171e-065 }, +// { 0.0000000000000000000e-000, 8.8612334976263783420e-023, 8.8612334976263783421e-023, 0.0000000000000000000e-000 } +// }; + +// auto state = solver.GetState(); + +// state.variables_[0] = model_concentrations[0]; + +// std::vector times; +// times.push_back(0); +// double time_step = 10; +// for (size_t i_time = 0; i_time < N; ++i_time) +// { +// double solve_time = time_step + i_time * time_step; +// times.push_back(solve_time); +// // Model results +// double actual_solve = 0; +// while (actual_solve < time_step) +// { +// auto result = solver.Solve(time_step - actual_solve, state); +// state.variables_[0] = result.result_.AsVector(); +// actual_solve += result.final_time_; +// } +// model_concentrations[i_time + 1] = state.variables_[0]; +// time_step *= 100; +// } + +// std::vector header = { "time", "y1", "y2", "y3", "y4" }; +// writeCSV("model_concentrations.csv", header, model_concentrations, times); +// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); + +// double tol = 1e-5; +// for (size_t i = 0; i < model_concentrations.size(); ++i) +// { +// for (size_t j = 0; j < model_concentrations[0].size(); ++j) +// { +// double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); +// EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol) +// << "difference at (" << i << ", " << j << ")"; +// } +// } +// } \ No newline at end of file diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index 01da9b6e7..a0c422b9c 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -132,7 +132,7 @@ TEST(ChapmanIntegration, CanBuildChapmanSystem) micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() }; - micm::State state = solver.GetState(); + auto state = solver.GetState(); std::vector concentrations{ 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.3, 0.3, 0.3 }; state.variables_[0] = concentrations; diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index bbf2e6b45..4dd717f77 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -26,10 +26,17 @@ class E5 : public micm::RosenbrockSolverjacobian_ = builder; - for (std::size_t i = 0; i < this->jacobian_[0].size(); ++i) - this->jacobian_diagonal_elements_.push_back(this->jacobian_.VectorIndex(0, i, i)); - this->linear_solver_ = LinearSolverPolicy(this->jacobian_, 1.0e-30); + SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); + + std::vector jacobian_diagonal_elements; + for (std::size_t i = 0; i < jacobian[0].size(); ++i) + jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); + + this->state_parameters_ = { + .jacobian_diagonal_elements_ = jacobian_diagonal_elements + }; + + this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); } ~E5() diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 5b682cafc..2686843f3 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -27,10 +27,17 @@ class HIRES : public micm::RosenbrockSolverjacobian_ = builder; - for (std::size_t i = 0; i < this->jacobian_[0].size(); ++i) - this->jacobian_diagonal_elements_.push_back(this->jacobian_.VectorIndex(0, i, i)); - this->linear_solver_ = LinearSolverPolicy(this->jacobian_, 1.0e-30); + SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); + + std::vector jacobian_diagonal_elements; + for (std::size_t i = 0; i < jacobian[0].size(); ++i) + jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); + + this->state_parameters_ = { + .jacobian_diagonal_elements_ = jacobian_diagonal_elements + }; + + this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); } ~HIRES() diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index 27b74f69f..cf9dfd787 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -27,10 +27,17 @@ class Oregonator : public micm::RosenbrockSolverjacobian_ = builder; - for (std::size_t i = 0; i < this->jacobian_[0].size(); ++i) - this->jacobian_diagonal_elements_.push_back(this->jacobian_.VectorIndex(0, i, i)); - this->linear_solver_ = LinearSolverPolicy(this->jacobian_, 1.0e-30); + SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); + + std::vector jacobian_diagonal_elements; + for (std::size_t i = 0; i < jacobian[0].size(); ++i) + jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); + + this->state_parameters_ = { + .jacobian_diagonal_elements_ = jacobian_diagonal_elements + }; + + this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); } ~Oregonator() diff --git a/test/kpp/test_kpp_to_micm.cpp b/test/kpp/test_kpp_to_micm.cpp index bcff1d90a..62a306cc6 100644 --- a/test/kpp/test_kpp_to_micm.cpp +++ b/test/kpp/test_kpp_to_micm.cpp @@ -16,8 +16,8 @@ void print_header() << "," << std::setw(11) << "O1D" << std::endl; } -template class T> -void print_state(double time, micm::State& state) +template class T, template class D> +void print_state(double time, micm::State& state) { std::ios oldState(nullptr); oldState.copyfmt(std::cout); diff --git a/test/regression/RosenbrockChapman/regression_test_dforce_dy_policy.hpp b/test/regression/RosenbrockChapman/regression_test_dforce_dy_policy.hpp index f95bb15a0..a86c2599f 100644 --- a/test/regression/RosenbrockChapman/regression_test_dforce_dy_policy.hpp +++ b/test/regression/RosenbrockChapman/regression_test_dforce_dy_policy.hpp @@ -25,7 +25,7 @@ void testJacobian(OdeSolverPolicy& solver) auto& rate_const_vec = state.rate_constants_.AsVector(); std::generate(state_vec.begin(), state_vec.end(), [&]() { return dist(engine); }); - auto& jacobian = solver.jacobian_; + auto& jacobian = state.jacobian_; solver.CalculateJacobian(state.rate_constants_, state.variables_, jacobian); for (std::size_t i{}; i < 3; ++i) diff --git a/test/tutorial/test_but_how_fast_is_it.cpp b/test/tutorial/test_but_how_fast_is_it.cpp index 0cb133a83..d1bd06f84 100644 --- a/test/tutorial/test_but_how_fast_is_it.cpp +++ b/test/tutorial/test_but_how_fast_is_it.cpp @@ -44,7 +44,7 @@ int main() RosenbrockSolverParameters::three_stage_rosenbrock_parameters( 3, false) }; - State state = solver.GetState(); + auto state = solver.GetState(); // mol m-3 state.SetConcentration(a, std::vector{ 1, 2, 0.5 }); diff --git a/test/tutorial/test_multiple_grid_cells.cpp b/test/tutorial/test_multiple_grid_cells.cpp index 57b17c691..d452149b0 100644 --- a/test/tutorial/test_multiple_grid_cells.cpp +++ b/test/tutorial/test_multiple_grid_cells.cpp @@ -21,8 +21,8 @@ void print_header() << "," << std::setw(10) << "C" << std::endl; } -template class T> -void print_state(double time, State& state) +template class T, template class D> +void print_state(double time, State& state) { std::ios oldState(nullptr); oldState.copyfmt(std::cout); @@ -82,7 +82,7 @@ int main() micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters(3, false) }; - State state = solver.GetState(); + auto state = solver.GetState(); // mol m-3 state.SetConcentration(a, std::vector{ 1, 2, 0.5 }); diff --git a/test/tutorial/test_rate_constants_user_defined_by_hand.cpp b/test/tutorial/test_rate_constants_user_defined_by_hand.cpp index 6938c20ee..0563ae57a 100644 --- a/test/tutorial/test_rate_constants_user_defined_by_hand.cpp +++ b/test/tutorial/test_rate_constants_user_defined_by_hand.cpp @@ -33,8 +33,8 @@ void print_header() << "," << std::setw(10) << "G" << std::endl; } -template class T> -void print_state(double time, State& state) +template class T, template class D> +void print_state(double time, State& state) { std::ios oldState(nullptr); oldState.copyfmt(std::cout); diff --git a/test/tutorial/test_rate_constants_user_defined_with_config.cpp b/test/tutorial/test_rate_constants_user_defined_with_config.cpp index 2d0218ecf..2a1bfec61 100644 --- a/test/tutorial/test_rate_constants_user_defined_with_config.cpp +++ b/test/tutorial/test_rate_constants_user_defined_with_config.cpp @@ -33,8 +33,8 @@ void print_header() << "," << std::setw(10) << "G" << std::endl; } -template class T> -void print_state(double time, State& state) +template class T, template class D> +void print_state(double time, State& state) { std::ios oldState(nullptr); oldState.copyfmt(std::cout); diff --git a/test/tutorial/test_solver_configuration.cpp b/test/tutorial/test_solver_configuration.cpp index 7f208005b..6a8c04f66 100644 --- a/test/tutorial/test_solver_configuration.cpp +++ b/test/tutorial/test_solver_configuration.cpp @@ -21,8 +21,8 @@ void print_header() << "," << std::setw(10) << "C" << std::endl; } -template class T> -void print_state(double time, State& state) +template class T, template class D> +void print_state(double time, State& state) { std::ios oldState(nullptr); oldState.copyfmt(std::cout); @@ -40,7 +40,7 @@ void print_state(double time, State& state) template void test_solver_type(T solver) { - State state = solver.GetState(); + auto state = solver.GetState(); // mol m-3 state.variables_[0] = {1, 0, 0}; @@ -66,7 +66,7 @@ void test_solver_type(T solver) print_header(); print_state(0, state); - typename T::SolverStats total_stats; + SolverStats total_stats; std::chrono::duration total_solve_time = std::chrono::nanoseconds::zero();; diff --git a/test/unit/process/test_process_set.cpp b/test/unit/process/test_process_set.cpp index 265008ce3..95a57fbba 100644 --- a/test/unit/process/test_process_set.cpp +++ b/test/unit/process/test_process_set.cpp @@ -35,7 +35,7 @@ TEST(ProcessSet, Matrix) { testProcessSet( [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); } @@ -43,19 +43,19 @@ TEST(ProcessSet, VectorMatrix) { testProcessSet( [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); } @@ -66,20 +66,20 @@ TEST(RandomProcessSet, Matrix) 500, 400, [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); testRandomSystem( 3000, 300, 200, [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); testRandomSystem( 4000, 100, 80, [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { - return micm::ProcessSet{ processes, state }; + return micm::ProcessSet{ processes, state.variable_map_ }; }); } \ No newline at end of file diff --git a/test/unit/process/test_process_set_policy.hpp b/test/unit/process/test_process_set_policy.hpp index 1e050b006..a301d94a8 100644 --- a/test/unit/process/test_process_set_policy.hpp +++ b/test/unit/process/test_process_set_policy.hpp @@ -24,7 +24,7 @@ void testProcessSet( micm::Phase gas_phase{ std::vector{ foo, bar, baz, quz, quuz } }; - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3 } }; @@ -134,7 +134,7 @@ void testRandomSystem( species_names.push_back(std::to_string(i)); } micm::Phase gas_phase{ species }; - micm::State state{ micm::StateParameters{ .state_variable_names_{ species_names }, + micm::State state{ micm::StateParameters{ .variable_names_{ species_names }, .number_of_grid_cells_ = n_cells, .number_of_rate_constants_ = n_reactions } }; std::vector processes{}; diff --git a/test/unit/solver/test_rosenbrock.cpp b/test/unit/solver/test_rosenbrock.cpp index e2e019b26..85899cf64 100644 --- a/test/unit/solver/test_rosenbrock.cpp +++ b/test/unit/solver/test_rosenbrock.cpp @@ -53,7 +53,7 @@ template class MatrixPolicy, template class SparseMatrixP void testAlphaMinusJacobian(std::size_t number_of_grid_cells) { auto solver = getSolver(number_of_grid_cells); - auto jacobian = solver.jacobian_; + auto jacobian = solver.GetState().jacobian_; EXPECT_EQ(jacobian.size(), number_of_grid_cells); EXPECT_EQ(jacobian[0].size(), 5); diff --git a/test/unit/solver/test_state.cpp b/test/unit/solver/test_state.cpp index 053ea1bfd..0143cfa3c 100644 --- a/test/unit/solver/test_state.cpp +++ b/test/unit/solver/test_state.cpp @@ -4,7 +4,7 @@ TEST(State, Constructor) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = 3, .number_of_rate_constants_ = 10 } }; @@ -26,7 +26,7 @@ TEST(State, Constructor) TEST(State, SettingSingleConcentrationWithInvalidArgumentsThowsException) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = 3, .number_of_rate_constants_ = 10 } }; @@ -39,7 +39,7 @@ TEST(State, SettingSingleConcentrationWithInvalidArgumentsThowsException) TEST(State, SetSingleConcentration) { { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = 3, .number_of_rate_constants_ = 10 } }; @@ -49,7 +49,7 @@ TEST(State, SetSingleConcentration) EXPECT_EQ(state.variables_[i][state.variable_map_["bar"]], concentrations[i]); } { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = 10 } }; @@ -60,7 +60,7 @@ TEST(State, SetSingleConcentration) TEST(State, SettingConcentrationsWithInvalidArguementsThrowsException) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = 3, .number_of_rate_constants_ = 10 } }; @@ -77,7 +77,7 @@ TEST(State, SetConcentrations) uint32_t num_grid_cells = 3; uint32_t num_species = 4; - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "quux", "corge" }, .number_of_grid_cells_ = num_grid_cells, .number_of_rate_constants_ = 10 } }; @@ -106,7 +106,7 @@ TEST(State, SetConcentrations) TEST(State, SettingCustomRateParameterWithInvalidVectorSizeThrowsException) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, .number_of_grid_cells_ = 3, .number_of_rate_constants_ = 10 } }; @@ -121,7 +121,7 @@ TEST(State, SettingCustomRateParameterWithInvalidVectorSizeThrowsException) TEST(State, SettingCustomRateParameterWithInvalidLabelThrowsException) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = 10 } }; @@ -136,7 +136,7 @@ TEST(State, SettingCustomRateParameterWithInvalidLabelThrowsException) TEST(State, SetCustomRateParameter) { - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = 10 } }; @@ -149,7 +149,7 @@ TEST(State, SetCustomRateParameters) { uint32_t num_grid_cells = 3; - micm::State state{ micm::StateParameters{ .state_variable_names_{ "foo", "bar", "baz", "quz" }, + micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, .number_of_grid_cells_ = num_grid_cells, .number_of_rate_constants_ = 10 } }; From f81d44db5fbb5cdeeac7e3ba7d9ec5eb5d5170fe Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Fri, 20 Oct 2023 16:15:06 -0500 Subject: [PATCH 03/30] moving L and U to state --- include/micm/solver/linear_solver.hpp | 10 +- include/micm/solver/linear_solver.inl | 54 +- include/micm/solver/rosenbrock.hpp | 2 +- include/micm/solver/rosenbrock.inl | 16 +- include/micm/solver/state.hpp | 2 + test/integration/analytical_rosenbrock.cpp | 1254 ++++++++--------- test/integration/e5.hpp | 12 +- test/integration/hires.hpp | 12 +- test/integration/oregonator.hpp | 12 +- .../unit/solver/test_linear_solver_policy.hpp | 21 +- 10 files changed, 725 insertions(+), 670 deletions(-) diff --git a/include/micm/solver/linear_solver.hpp b/include/micm/solver/linear_solver.hpp index 2a53386cf..72a616f14 100644 --- a/include/micm/solver/linear_solver.hpp +++ b/include/micm/solver/linear_solver.hpp @@ -49,8 +49,6 @@ namespace micm std::vector> Uij_xj_; LuDecompositionPolicy lu_decomp_; - SparseMatrixPolicy lower_matrix_; - SparseMatrixPolicy upper_matrix_; public: /// @brief default constructor @@ -71,15 +69,17 @@ namespace micm const std::function&)> create_lu_decomp); /// @brief Decompose the matrix into upper and lower triangular matrices - void Factor(const SparseMatrixPolicy& matrix); + void Factor(const SparseMatrixPolicy& matrix, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); /// @brief Solve for x in Ax = b template class MatrixPolicy> requires(!VectorizableDense> || !VectorizableSparse>) - void Solve(const MatrixPolicy& b, MatrixPolicy& x); + void Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); template class MatrixPolicy> requires(VectorizableDense> && VectorizableSparse>) - void Solve(const MatrixPolicy& b, MatrixPolicy& x); + void Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); + + std::pair, SparseMatrixPolicy> GetLUMatrices(const SparseMatrixPolicy& matrix, T initial_value) const; }; } // namespace micm diff --git a/include/micm/solver/linear_solver.inl b/include/micm/solver/linear_solver.inl index ec6ebbad3..09e405166 100644 --- a/include/micm/solver/linear_solver.inl +++ b/include/micm/solver/linear_solver.inl @@ -72,55 +72,56 @@ namespace micm lu_decomp_(create_lu_decomp(matrix)) { auto lu = lu_decomp_.GetLUMatrices(matrix, initial_value); - lower_matrix_ = std::move(lu.first); - upper_matrix_ = std::move(lu.second); - for (std::size_t i = 0; i < lower_matrix_[0].size(); ++i) + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + for (std::size_t i = 0; i < lower_matrix[0].size(); ++i) { std::size_t nLij = 0; - for (std::size_t j_id = lower_matrix_.RowStartVector()[i]; j_id < lower_matrix_.RowStartVector()[i + 1]; ++j_id) + for (std::size_t j_id = lower_matrix.RowStartVector()[i]; j_id < lower_matrix.RowStartVector()[i + 1]; ++j_id) { - std::size_t j = lower_matrix_.RowIdsVector()[j_id]; + std::size_t j = lower_matrix.RowIdsVector()[j_id]; if (j >= i) break; - Lij_yj_.push_back(std::make_pair(lower_matrix_.VectorIndex(0, i, j), j)); + Lij_yj_.push_back(std::make_pair(lower_matrix.VectorIndex(0, i, j), j)); ++nLij; } // There must always be a non-zero element on the diagonal - nLij_Lii_.push_back(std::make_pair(nLij, lower_matrix_.VectorIndex(0, i, i))); + nLij_Lii_.push_back(std::make_pair(nLij, lower_matrix.VectorIndex(0, i, i))); } - for (std::size_t i = upper_matrix_[0].size() - 1; i != static_cast(-1); --i) + for (std::size_t i = upper_matrix[0].size() - 1; i != static_cast(-1); --i) { std::size_t nUij = 0; - for (std::size_t j_id = upper_matrix_.RowStartVector()[i]; j_id < upper_matrix_.RowStartVector()[i + 1]; ++j_id) + for (std::size_t j_id = upper_matrix.RowStartVector()[i]; j_id < upper_matrix.RowStartVector()[i + 1]; ++j_id) { - std::size_t j = upper_matrix_.RowIdsVector()[j_id]; + std::size_t j = upper_matrix.RowIdsVector()[j_id]; if (j <= i) continue; - Uij_xj_.push_back(std::make_pair(upper_matrix_.VectorIndex(0, i, j), j)); + Uij_xj_.push_back(std::make_pair(upper_matrix.VectorIndex(0, i, j), j)); ++nUij; } // There must always be a non-zero element on the diagonal - nUij_Uii_.push_back(std::make_pair(nUij, upper_matrix_.VectorIndex(0, i, i))); + nUij_Uii_.push_back(std::make_pair(nUij, upper_matrix.VectorIndex(0, i, i))); } }; + template class SparseMatrixPolicy, class LuDecompositionPolicy> - inline void LinearSolver::Factor(const SparseMatrixPolicy& matrix) + inline void LinearSolver::Factor(const SparseMatrixPolicy& matrix, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix) { - lu_decomp_.template Decompose(matrix, lower_matrix_, upper_matrix_); + lu_decomp_.template Decompose(matrix, lower_matrix, upper_matrix); } template class SparseMatrixPolicy, class LuDecompositionPolicy> template class MatrixPolicy> requires(!VectorizableDense> || !VectorizableSparse>) - inline void LinearSolver::Solve(const MatrixPolicy& b, MatrixPolicy& x) + inline void LinearSolver::Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix) { for (std::size_t i_cell = 0; i_cell < b.size(); ++i_cell) { auto b_cell = b[i_cell]; auto x_cell = x[i_cell]; - const std::size_t lower_grid_offset = i_cell * lower_matrix_.FlatBlockSize(); - const std::size_t upper_grid_offset = i_cell * upper_matrix_.FlatBlockSize(); + const std::size_t lower_grid_offset = i_cell * lower_matrix.FlatBlockSize(); + const std::size_t upper_grid_offset = i_cell * upper_matrix.FlatBlockSize(); auto& y_cell = x_cell; // Alias x for consistency with equations, but to reuse memory { auto b_elem = b_cell.begin(); @@ -131,10 +132,10 @@ namespace micm *y_elem = *(b_elem++); for (std::size_t i = 0; i < nLij_Lii.first; ++i) { - *y_elem -= lower_matrix_.AsVector()[lower_grid_offset + (*Lij_yj).first] * y_cell[(*Lij_yj).second]; + *y_elem -= lower_matrix.AsVector()[lower_grid_offset + (*Lij_yj).first] * y_cell[(*Lij_yj).second]; ++Lij_yj; } - *(y_elem++) /= lower_matrix_.AsVector()[lower_grid_offset + nLij_Lii.second]; + *(y_elem++) /= lower_matrix.AsVector()[lower_grid_offset + nLij_Lii.second]; } } { @@ -151,12 +152,12 @@ namespace micm for (std::size_t i = 0; i < nUij_Uii.first; ++i) { - *x_elem -= upper_matrix_.AsVector()[upper_grid_offset + (*Uij_xj).first] * x_cell[(*Uij_xj).second]; + *x_elem -= upper_matrix.AsVector()[upper_grid_offset + (*Uij_xj).first] * x_cell[(*Uij_xj).second]; ++Uij_xj; } // don't iterate before the beginning of the vector - *(x_elem) /= upper_matrix_.AsVector()[upper_grid_offset + nUij_Uii.second]; + *(x_elem) /= upper_matrix.AsVector()[upper_grid_offset + nUij_Uii.second]; if (x_elem != x_cell.begin()) { --x_elem; @@ -169,7 +170,7 @@ namespace micm template class SparseMatrixPolicy, class LuDecompositionPolicy> template class MatrixPolicy> requires(VectorizableDense> && VectorizableSparse>) - inline void LinearSolver::Solve(const MatrixPolicy& b, MatrixPolicy& x) + inline void LinearSolver::Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix) { const std::size_t n_cells = b.GroupVectorSize(); // Loop over groups of blocks @@ -178,9 +179,9 @@ namespace micm auto b_group = std::next(b.AsVector().begin(), i_group * b.GroupSize()); auto x_group = std::next(x.AsVector().begin(), i_group * x.GroupSize()); auto L_group = - std::next(lower_matrix_.AsVector().begin(), i_group * lower_matrix_.GroupSize(lower_matrix_.FlatBlockSize())); + std::next(lower_matrix.AsVector().begin(), i_group * lower_matrix.GroupSize(lower_matrix.FlatBlockSize())); auto U_group = - std::next(upper_matrix_.AsVector().begin(), i_group * upper_matrix_.GroupSize(upper_matrix_.FlatBlockSize())); + std::next(upper_matrix.AsVector().begin(), i_group * upper_matrix.GroupSize(upper_matrix.FlatBlockSize())); auto y_group = x_group; // Alias x for consistency with equations, but to reuse memory { auto b_elem = b_group; @@ -229,4 +230,9 @@ namespace micm } } + template class SparseMatrixPolicy, class LuDecompositionPolicy> + std::pair, SparseMatrixPolicy> LinearSolver::GetLUMatrices(const SparseMatrixPolicy& matrix, T initial_value) const { + return lu_decomp_.GetLUMatrices(matrix, initial_value); + } + } // namespace micm \ No newline at end of file diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index dc30f5887..46b4d0b52 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -284,7 +284,7 @@ namespace micm /// @param singular indicates if the matrix is singular /// @param number_densities constituent concentration (molec/cm^3) /// @param rate_constants Rate constants for each process (molecule/cm3)^(n-1) s-1 - void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities, SolverStats& stats, SparseMatrixPolicy jacobian); + void LinearFactor(double& H, const double gamma, bool& singular, const MatrixPolicy& number_densities, SolverStats& stats, State& state); protected: /// @brief Computes the scaled norm of the vector errors diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 7c20f2afa..aed8b496e 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -536,12 +536,19 @@ namespace micm inline State RosenbrockSolver::GetState() const { auto state = State{ state_parameters_ }; + state.jacobian_ = build_jacobian( state_parameters_.nonzero_jacobian_elements_, state_parameters_.number_of_grid_cells_, system_.StateSize() ); + auto lu = linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + state.lower_matrix_ = lower_matrix; + state.upper_matrix_ = upper_matrix; + return state; } @@ -611,7 +618,7 @@ namespace micm { bool is_singular{ false }; // Form and factor the rosenbrock ode jacobian - TIMED_METHOD(stats.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y, stats, state.jacobian_); + TIMED_METHOD(stats.total_linear_factor_time, time_it, LinearFactor, H, parameters_.gamma_[0], is_singular, Y, stats, state); if (is_singular) { result.state_ = SolverState::RepeatedlySingularMatrix; @@ -647,7 +654,7 @@ namespace micm K[stage].ForEach([&](double& iKstage, double& iKj) { iKstage += HC * iKj; }, K[j]); } temp.AsVector().assign(K[stage].AsVector().begin(), K[stage].AsVector().end()); - TIMED_METHOD(stats.total_linear_solve_time, time_it, linear_solver_.template Solve, temp, K[stage]); + TIMED_METHOD(stats.total_linear_solve_time, time_it, linear_solver_.template Solve, temp, K[stage], state.lower_matrix_, state.upper_matrix_); stats.solves += 1; } @@ -792,17 +799,18 @@ namespace micm bool& singular, const MatrixPolicy& number_densities, SolverStats& stats, - SparseMatrixPolicy jacobian) + State& state) { // TODO: invesitage this function. The fortran equivalent appears to have a bug. // From my understanding the fortran do loop would only ever do one iteration and is equivalent to what's below + auto jacobian = state.jacobian_; uint64_t n_consecutive = 0; singular = true; while (true) { double alpha = 1 / (H * gamma); AlphaMinusJacobian(jacobian, alpha); - linear_solver_.Factor(jacobian); + linear_solver_.Factor(jacobian, state.lower_matrix_, state.upper_matrix_); singular = false; // TODO This should be evaluated in some way stats.decompositions += 1; if (!singular) diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index 96072af7d..9b4545117 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -47,6 +47,8 @@ namespace micm std::map variable_map_; std::map custom_rate_parameter_map_; std::vector variable_names_{}; + SparseMatrixPolicy lower_matrix_; + SparseMatrixPolicy upper_matrix_; /// @brief State(); diff --git a/test/integration/analytical_rosenbrock.cpp b/test/integration/analytical_rosenbrock.cpp index 66d51e5e6..6d72a32ce 100644 --- a/test/integration/analytical_rosenbrock.cpp +++ b/test/integration/analytical_rosenbrock.cpp @@ -35,630 +35,630 @@ TEST(AnalyticalExamples, TroeSuperStiffButAnalytical) }); } -// TEST(AnalyticalExamples, Photolysis) -// { -// test_analytical_photolysis>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, PhotolysisSuperStiffButAnalytical) -// { -// test_analytical_stiff_photolysis>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, TernaryChemicalActivation) -// { -// test_analytical_ternary_chemical_activation>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, TernaryChemicalActivationSuperStiffButAnalytical) -// { -// test_analytical_stiff_ternary_chemical_activation>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, Tunneling) -// { -// test_analytical_tunneling>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, TunnelingSuperStiffButAnalytical) -// { -// test_analytical_stiff_tunneling>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, Arrhenius) -// { -// test_analytical_arrhenius>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, ArrheniusSuperStiffButAnalytical) -// { -// test_analytical_stiff_arrhenius>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, Branched) -// { -// test_analytical_branched>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, BranchedSuperStiffButAnalytical) -// { -// test_analytical_stiff_branched>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, Robertson) -// { -// test_analytical_robertson>( -// [](const micm::System& s, -// const std::vector& p) -> micm::RosenbrockSolver -// { -// return micm::RosenbrockSolver{ -// s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() -// }; -// }); -// } - -// TEST(AnalyticalExamples, Oregonator) -// { -// /* -// * I think these are the equations, but I'm really not sure. I don't know how this translates to the jacobian -// * and forcing functions used by the ODE book: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f -// * A+Y -> X+P -// * X+Y -> 2P -// * A+X -> 2X+2Z -// * 2X -> A+P -// * B+Z -> 1/2fY -// * -// * this problem is described in -// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd -// * edition. ed. Springer, Berlin ; New York. Page 3 -// * -// * solutions are provided here -// * https://www.unige.ch/~hairer/testset/testset.html -// */ - -// auto a = micm::Species("A"); -// auto b = micm::Species("B"); -// auto c = micm::Species("C"); - -// micm::Phase gas_phase{ std::vector{ a, b, c } }; - -// micm::Process r1 = micm::Process::create() -// .reactants({ a }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) -// .phase(gas_phase); - -// micm::Process r2 = micm::Process::create() -// .reactants({ b }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) -// .phase(gas_phase); - -// micm::Process r3 = micm::Process::create() -// .reactants({ b }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) -// .phase(gas_phase); - -// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); -// params.relative_tolerance_ = 1e-4; -// params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; -// Oregonator solver( -// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3 }, params); - -// double end = 360; -// double time_step = 30; -// size_t N = static_cast(end / time_step); - -// std::vector> model_concentrations(N + 1, std::vector(3)); -// std::vector> analytical_concentrations(13, std::vector(3)); - -// model_concentrations[0] = { 1, 2, 3 }; - -// analytical_concentrations = { -// { 1, 2, 3 }, -// { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, -// { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, -// { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, -// { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, -// { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, -// { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, -// { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, -// { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, -// { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, -// { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, -// { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, -// { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, -// }; - -// auto state = solver.GetState(); - -// state.variables_[0] = model_concentrations[0]; - -// std::vector times; -// times.push_back(0); -// for (size_t i_time = 0; i_time < N; ++i_time) -// { -// double solve_time = time_step + i_time * time_step; -// times.push_back(solve_time); -// // Model results -// double actual_solve = 0; -// while (actual_solve < time_step) -// { -// auto result = solver.Solve(time_step - actual_solve, state); -// state.variables_[0] = result.result_.AsVector(); -// actual_solve += result.final_time_; -// } -// model_concentrations[i_time + 1] = state.variables_[0]; -// } - -// std::vector header = { "time", "A", "B", "C" }; -// writeCSV("model_concentrations.csv", header, model_concentrations, times); -// std::vector an_times; -// an_times.push_back(0); -// for (int i = 1; i <= 12; ++i) -// { -// an_times.push_back(30 * i); -// } -// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); - -// auto map = state.variable_map_; - -// size_t _a = map.at("A"); -// size_t _b = map.at("B"); -// size_t _c = map.at("C"); - -// double tol = 1e-3; -// for (size_t i = 0; i < model_concentrations.size(); ++i) -// { -// double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; -// rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; -// rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; -// } -// } - -// TEST(AnalyticalExamples, Oregonator2) -// { -// /* Equations derived from the forcing function here: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f -// * a + b -> ( 1 - (1/77.27)^2 ) b k = 77.27 -// * c -> ( 1 / (0.161 * 77.27) ) b k = 0.161 -// * b -> ( 77.27 )^2 a k = 1/77.27 -// * a -> 2 a + ( 0.161/77.27 ) c k = 77.27 -// * a + a -> NULL k = 77.27 * 8.375e-6 -// * -// * this problem is described in -// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd -// * edition. ed. Springer, Berlin ; New York. Page 3 -// * -// * solutions are provided here -// * https://www.unige.ch/~hairer/testset/testset.html -// */ - -// auto a = micm::Species("A"); -// auto b = micm::Species("B"); -// auto c = micm::Species("C"); - -// micm::Phase gas_phase{ std::vector{ a, b, c } }; - -// micm::Process r1 = micm::Process::create() -// .reactants({ a, b }) -// .products({ yields(b, 1 - std::pow((1 / 77.27), 2)) }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) -// .phase(gas_phase); - -// micm::Process r2 = micm::Process::create() -// .reactants({ c }) -// .products({ yields(b, 1 / (0.161 * 77.27)) }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) -// .phase(gas_phase); - -// micm::Process r3 = micm::Process::create() -// .reactants({ b }) -// .products({ yields(a, std::pow(77.27, 2)) }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) -// .phase(gas_phase); - -// micm::Process r4 = micm::Process::create() -// .reactants({ a }) -// .products({ yields(a, 2), yields(c, 0.161 / 77.27) }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) -// .phase(gas_phase); - -// micm::Process r5 = micm::Process::create() -// .reactants({ a, a }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) -// .phase(gas_phase); - -// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); -// params.relative_tolerance_ = 1e-4; -// params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; -// Oregonator solver( -// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), -// std::vector{ r1, r2, r3, r4, r5 }, -// params); - -// double end = 360; -// double time_step = 30; -// size_t N = static_cast(end / time_step); - -// std::vector> model_concentrations(N + 1, std::vector(3)); -// std::vector> analytical_concentrations(13, std::vector(3)); - -// model_concentrations[0] = { 1, 2, 3 }; - -// analytical_concentrations = { -// { 1, 2, 3 }, -// { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, -// { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, -// { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, -// { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, -// { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, -// { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, -// { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, -// { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, -// { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, -// { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, -// { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, -// { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, -// }; - -// auto state = solver.GetState(); - -// double k1 = 77.27; -// double k2 = 0.161; -// double k3 = 1 / 77.27; -// double k4 = 77.27; -// double k5 = 77.27 * 8.375e-6; - -// state.SetCustomRateParameter("r1", k1); -// state.SetCustomRateParameter("r2", k2); -// state.SetCustomRateParameter("r3", k3); -// state.SetCustomRateParameter("r4", k4); -// state.SetCustomRateParameter("r5", k5); - -// state.variables_[0] = model_concentrations[0]; - -// std::vector times; -// times.push_back(0); -// for (size_t i_time = 0; i_time < N; ++i_time) -// { -// double solve_time = time_step + i_time * time_step; -// times.push_back(solve_time); -// // Model results -// double actual_solve = 0; -// while (actual_solve < time_step) -// { -// auto result = solver.Solve(time_step - actual_solve, state); -// state.variables_[0] = result.result_.AsVector(); -// actual_solve += result.final_time_; -// } -// model_concentrations[i_time + 1] = state.variables_[0]; -// } - -// std::vector header = { "time", "A", "B", "C" }; -// writeCSV("model_concentrations.csv", header, model_concentrations, times); -// std::vector an_times; -// an_times.push_back(0); -// for (int i = 1; i <= 12; ++i) -// { -// an_times.push_back(30 * i); -// } -// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); - -// auto map = state.variable_map_; - -// size_t _a = map.at("A"); -// size_t _b = map.at("B"); -// size_t _c = map.at("C"); - -// double tol = 1e-3; -// for (size_t i = 0; i < model_concentrations.size(); ++i) -// { -// double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; -// rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; -// rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); -// EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; -// } -// } - -// TEST(AnalyticalExamples, HIRES) -// { -// /* -// * No idea what these equations are -// * -// * this problem is described in -// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd -// * edition. ed. Springer, Berlin ; New York. Page 3 -// * -// * solutions are provided here -// * https://www.unige.ch/~hairer/testset/testset.html -// */ - -// auto y1 = micm::Species("y1"); -// auto y2 = micm::Species("y2"); -// auto y3 = micm::Species("y3"); -// auto y4 = micm::Species("y4"); -// auto y5 = micm::Species("y5"); -// auto y6 = micm::Species("y6"); -// auto y7 = micm::Species("y7"); -// auto y8 = micm::Species("y8"); - -// micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4, y5, y6, y7, y8 } }; - -// micm::Process r1 = micm::Process::create() -// .reactants({ y1 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) -// .phase(gas_phase); -// micm::Process r2 = micm::Process::create() -// .reactants({ y2 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) -// .phase(gas_phase); -// micm::Process r3 = micm::Process::create() -// .reactants({ y3 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) -// .phase(gas_phase); -// micm::Process r4 = micm::Process::create() -// .reactants({ y4 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) -// .phase(gas_phase); -// micm::Process r5 = micm::Process::create() -// .reactants({ y5 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) -// .phase(gas_phase); -// micm::Process r6 = micm::Process::create() -// .reactants({ y6 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r6" })) -// .phase(gas_phase); -// micm::Process r7 = micm::Process::create() -// .reactants({ y7 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r7" })) -// .phase(gas_phase); -// micm::Process r8 = micm::Process::create() -// .reactants({ y8 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r8" })) -// .phase(gas_phase); - -// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); -// params.relative_tolerance_ = 1e-3; -// params.absolute_tolerance_ = params.relative_tolerance_ * 1e-4; -// HIRES solver( -// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), -// std::vector{ r1, r2, r3, r4, r5, r6, r7, r8 }, -// params); - -// size_t N = 2; - -// std::vector> model_concentrations(N + 1, std::vector(8)); -// std::vector> analytical_concentrations(3, std::vector(8)); - -// model_concentrations[0] = { 1, 0, 0, 0, 0, 0, 0, 0.0057 }; - -// analytical_concentrations = { -// { 1, 0, 0, 0, 0, 0, 0, 0.0057 }, -// { 0.000737131257332567, -// 0.000144248572631618, -// 0.000058887297409676, -// 0.001175651343283149, -// 0.002386356198831330, -// 0.006238968252742796, -// 0.002849998395185769, -// 0.002850001604814231 }, -// { 0.000670305503581864, -// 0.000130996846986347, -// 0.000046862231597733, -// 0.001044668020551705, -// 0.000594883830951485, -// 0.001399628833942774, -// 0.001014492757718480, -// 0.004685507242281520 }, -// }; - -// auto state = solver.GetState(); - -// state.variables_[0] = model_concentrations[0]; - -// std::vector times; -// times.push_back(0); -// double time_step = 321.8122; -// for (size_t i_time = 0; i_time < N; ++i_time) -// { -// double solve_time = time_step + i_time * time_step; -// times.push_back(solve_time); -// // Model results -// double actual_solve = 0; -// while (actual_solve < time_step) -// { -// auto result = solver.Solve(time_step - actual_solve, state); -// state.variables_[0] = result.result_.AsVector(); -// actual_solve += result.final_time_; -// } -// model_concentrations[i_time + 1] = state.variables_[0]; -// time_step += 100; -// } - -// std::vector header = { "time", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8" }; -// writeCSV("model_concentrations.csv", header, model_concentrations, times); -// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); - -// double tol = 1e-5; -// for (size_t i = 0; i < model_concentrations.size(); ++i) -// { -// for (size_t j = 0; j < model_concentrations[0].size(); ++j) -// { -// double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); -// EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol); -// } -// } -// } - -// TEST(AnalyticalExamples, E5) -// { -// /* -// * No idea what these equations are -// * -// * this problem is described in -// * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd -// * edition. ed. Springer, Berlin ; New York. Page 3 -// * -// * solutions are provided here -// * https://www.unige.ch/~hairer/testset/testset.html -// */ - -// auto y1 = micm::Species("y1"); -// auto y2 = micm::Species("y2"); -// auto y3 = micm::Species("y3"); -// auto y4 = micm::Species("y4"); - -// micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4 } }; - -// micm::Process r1 = micm::Process::create() -// .reactants({ y1 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) -// .phase(gas_phase); -// micm::Process r2 = micm::Process::create() -// .reactants({ y2 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) -// .phase(gas_phase); -// micm::Process r3 = micm::Process::create() -// .reactants({ y3 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) -// .phase(gas_phase); -// micm::Process r4 = micm::Process::create() -// .reactants({ y4 }) -// .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) -// .phase(gas_phase); - -// auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); -// params.relative_tolerance_ = 1e-2; -// params.absolute_tolerance_ = 1.7e-24; -// E5 solver( -// micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3, r4 }, params); - -// size_t N = 7; - -// std::vector> model_concentrations(N + 1, std::vector(4)); -// std::vector> analytical_concentrations(N + 1, std::vector(4)); - -// model_concentrations[0] = { 1.76e-3, 0, 0, 0 }; - -// analytical_concentrations = { -// { 1.76e-3, 0, 0, 0 }, -// { 1.7599259497677897058e-003, 1.3846281519376516449e-011, 7.6370038530073911180e-013, 1.3082581134075777338e-011 }, -// { 1.6180769999072942552e-003, 1.3822370304983735443e-010, 8.2515735006838336088e-012, 1.2997212954915352082e-010 }, -// { 7.4813208224292220114e-006, 2.3734781561205975019e-012, 2.2123586689581663654e-012, 1.6111948716243113653e-013 }, -// { 4.7150333630401632232e-010, 1.8188895860807021729e-014, 1.8188812376786725407e-014, 8.3484020296321693074e-020 }, -// { 3.1317148329356996037e-014, 1.4840957952870064294e-016, 1.4840957948345691466e-016, 4.5243728279782625194e-026 }, -// { 3.8139035189787091771e-049, 1.0192582567660293322e-020, 1.0192582567660293322e-020, 3.7844935507486221171e-065 }, -// { 0.0000000000000000000e-000, 8.8612334976263783420e-023, 8.8612334976263783421e-023, 0.0000000000000000000e-000 } -// }; - -// auto state = solver.GetState(); - -// state.variables_[0] = model_concentrations[0]; - -// std::vector times; -// times.push_back(0); -// double time_step = 10; -// for (size_t i_time = 0; i_time < N; ++i_time) -// { -// double solve_time = time_step + i_time * time_step; -// times.push_back(solve_time); -// // Model results -// double actual_solve = 0; -// while (actual_solve < time_step) -// { -// auto result = solver.Solve(time_step - actual_solve, state); -// state.variables_[0] = result.result_.AsVector(); -// actual_solve += result.final_time_; -// } -// model_concentrations[i_time + 1] = state.variables_[0]; -// time_step *= 100; -// } - -// std::vector header = { "time", "y1", "y2", "y3", "y4" }; -// writeCSV("model_concentrations.csv", header, model_concentrations, times); -// writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); - -// double tol = 1e-5; -// for (size_t i = 0; i < model_concentrations.size(); ++i) -// { -// for (size_t j = 0; j < model_concentrations[0].size(); ++j) -// { -// double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); -// EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol) -// << "difference at (" << i << ", " << j << ")"; -// } -// } -// } \ No newline at end of file +TEST(AnalyticalExamples, Photolysis) +{ + test_analytical_photolysis>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, PhotolysisSuperStiffButAnalytical) +{ + test_analytical_stiff_photolysis>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, TernaryChemicalActivation) +{ + test_analytical_ternary_chemical_activation>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, TernaryChemicalActivationSuperStiffButAnalytical) +{ + test_analytical_stiff_ternary_chemical_activation>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, Tunneling) +{ + test_analytical_tunneling>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, TunnelingSuperStiffButAnalytical) +{ + test_analytical_stiff_tunneling>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, Arrhenius) +{ + test_analytical_arrhenius>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, ArrheniusSuperStiffButAnalytical) +{ + test_analytical_stiff_arrhenius>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, Branched) +{ + test_analytical_branched>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, BranchedSuperStiffButAnalytical) +{ + test_analytical_stiff_branched>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, Robertson) +{ + test_analytical_robertson>( + [](const micm::System& s, + const std::vector& p) -> micm::RosenbrockSolver + { + return micm::RosenbrockSolver{ + s, p, micm::RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + }; + }); +} + +TEST(AnalyticalExamples, Oregonator) +{ + /* + * I think these are the equations, but I'm really not sure. I don't know how this translates to the jacobian + * and forcing functions used by the ODE book: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f + * A+Y -> X+P + * X+Y -> 2P + * A+X -> 2X+2Z + * 2X -> A+P + * B+Z -> 1/2fY + * + * this problem is described in + * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd + * edition. ed. Springer, Berlin ; New York. Page 3 + * + * solutions are provided here + * https://www.unige.ch/~hairer/testset/testset.html + */ + + auto a = micm::Species("A"); + auto b = micm::Species("B"); + auto c = micm::Species("C"); + + micm::Phase gas_phase{ std::vector{ a, b, c } }; + + micm::Process r1 = micm::Process::create() + .reactants({ a }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) + .phase(gas_phase); + + micm::Process r2 = micm::Process::create() + .reactants({ b }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) + .phase(gas_phase); + + micm::Process r3 = micm::Process::create() + .reactants({ b }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) + .phase(gas_phase); + + auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); + params.relative_tolerance_ = 1e-4; + params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; + Oregonator solver( + micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3 }, params); + + double end = 360; + double time_step = 30; + size_t N = static_cast(end / time_step); + + std::vector> model_concentrations(N + 1, std::vector(3)); + std::vector> analytical_concentrations(13, std::vector(3)); + + model_concentrations[0] = { 1, 2, 3 }; + + analytical_concentrations = { + { 1, 2, 3 }, + { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, + { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, + { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, + { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, + { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, + { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, + { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, + { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, + { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, + { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, + { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, + { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, + }; + + auto state = solver.GetState(); + + state.variables_[0] = model_concentrations[0]; + + std::vector times; + times.push_back(0); + for (size_t i_time = 0; i_time < N; ++i_time) + { + double solve_time = time_step + i_time * time_step; + times.push_back(solve_time); + // Model results + double actual_solve = 0; + while (actual_solve < time_step) + { + auto result = solver.Solve(time_step - actual_solve, state); + state.variables_[0] = result.result_.AsVector(); + actual_solve += result.final_time_; + } + model_concentrations[i_time + 1] = state.variables_[0]; + } + + std::vector header = { "time", "A", "B", "C" }; + writeCSV("model_concentrations.csv", header, model_concentrations, times); + std::vector an_times; + an_times.push_back(0); + for (int i = 1; i <= 12; ++i) + { + an_times.push_back(30 * i); + } + writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); + + auto map = state.variable_map_; + + size_t _a = map.at("A"); + size_t _b = map.at("B"); + size_t _c = map.at("C"); + + double tol = 1e-3; + for (size_t i = 0; i < model_concentrations.size(); ++i) + { + double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; + rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; + rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; + } +} + +TEST(AnalyticalExamples, Oregonator2) +{ + /* Equations derived from the forcing function here: https://www.unige.ch/~hairer/testset/stiff/orego/equation.f + * a + b -> ( 1 - (1/77.27)^2 ) b k = 77.27 + * c -> ( 1 / (0.161 * 77.27) ) b k = 0.161 + * b -> ( 77.27 )^2 a k = 1/77.27 + * a -> 2 a + ( 0.161/77.27 ) c k = 77.27 + * a + a -> NULL k = 77.27 * 8.375e-6 + * + * this problem is described in + * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd + * edition. ed. Springer, Berlin ; New York. Page 3 + * + * solutions are provided here + * https://www.unige.ch/~hairer/testset/testset.html + */ + + auto a = micm::Species("A"); + auto b = micm::Species("B"); + auto c = micm::Species("C"); + + micm::Phase gas_phase{ std::vector{ a, b, c } }; + + micm::Process r1 = micm::Process::create() + .reactants({ a, b }) + .products({ yields(b, 1 - std::pow((1 / 77.27), 2)) }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) + .phase(gas_phase); + + micm::Process r2 = micm::Process::create() + .reactants({ c }) + .products({ yields(b, 1 / (0.161 * 77.27)) }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) + .phase(gas_phase); + + micm::Process r3 = micm::Process::create() + .reactants({ b }) + .products({ yields(a, std::pow(77.27, 2)) }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) + .phase(gas_phase); + + micm::Process r4 = micm::Process::create() + .reactants({ a }) + .products({ yields(a, 2), yields(c, 0.161 / 77.27) }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) + .phase(gas_phase); + + micm::Process r5 = micm::Process::create() + .reactants({ a, a }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) + .phase(gas_phase); + + auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); + params.relative_tolerance_ = 1e-4; + params.absolute_tolerance_ = 1e-6 * params.relative_tolerance_; + Oregonator solver( + micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), + std::vector{ r1, r2, r3, r4, r5 }, + params); + + double end = 360; + double time_step = 30; + size_t N = static_cast(end / time_step); + + std::vector> model_concentrations(N + 1, std::vector(3)); + std::vector> analytical_concentrations(13, std::vector(3)); + + model_concentrations[0] = { 1, 2, 3 }; + + analytical_concentrations = { + { 1, 2, 3 }, + { 0.1000661467180497E+01, 0.1512778937348249E+04, 0.1035854312767229E+05 }, + { 0.1000874625199626E+01, 0.1144336972384497E+04, 0.8372149966624639E+02 }, + { 0.1001890368438751E+01, 0.5299926232295553E+03, 0.1662279579042420E+01 }, + { 0.1004118022612645E+01, 0.2438326079910346E+03, 0.1008822224048647E+01 }, + { 0.1008995416634061E+01, 0.1121664388662539E+03, 0.1007783229065319E+01 }, + { 0.1019763472537298E+01, 0.5159761322947535E+02, 0.1016985778956374E+01 }, + { 0.1043985088527474E+01, 0.2373442027531524E+02, 0.1037691843544522E+01 }, + { 0.1100849071667922E+01, 0.1091533805469020E+02, 0.1085831969810860E+01 }, + { 0.1249102130020572E+01, 0.5013945178605446E+01, 0.1208326626237875E+01 }, + { 0.1779724751937019E+01, 0.2281852385542403E+01, 0.1613754023671725E+01 }, + { 0.1000889326903503E+01, 0.1125438585746596E+04, 0.1641049483777168E+05 }, + { 0.1000814870318523E+01, 0.1228178521549889E+04, 0.1320554942846513E+03 }, + }; + + auto state = solver.GetState(); + + double k1 = 77.27; + double k2 = 0.161; + double k3 = 1 / 77.27; + double k4 = 77.27; + double k5 = 77.27 * 8.375e-6; + + state.SetCustomRateParameter("r1", k1); + state.SetCustomRateParameter("r2", k2); + state.SetCustomRateParameter("r3", k3); + state.SetCustomRateParameter("r4", k4); + state.SetCustomRateParameter("r5", k5); + + state.variables_[0] = model_concentrations[0]; + + std::vector times; + times.push_back(0); + for (size_t i_time = 0; i_time < N; ++i_time) + { + double solve_time = time_step + i_time * time_step; + times.push_back(solve_time); + // Model results + double actual_solve = 0; + while (actual_solve < time_step) + { + auto result = solver.Solve(time_step - actual_solve, state); + state.variables_[0] = result.result_.AsVector(); + actual_solve += result.final_time_; + } + model_concentrations[i_time + 1] = state.variables_[0]; + } + + std::vector header = { "time", "A", "B", "C" }; + writeCSV("model_concentrations.csv", header, model_concentrations, times); + std::vector an_times; + an_times.push_back(0); + for (int i = 1; i <= 12; ++i) + { + an_times.push_back(30 * i); + } + writeCSV("analytical_concentrations.csv", header, analytical_concentrations, an_times); + + auto map = state.variable_map_; + + size_t _a = map.at("A"); + size_t _b = map.at("B"); + size_t _c = map.at("C"); + + double tol = 1e-3; + for (size_t i = 0; i < model_concentrations.size(); ++i) + { + double rel_diff = relative_difference(model_concentrations[i][_a], analytical_concentrations[i][0]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 0 << ")"; + rel_diff = relative_difference(model_concentrations[i][_b], analytical_concentrations[i][1]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 1 << ")"; + rel_diff = relative_difference(model_concentrations[i][_c], analytical_concentrations[i][2]); + EXPECT_TRUE(rel_diff < tol) << "Arrays differ at index (" << i << ", " << 2 << ")"; + } +} + +TEST(AnalyticalExamples, HIRES) +{ + /* + * No idea what these equations are + * + * this problem is described in + * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd + * edition. ed. Springer, Berlin ; New York. Page 3 + * + * solutions are provided here + * https://www.unige.ch/~hairer/testset/testset.html + */ + + auto y1 = micm::Species("y1"); + auto y2 = micm::Species("y2"); + auto y3 = micm::Species("y3"); + auto y4 = micm::Species("y4"); + auto y5 = micm::Species("y5"); + auto y6 = micm::Species("y6"); + auto y7 = micm::Species("y7"); + auto y8 = micm::Species("y8"); + + micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4, y5, y6, y7, y8 } }; + + micm::Process r1 = micm::Process::create() + .reactants({ y1 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) + .phase(gas_phase); + micm::Process r2 = micm::Process::create() + .reactants({ y2 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) + .phase(gas_phase); + micm::Process r3 = micm::Process::create() + .reactants({ y3 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) + .phase(gas_phase); + micm::Process r4 = micm::Process::create() + .reactants({ y4 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) + .phase(gas_phase); + micm::Process r5 = micm::Process::create() + .reactants({ y5 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r5" })) + .phase(gas_phase); + micm::Process r6 = micm::Process::create() + .reactants({ y6 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r6" })) + .phase(gas_phase); + micm::Process r7 = micm::Process::create() + .reactants({ y7 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r7" })) + .phase(gas_phase); + micm::Process r8 = micm::Process::create() + .reactants({ y8 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r8" })) + .phase(gas_phase); + + auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); + params.relative_tolerance_ = 1e-3; + params.absolute_tolerance_ = params.relative_tolerance_ * 1e-4; + HIRES solver( + micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), + std::vector{ r1, r2, r3, r4, r5, r6, r7, r8 }, + params); + + size_t N = 2; + + std::vector> model_concentrations(N + 1, std::vector(8)); + std::vector> analytical_concentrations(3, std::vector(8)); + + model_concentrations[0] = { 1, 0, 0, 0, 0, 0, 0, 0.0057 }; + + analytical_concentrations = { + { 1, 0, 0, 0, 0, 0, 0, 0.0057 }, + { 0.000737131257332567, + 0.000144248572631618, + 0.000058887297409676, + 0.001175651343283149, + 0.002386356198831330, + 0.006238968252742796, + 0.002849998395185769, + 0.002850001604814231 }, + { 0.000670305503581864, + 0.000130996846986347, + 0.000046862231597733, + 0.001044668020551705, + 0.000594883830951485, + 0.001399628833942774, + 0.001014492757718480, + 0.004685507242281520 }, + }; + + auto state = solver.GetState(); + + state.variables_[0] = model_concentrations[0]; + + std::vector times; + times.push_back(0); + double time_step = 321.8122; + for (size_t i_time = 0; i_time < N; ++i_time) + { + double solve_time = time_step + i_time * time_step; + times.push_back(solve_time); + // Model results + double actual_solve = 0; + while (actual_solve < time_step) + { + auto result = solver.Solve(time_step - actual_solve, state); + state.variables_[0] = result.result_.AsVector(); + actual_solve += result.final_time_; + } + model_concentrations[i_time + 1] = state.variables_[0]; + time_step += 100; + } + + std::vector header = { "time", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8" }; + writeCSV("model_concentrations.csv", header, model_concentrations, times); + writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); + + double tol = 1e-5; + for (size_t i = 0; i < model_concentrations.size(); ++i) + { + for (size_t j = 0; j < model_concentrations[0].size(); ++j) + { + double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); + EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol); + } + } +} + +TEST(AnalyticalExamples, E5) +{ + /* + * No idea what these equations are + * + * this problem is described in + * Hairer, E., Wanner, G., 1996. Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, 2nd + * edition. ed. Springer, Berlin ; New York. Page 3 + * + * solutions are provided here + * https://www.unige.ch/~hairer/testset/testset.html + */ + + auto y1 = micm::Species("y1"); + auto y2 = micm::Species("y2"); + auto y3 = micm::Species("y3"); + auto y4 = micm::Species("y4"); + + micm::Phase gas_phase{ std::vector{ y1, y2, y3, y4 } }; + + micm::Process r1 = micm::Process::create() + .reactants({ y1 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r1" })) + .phase(gas_phase); + micm::Process r2 = micm::Process::create() + .reactants({ y2 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r2" })) + .phase(gas_phase); + micm::Process r3 = micm::Process::create() + .reactants({ y3 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r3" })) + .phase(gas_phase); + micm::Process r4 = micm::Process::create() + .reactants({ y4 }) + .rate_constant(micm::UserDefinedRateConstant({ .label_ = "r4" })) + .phase(gas_phase); + + auto params = micm::RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters(); + params.relative_tolerance_ = 1e-2; + params.absolute_tolerance_ = 1.7e-24; + E5 solver( + micm::System(micm::SystemParameters{ .gas_phase_ = gas_phase }), std::vector{ r1, r2, r3, r4 }, params); + + size_t N = 7; + + std::vector> model_concentrations(N + 1, std::vector(4)); + std::vector> analytical_concentrations(N + 1, std::vector(4)); + + model_concentrations[0] = { 1.76e-3, 0, 0, 0 }; + + analytical_concentrations = { + { 1.76e-3, 0, 0, 0 }, + { 1.7599259497677897058e-003, 1.3846281519376516449e-011, 7.6370038530073911180e-013, 1.3082581134075777338e-011 }, + { 1.6180769999072942552e-003, 1.3822370304983735443e-010, 8.2515735006838336088e-012, 1.2997212954915352082e-010 }, + { 7.4813208224292220114e-006, 2.3734781561205975019e-012, 2.2123586689581663654e-012, 1.6111948716243113653e-013 }, + { 4.7150333630401632232e-010, 1.8188895860807021729e-014, 1.8188812376786725407e-014, 8.3484020296321693074e-020 }, + { 3.1317148329356996037e-014, 1.4840957952870064294e-016, 1.4840957948345691466e-016, 4.5243728279782625194e-026 }, + { 3.8139035189787091771e-049, 1.0192582567660293322e-020, 1.0192582567660293322e-020, 3.7844935507486221171e-065 }, + { 0.0000000000000000000e-000, 8.8612334976263783420e-023, 8.8612334976263783421e-023, 0.0000000000000000000e-000 } + }; + + auto state = solver.GetState(); + + state.variables_[0] = model_concentrations[0]; + + std::vector times; + times.push_back(0); + double time_step = 10; + for (size_t i_time = 0; i_time < N; ++i_time) + { + double solve_time = time_step + i_time * time_step; + times.push_back(solve_time); + // Model results + double actual_solve = 0; + while (actual_solve < time_step) + { + auto result = solver.Solve(time_step - actual_solve, state); + state.variables_[0] = result.result_.AsVector(); + actual_solve += result.final_time_; + } + model_concentrations[i_time + 1] = state.variables_[0]; + time_step *= 100; + } + + std::vector header = { "time", "y1", "y2", "y3", "y4" }; + writeCSV("model_concentrations.csv", header, model_concentrations, times); + writeCSV("analytical_concentrations.csv", header, analytical_concentrations, times); + + double tol = 1e-5; + for (size_t i = 0; i < model_concentrations.size(); ++i) + { + for (size_t j = 0; j < model_concentrations[0].size(); ++j) + { + double rel_diff = relative_difference(model_concentrations[i][j], analytical_concentrations[i][j]); + EXPECT_NEAR(model_concentrations[i][j], analytical_concentrations[i][j], tol) + << "difference at (" << i << ", " << j << ")"; + } + } +} diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 4dd717f77..4c1f06756 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -32,8 +32,18 @@ class E5 : public micm::RosenbrockSolver param_labels{}; + for (const auto& process : processes) + if (process.rate_constant_) + for (auto& label : process.rate_constant_->CustomParameters()) + param_labels.push_back(label); + this->state_parameters_ = { - .jacobian_diagonal_elements_ = jacobian_diagonal_elements + .variable_names_ = system.UniqueNames(this->state_reordering_), + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, + .custom_rate_parameter_labels_ = param_labels, + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = processes.size() }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 2686843f3..163035cff 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -33,8 +33,18 @@ class HIRES : public micm::RosenbrockSolver param_labels{}; + for (const auto& process : processes) + if (process.rate_constant_) + for (auto& label : process.rate_constant_->CustomParameters()) + param_labels.push_back(label); + this->state_parameters_ = { - .jacobian_diagonal_elements_ = jacobian_diagonal_elements + .variable_names_ = system.UniqueNames(this->state_reordering_), + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, + .custom_rate_parameter_labels_ = param_labels, + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = processes.size() }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index cf9dfd787..b3f3914ca 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -33,8 +33,18 @@ class Oregonator : public micm::RosenbrockSolver param_labels{}; + for (const auto& process : processes) + if (process.rate_constant_) + for (auto& label : process.rate_constant_->CustomParameters()) + param_labels.push_back(label); + this->state_parameters_ = { - .jacobian_diagonal_elements_ = jacobian_diagonal_elements + .variable_names_ = system.UniqueNames(this->state_reordering_), + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, + .custom_rate_parameter_labels_ = param_labels, + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = processes.size() }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/unit/solver/test_linear_solver_policy.hpp b/test/unit/solver/test_linear_solver_policy.hpp index 522a426c6..03c33e203 100644 --- a/test/unit/solver/test_linear_solver_policy.hpp +++ b/test/unit/solver/test_linear_solver_policy.hpp @@ -84,8 +84,11 @@ void testDenseMatrix(const std::function(b, x); + auto lu = solver.GetLUMatrices(A, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + solver.Factor(A, lower_matrix, upper_matrix); + solver.template Solve(b, x, lower_matrix, upper_matrix); check_results( A, b, x, [&](const double a, const double b) -> void { EXPECT_NEAR(a, b, 1.0e-5); }); } @@ -119,8 +122,11 @@ void testRandomMatrix( b[i_block][i] = get_double(); LinearSolverPolicy solver = create_linear_solver(A, 1.0e-30); - solver.Factor(A); - solver.template Solve(b, x); + auto lu = solver.GetLUMatrices(A, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + solver.Factor(A, lower_matrix, upper_matrix); + solver.template Solve(b, x, lower_matrix, upper_matrix); check_results( A, b, x, [&](const double a, const double b) -> void { EXPECT_NEAR(a, b, 1.0e-5); }); } @@ -145,8 +151,11 @@ void testDiagonalMatrix( A[i_block][i][i] = get_double(); LinearSolverPolicy solver = create_linear_solver(A, 1.0e-30); - solver.Factor(A); - solver.template Solve(b, x); + auto lu = solver.GetLUMatrices(A, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + solver.Factor(A, lower_matrix, upper_matrix); + solver.template Solve(b, x, lower_matrix, upper_matrix); check_results( A, b, x, [&](const double a, const double b) -> void { EXPECT_NEAR(a, b, 1.0e-5); }); } From 07a0f5453119acb63366df691eddd995cec15bf7 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Fri, 20 Oct 2023 16:27:03 -0500 Subject: [PATCH 04/30] tests pass --- test/integration/e5.hpp | 6 +++++- test/integration/hires.hpp | 6 +++++- test/integration/oregonator.hpp | 7 ++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 4c1f06756..8a34ef6f6 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -18,12 +18,15 @@ class E5 : public micm::RosenbrockSolverprocesses_ = processes; this->parameters_ = parameters; this->N_ = this->system_.StateSize() * this->parameters_.number_of_grid_cells_; + auto builder = SparseMatrixPolicy::create(4).number_of_blocks(1).initial_value(0.0); + std::set> nonzero_jacobian_elements; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { builder = builder.with_element(i, j); + nonzero_jacobian_elements.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -43,7 +46,8 @@ class E5 : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 163035cff..64f177b41 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -19,12 +19,15 @@ class HIRES : public micm::RosenbrockSolverprocesses_ = processes; this->parameters_ = parameters; this->N_ = this->system_.StateSize() * this->parameters_.number_of_grid_cells_; + auto builder = SparseMatrixPolicy::create(8).number_of_blocks(1).initial_value(0.0); + std::set> nonzero_jacobian_elements; for (int i = 0; i < 8; ++i) { for (int j = 0; j < 8; ++j) { builder = builder.with_element(i, j); + nonzero_jacobian_elements.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -44,7 +47,8 @@ class HIRES : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index b3f3914ca..8669aea18 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -19,12 +19,15 @@ class Oregonator : public micm::RosenbrockSolverprocesses_ = processes; this->parameters_ = parameters; this->N_ = this->system_.StateSize() * this->parameters_.number_of_grid_cells_; + auto builder = SparseMatrixPolicy::create(3).number_of_blocks(1).initial_value(0.0); + std::set> nonzero_jacobian_elements; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { builder = builder.with_element(i, j); + nonzero_jacobian_elements.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -39,12 +42,14 @@ class Oregonator : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); + this->state_parameters_ = { .variable_names_ = system.UniqueNames(this->state_reordering_), .jacobian_diagonal_elements_ = jacobian_diagonal_elements, .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, - .number_of_rate_constants_ = processes.size() + .number_of_rate_constants_ = processes.size(), + .nonzero_jacobian_elements_ = nonzero_jacobian_elements }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); From 02e0718f19276972e2217bd4f0712e281257f882 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Fri, 20 Oct 2023 16:49:34 -0500 Subject: [PATCH 05/30] added openmp test --- test/tutorial/test_openmp.cpp | 4 ++-- test/unit/openmp/test_openmp.cpp | 23 ++++++++++------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/test/tutorial/test_openmp.cpp b/test/tutorial/test_openmp.cpp index ead3829ff..a6242a399 100644 --- a/test/tutorial/test_openmp.cpp +++ b/test/tutorial/test_openmp.cpp @@ -26,7 +26,7 @@ void print_results(std::vector results) std::cout.copyfmt(oldState); } -std::vector test_solver_on_thread(System chemical_system, std::vector reactions) +std::vector run_solver_on_thread_with_own_state(System chemical_system, std::vector reactions) { RosenbrockSolver<> solver{ chemical_system, reactions, @@ -90,7 +90,7 @@ int main() #pragma omp parallel num_threads(n_threads) { - std::vector result = test_solver_on_thread(chemical_system, reactions); + std::vector result = run_solver_on_thread_with_own_state(chemical_system, reactions); results[omp_get_thread_num()] = result; #pragma omp barrier } diff --git a/test/unit/openmp/test_openmp.cpp b/test/unit/openmp/test_openmp.cpp index c398143e5..cdec67696 100644 --- a/test/unit/openmp/test_openmp.cpp +++ b/test/unit/openmp/test_openmp.cpp @@ -6,16 +6,9 @@ using namespace micm; -template -using SparseMatrixPolicy = SparseMatrix; - -std::vector test_solver_on_thread(System chemical_system, std::vector reactions) +std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) { std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; - RosenbrockSolver<> solver{ chemical_system, - reactions, - RosenbrockSolverParameters::three_stage_rosenbrock_parameters() }; - State state = solver.GetState(); // mol m-3 state.variables_[0] = { 1, 0, 0 }; @@ -70,18 +63,22 @@ TEST(OpenMP, OneFileReadThreeThreads) auto chemical_system = solver_params.system_; auto reactions = solver_params.processes_; - std::vector> results(3); + std::vector> results(n_threads); + + RosenbrockSolver<> solver{ chemical_system, reactions, RosenbrockSolverParameters::three_stage_rosenbrock_parameters() }; #pragma omp parallel num_threads(n_threads) { - std::vector result = test_solver_on_thread(chemical_system, reactions); + auto state = solver.GetState(); + std::vector result = run_solver_on_thread_with_own_state(solver, state); results[omp_get_thread_num()] = result; -#pragma omp barrier +#pragma omp barrier } - for(int i = 0; i < results[0].size(); ++i) { + for (int i = 0; i < results[0].size(); ++i) + { EXPECT_EQ(results[0][i], results[1][i]); EXPECT_EQ(results[0][i], results[2][i]); EXPECT_EQ(results[1][i], results[2][i]); } -} \ No newline at end of file +} From a8370c567c8d0a6f19cf47da2e6c343aaaed14de Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Fri, 20 Oct 2023 16:56:31 -0500 Subject: [PATCH 06/30] stuff --- include/micm/process/jit_process_set.hpp | 2 +- test/tutorial/test_openmp.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/micm/process/jit_process_set.hpp b/include/micm/process/jit_process_set.hpp index ef3926beb..c04f0d969 100644 --- a/include/micm/process/jit_process_set.hpp +++ b/include/micm/process/jit_process_set.hpp @@ -108,7 +108,7 @@ namespace micm std::shared_ptr compiler, const std::vector &processes, const State &state) - : ProcessSet(processes, state), + : ProcessSet(processes, state.variable_map_), compiler_(compiler) { forcing_function_ = NULL; diff --git a/test/tutorial/test_openmp.cpp b/test/tutorial/test_openmp.cpp index a6242a399..dceffdd32 100644 --- a/test/tutorial/test_openmp.cpp +++ b/test/tutorial/test_openmp.cpp @@ -26,12 +26,9 @@ void print_results(std::vector results) std::cout.copyfmt(oldState); } -std::vector run_solver_on_thread_with_own_state(System chemical_system, std::vector reactions) +std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) { - RosenbrockSolver<> solver{ chemical_system, - reactions, - RosenbrockSolverParameters::three_stage_rosenbrock_parameters(1, false) }; - State state = solver.GetState(); + std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; // mol m-3 state.variables_[0] = { 1, 0, 0 }; @@ -86,11 +83,15 @@ int main() auto chemical_system = solver_params.system_; auto reactions = solver_params.processes_; - std::vector> results(3); + std::vector> results(n_threads); + + RosenbrockSolver<> solver{ chemical_system, reactions, RosenbrockSolverParameters::three_stage_rosenbrock_parameters() }; #pragma omp parallel num_threads(n_threads) { - std::vector result = run_solver_on_thread_with_own_state(chemical_system, reactions); + // each thread should use its own state + auto state = solver.GetState(); + std::vector result = run_solver_on_thread_with_own_state(solver, state); results[omp_get_thread_num()] = result; #pragma omp barrier } From bdf58e217cd291031499c5d9565ba692c1785d78 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 11:08:19 -0500 Subject: [PATCH 07/30] adding a test for the jit solver for thread safety --- test/unit/openmp/CMakeLists.txt | 5 +- test/unit/openmp/test_openmp.cpp | 2 +- test/unit/openmp/test_openmp_jit_solver.cpp | 101 ++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 test/unit/openmp/test_openmp_jit_solver.cpp diff --git a/test/unit/openmp/CMakeLists.txt b/test/unit/openmp/CMakeLists.txt index 7db63577c..b744f9807 100644 --- a/test/unit/openmp/CMakeLists.txt +++ b/test/unit/openmp/CMakeLists.txt @@ -6,4 +6,7 @@ include(test_util) ################################################################################ # Tests -create_standard_test(NAME openmp SOURCES test_openmp.cpp) \ No newline at end of file +create_standard_test(NAME openmp SOURCES test_openmp.cpp) +if(ENABLE_LLVM) + create_standard_test(NAME openmp_jit_solver SOURCES test_openmp_jit_solver.cpp) +endif() \ No newline at end of file diff --git a/test/unit/openmp/test_openmp.cpp b/test/unit/openmp/test_openmp.cpp index 54c9b9746..d284bd16b 100644 --- a/test/unit/openmp/test_openmp.cpp +++ b/test/unit/openmp/test_openmp.cpp @@ -45,7 +45,7 @@ std::vector run_solver_on_thread_with_own_state(auto& solver, auto& stat return state.variables_.AsVector(); } -TEST(OpenMP, OneFileReadThreeThreads) +TEST(OpenMP, OneSolverManyStates) { constexpr size_t n_threads = 8; diff --git a/test/unit/openmp/test_openmp_jit_solver.cpp b/test/unit/openmp/test_openmp_jit_solver.cpp new file mode 100644 index 000000000..479d3e5c5 --- /dev/null +++ b/test/unit/openmp/test_openmp_jit_solver.cpp @@ -0,0 +1,101 @@ +#include +#include + +#include +#include +#include +#include + +using namespace micm; + +template +using Group1VectorMatrix = micm::VectorMatrix; +template +using Group1SparseVectorMatrix = micm::SparseMatrix>; + +std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) +{ + std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; + + // mol m-3 + state.variables_[0] = { 1, 0, 0 }; + + double k1 = 0.04; + double k2 = 3e7; + double k3 = 1e4; + state.SetCustomRateParameter("PHOTO.r1", k1); + state.SetCustomRateParameter("PHOTO.r2", k2); + state.SetCustomRateParameter("PHOTO.r3", k3); + + double temperature = 272.5; // [K] + double pressure = 101253.3; // [Pa] + double air_density = 1e6; // [mol m-3] + + state.conditions_[0].temperature_ = temperature; + state.conditions_[0].pressure_ = pressure; + state.conditions_[0].air_density_ = air_density; + + double time_step = 200; // s + + for (int i = 0; i < 10; ++i) + { + double elapsed_solve_time = 0; + + while (elapsed_solve_time < time_step) + { + auto result = solver.Solve(time_step - elapsed_solve_time, state); + elapsed_solve_time = result.final_time_; + state.variables_ = result.result_; + } + } + + return state.variables_.AsVector(); +} + +TEST(OpenMP, JITOneSolverManyStates) +{ + constexpr size_t n_threads = 8; + + SolverConfig solverConfig; + + std::string config_path = "./unit_configs/robertson"; + ConfigParseStatus status = solverConfig.ReadAndParse(config_path); + if (status != micm::ConfigParseStatus::Success) + { + throw "Parsing failed"; + } + + micm::SolverParameters solver_params = solverConfig.GetSolverParams(); + + auto chemical_system = solver_params.system_; + auto reactions = solver_params.processes_; + + std::vector> results(n_threads); + + auto jit{ micm::JitCompiler::create() }; + JitRosenbrockSolver< + Group1VectorMatrix, + Group1SparseVectorMatrix, + JitLinearSolver<1, Group1SparseVectorMatrix> + > solver( + jit.get(), + chemical_system, + reactions, + RosenbrockSolverParameters::three_stage_rosenbrock_parameters() + ); + +#pragma omp parallel num_threads(n_threads) + { + auto state = solver.GetState(); + std::vector result = run_solver_on_thread_with_own_state(solver, state); + results[omp_get_thread_num()] = result; +#pragma omp barrier + } + + // compare each thread to thread 1 + for (int i = 1; i < n_threads; ++i) { + for (int j = 0; j < results[0].size(); ++j) { + EXPECT_EQ(results[0][j], results[i][j]); + } + } +} From aa5ea0c98875aec7b0c73b5f8786069871558203 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 15:15:52 -0500 Subject: [PATCH 08/30] removing data member --- include/micm/solver/rosenbrock.hpp | 1 - include/micm/solver/rosenbrock.inl | 13 +++---- test/integration/e5.hpp | 3 +- test/integration/hires.hpp | 3 +- test/integration/oregonator.hpp | 4 +- test/unit/openmp/run_solver.hpp | 40 ++++++++++++++++++++ test/unit/openmp/test_openmp.cpp | 41 +-------------------- test/unit/openmp/test_openmp_jit_solver.cpp | 41 +-------------------- 8 files changed, 55 insertions(+), 91 deletions(-) create mode 100644 test/unit/openmp/run_solver.hpp diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 32ca9dd12..91da3efed 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -208,7 +208,6 @@ namespace micm std::vector processes_; RosenbrockSolverParameters parameters_; StateParameters state_parameters_; - std::function& variables, const std::size_t i)> state_reordering_; ProcessSet process_set_; LinearSolverPolicy linear_solver_; size_t N_{}; diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 11b3579bc..67e9c35d3 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -438,7 +438,6 @@ namespace micm processes_(), parameters_(RosenbrockSolverParameters::three_stage_rosenbrock_parameters()), state_parameters_(), - state_reordering_(), process_set_(), linear_solver_(), N_(system_.StateSize() * parameters_.number_of_grid_cells_) @@ -470,15 +469,15 @@ namespace micm processes_(processes), parameters_(parameters), state_parameters_(), - state_reordering_(), process_set_(), linear_solver_(), N_(system_.StateSize() * parameters_.number_of_grid_cells_) { std::map variable_map; + std::function& variables, const std::size_t i)> state_reordering; std::size_t index = 0; - for (auto& name : system_.UniqueNames(state_reordering_)) + for (auto& name : system_.UniqueNames(state_reordering)) variable_map[name] = index++; // generate a state-vector reordering function to reduce fill-in in linear solver @@ -491,12 +490,12 @@ namespace micm for (auto& elem : unsorted_jac_elements) unsorted_jac_non_zeros[elem.first][elem.second] = 1; auto reorder_map = DiagonalMarkowitzReorder(unsorted_jac_non_zeros); - state_reordering_ = [=](const std::vector& variables, const std::size_t i) + state_reordering = [=](const std::vector& variables, const std::size_t i) { return variables[reorder_map[i]]; }; variable_map.clear(); std::size_t index = 0; - for (auto& name : system_.UniqueNames(state_reordering_)) + for (auto& name : system_.UniqueNames(state_reordering)) variable_map[name] = index++; } @@ -520,7 +519,7 @@ namespace micm jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); state_parameters_ = { - .variable_names_ = system_.UniqueNames(state_reordering_), + .variable_names_ = system_.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = parameters_.number_of_grid_cells_, .number_of_rate_constants_ = processes_.size(), @@ -803,8 +802,6 @@ namespace micm SolverStats& stats, State& state) { - // TODO: invesitage this function. The fortran equivalent appears to have a bug. - // From my understanding the fortran do loop would only ever do one iteration and is equivalent to what's below auto jacobian = state.jacobian_; uint64_t n_consecutive = 0; singular = false; diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 8a34ef6f6..6347453fb 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -41,8 +41,9 @@ class E5 : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(this->state_reordering_), + .variable_names_ = system.UniqueNames(state_reordering), .jacobian_diagonal_elements_ = jacobian_diagonal_elements, .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 64f177b41..881a022a4 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -42,8 +42,9 @@ class HIRES : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(this->state_reordering_), + .variable_names_ = system.UniqueNames(state_reordering), .jacobian_diagonal_elements_ = jacobian_diagonal_elements, .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index 8669aea18..1e125fa12 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -42,9 +42,9 @@ class Oregonator : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); - + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(this->state_reordering_), + .variable_names_ = system.UniqueNames(state_reordering), .jacobian_diagonal_elements_ = jacobian_diagonal_elements, .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, diff --git a/test/unit/openmp/run_solver.hpp b/test/unit/openmp/run_solver.hpp new file mode 100644 index 000000000..d1e01020e --- /dev/null +++ b/test/unit/openmp/run_solver.hpp @@ -0,0 +1,40 @@ +#pragma once + +std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) +{ + std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; + + // mol m-3 + state.variables_[0] = { 1, 0, 0 }; + + double k1 = 0.04; + double k2 = 3e7; + double k3 = 1e4; + state.SetCustomRateParameter("PHOTO.r1", k1); + state.SetCustomRateParameter("PHOTO.r2", k2); + state.SetCustomRateParameter("PHOTO.r3", k3); + + double temperature = 272.5; // [K] + double pressure = 101253.3; // [Pa] + double air_density = 1e6; // [mol m-3] + + state.conditions_[0].temperature_ = temperature; + state.conditions_[0].pressure_ = pressure; + state.conditions_[0].air_density_ = air_density; + + double time_step = 200; // s + + for (int i = 0; i < 10; ++i) + { + double elapsed_solve_time = 0; + + while (elapsed_solve_time < time_step) + { + auto result = solver.Solve(time_step - elapsed_solve_time, state); + elapsed_solve_time = result.final_time_; + state.variables_ = result.result_; + } + } + + return state.variables_.AsVector(); +} \ No newline at end of file diff --git a/test/unit/openmp/test_openmp.cpp b/test/unit/openmp/test_openmp.cpp index d284bd16b..575c12a24 100644 --- a/test/unit/openmp/test_openmp.cpp +++ b/test/unit/openmp/test_openmp.cpp @@ -4,46 +4,9 @@ #include #include -using namespace micm; - -std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) -{ - std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; - - // mol m-3 - state.variables_[0] = { 1, 0, 0 }; - - double k1 = 0.04; - double k2 = 3e7; - double k3 = 1e4; - state.SetCustomRateParameter("PHOTO.r1", k1); - state.SetCustomRateParameter("PHOTO.r2", k2); - state.SetCustomRateParameter("PHOTO.r3", k3); - - double temperature = 272.5; // [K] - double pressure = 101253.3; // [Pa] - double air_density = 1e6; // [mol m-3] - - state.conditions_[0].temperature_ = temperature; - state.conditions_[0].pressure_ = pressure; - state.conditions_[0].air_density_ = air_density; - - double time_step = 200; // s +#include "run_solver.hpp" - for (int i = 0; i < 10; ++i) - { - double elapsed_solve_time = 0; - - while (elapsed_solve_time < time_step) - { - auto result = solver.Solve(time_step - elapsed_solve_time, state); - elapsed_solve_time = result.final_time_; - state.variables_ = result.result_; - } - } - - return state.variables_.AsVector(); -} +using namespace micm; TEST(OpenMP, OneSolverManyStates) { diff --git a/test/unit/openmp/test_openmp_jit_solver.cpp b/test/unit/openmp/test_openmp_jit_solver.cpp index 479d3e5c5..5e43588a1 100644 --- a/test/unit/openmp/test_openmp_jit_solver.cpp +++ b/test/unit/openmp/test_openmp_jit_solver.cpp @@ -6,6 +6,8 @@ #include #include +#include "run_solver.hpp" + using namespace micm; template @@ -13,45 +15,6 @@ using Group1VectorMatrix = micm::VectorMatrix; template using Group1SparseVectorMatrix = micm::SparseMatrix>; -std::vector run_solver_on_thread_with_own_state(auto& solver, auto& state) -{ - std::cout << "Running solver on thread " << omp_get_thread_num() << std::endl; - - // mol m-3 - state.variables_[0] = { 1, 0, 0 }; - - double k1 = 0.04; - double k2 = 3e7; - double k3 = 1e4; - state.SetCustomRateParameter("PHOTO.r1", k1); - state.SetCustomRateParameter("PHOTO.r2", k2); - state.SetCustomRateParameter("PHOTO.r3", k3); - - double temperature = 272.5; // [K] - double pressure = 101253.3; // [Pa] - double air_density = 1e6; // [mol m-3] - - state.conditions_[0].temperature_ = temperature; - state.conditions_[0].pressure_ = pressure; - state.conditions_[0].air_density_ = air_density; - - double time_step = 200; // s - - for (int i = 0; i < 10; ++i) - { - double elapsed_solve_time = 0; - - while (elapsed_solve_time < time_step) - { - auto result = solver.Solve(time_step - elapsed_solve_time, state); - elapsed_solve_time = result.final_time_; - state.variables_ = result.result_; - } - } - - return state.variables_.AsVector(); -} - TEST(OpenMP, JITOneSolverManyStates) { constexpr size_t n_threads = 8; From 2dc189c0f8af9cc54d066b1d2baafc38c31cc4c6 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 15:23:15 -0500 Subject: [PATCH 09/30] removing N --- include/micm/solver/rosenbrock.hpp | 1 - include/micm/solver/rosenbrock.inl | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 91da3efed..5178dfd49 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -210,7 +210,6 @@ namespace micm StateParameters state_parameters_; ProcessSet process_set_; LinearSolverPolicy linear_solver_; - size_t N_{}; static constexpr double delta_min_ = 1.0e-6; diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 67e9c35d3..fd7e821cb 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -439,8 +439,7 @@ namespace micm parameters_(RosenbrockSolverParameters::three_stage_rosenbrock_parameters()), state_parameters_(), process_set_(), - linear_solver_(), - N_(system_.StateSize() * parameters_.number_of_grid_cells_) + linear_solver_() { } @@ -470,8 +469,7 @@ namespace micm parameters_(parameters), state_parameters_(), process_set_(), - linear_solver_(), - N_(system_.StateSize() * parameters_.number_of_grid_cells_) + linear_solver_() { std::map variable_map; std::function& variables, const std::size_t i)> state_reordering; @@ -519,10 +517,10 @@ namespace micm jacobian_diagonal_elements.push_back(jacobian.VectorIndex(0, i, i)); state_parameters_ = { - .variable_names_ = system_.UniqueNames(state_reordering), - .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = parameters_.number_of_grid_cells_, .number_of_rate_constants_ = processes_.size(), + .variable_names_ = system_.UniqueNames(state_reordering), + .custom_rate_parameter_labels_ = param_labels, .nonzero_jacobian_elements_ = process_set_.NonZeroJacobianElements(), .jacobian_diagonal_elements_ = jacobian_diagonal_elements }; @@ -839,10 +837,11 @@ namespace micm auto _y = Y.AsVector(); auto _ynew = Ynew.AsVector(); auto _errors = errors.AsVector(); + size_t N = Y.AsVector().size(); double error = 0; - for (size_t i = 0; i < N_; ++i) + for (size_t i = 0; i < N; ++i) { double ymax = std::max(std::abs(_y[i]), std::abs(_ynew[i])); double scale = parameters_.absolute_tolerance_ + parameters_.relative_tolerance_ * ymax; @@ -850,7 +849,7 @@ namespace micm } double error_min_ = 1.0e-10; - return std::max(std::sqrt(error / N_), error_min_); + return std::max(std::sqrt(error / N), error_min_); } } // namespace micm From c203293a1e8ff0b8ea4f05846fbbe20f7eba0ddd Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 15:50:04 -0500 Subject: [PATCH 10/30] ordering state parameters --- test/integration/e5.hpp | 8 ++++---- test/integration/hires.hpp | 8 ++++---- test/integration/oregonator.hpp | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 2c1d87fc6..d45964387 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -45,12 +45,12 @@ class E5 : public micm::RosenbrockSolver& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(state_reordering), - .jacobian_diagonal_elements_ = jacobian_diagonal_elements, - .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), - .nonzero_jacobian_elements_ = nonzero_jacobian_elements + .variable_names_ = system.UniqueNames(state_reordering), + .custom_rate_parameter_labels_ = param_labels, + .nonzero_jacobian_elements_ = nonzero_jacobian_elements, + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 63ce72ccb..f10b463d6 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -46,12 +46,12 @@ class HIRES : public micm::RosenbrockSolver& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(state_reordering), - .jacobian_diagonal_elements_ = jacobian_diagonal_elements, - .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), - .nonzero_jacobian_elements_ = nonzero_jacobian_elements + .variable_names_ = system.UniqueNames(state_reordering), + .custom_rate_parameter_labels_ = param_labels, + .nonzero_jacobian_elements_ = nonzero_jacobian_elements, + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index 6547e0cb9..7c038710e 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -46,12 +46,12 @@ class Oregonator : public micm::RosenbrockSolver& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { - .variable_names_ = system.UniqueNames(state_reordering), - .jacobian_diagonal_elements_ = jacobian_diagonal_elements, - .custom_rate_parameter_labels_ = param_labels, .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), - .nonzero_jacobian_elements_ = nonzero_jacobian_elements + .variable_names_ = system.UniqueNames(state_reordering), + .custom_rate_parameter_labels_ = param_labels, + .nonzero_jacobian_elements_ = nonzero_jacobian_elements, + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; this->linear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); From 7afb07673ffdc05918069b58ddde8e18f70c9703 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 15:56:16 -0500 Subject: [PATCH 11/30] more ordering... --- test/unit/process/test_process_set_policy.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/unit/process/test_process_set_policy.hpp b/test/unit/process/test_process_set_policy.hpp index a6a749c66..a95193140 100644 --- a/test/unit/process/test_process_set_policy.hpp +++ b/test/unit/process/test_process_set_policy.hpp @@ -26,9 +26,8 @@ void testProcessSet( micm::Phase gas_phase{ std::vector{ foo, bar, qux, baz, quz, quuz } }; - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, - .number_of_grid_cells_ = 2, - .number_of_rate_constants_ = 3 } }; + micm::State state{ micm::StateParameters{ + .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3 } }; micm::Process r1 = micm::Process::create().reactants({ foo, baz }).products({ yields(bar, 1), yields(quuz, 2.4) }).phase(gas_phase); @@ -136,9 +135,11 @@ void testRandomSystem( species_names.push_back(std::to_string(i)); } micm::Phase gas_phase{ species }; - micm::State state{ micm::StateParameters{ .variable_names_{ species_names }, - .number_of_grid_cells_ = n_cells, - .number_of_rate_constants_ = n_reactions } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = n_cells, + .number_of_rate_constants_ = n_reactions, + .variable_names_{ species_names }, + } }; std::vector processes{}; for (std::size_t i = 0; i < n_reactions; ++i) { From d013616fec871222233b861bed58fe2f00f6771f Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 16:02:55 -0500 Subject: [PATCH 12/30] ordering --- test/unit/process/test_process.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/unit/process/test_process.cpp b/test/unit/process/test_process.cpp index a3112e573..3529540dc 100644 --- a/test/unit/process/test_process.cpp +++ b/test/unit/process/test_process.cpp @@ -30,9 +30,10 @@ void testProcessUpdateState(const std::size_t number_of_grid_cells) for (const auto& process : processes) for (auto& label : process.rate_constant_->CustomParameters()) param_labels.push_back(label); - micm::State state{ micm::StateParameters{ .custom_rate_parameter_labels_ = param_labels, - .number_of_grid_cells_ = number_of_grid_cells, - .number_of_rate_constants_ = processes.size() } }; + micm::State state{ micm::StateParameters{ .number_of_grid_cells_ = number_of_grid_cells, + .number_of_rate_constants_ = processes.size(), + .custom_rate_parameter_labels_ = param_labels, + } }; MatrixPolicy expected_rate_constants(number_of_grid_cells, 3, 0.0); std::vector params = { 0.0, 0.0, 0.0 }; From aedb60ec77a096f5030872990e14926a00062731 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 23 Oct 2023 16:10:19 -0500 Subject: [PATCH 13/30] ordering --- test/unit/process/test_process_set_policy.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/process/test_process_set_policy.hpp b/test/unit/process/test_process_set_policy.hpp index a95193140..afb0158e4 100644 --- a/test/unit/process/test_process_set_policy.hpp +++ b/test/unit/process/test_process_set_policy.hpp @@ -27,7 +27,7 @@ void testProcessSet( micm::Phase gas_phase{ std::vector{ foo, bar, qux, baz, quz, quuz } }; micm::State state{ micm::StateParameters{ - .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3 } }; + .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3 }, .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, }; micm::Process r1 = micm::Process::create().reactants({ foo, baz }).products({ yields(bar, 1), yields(quuz, 2.4) }).phase(gas_phase); From 732e7b9808e33a99bc8716535372f7efac028eca Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Tue, 24 Oct 2023 11:48:07 -0500 Subject: [PATCH 14/30] fixing some things? --- docker/Dockerfile | 2 +- include/micm/process/jit_process_set.hpp | 8 +++---- include/micm/process/process_set.hpp | 4 ++-- test/unit/process/test_jit_process_set.cpp | 10 ++++----- test/unit/process/test_process_set.cpp | 22 +++++++++---------- test/unit/process/test_process_set_policy.hpp | 13 ++++++----- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1954e7222..c13d0eaa4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,7 +20,7 @@ RUN mkdir /build \ -D CMAKE_BUILD_TYPE=debug \ -D ENABLE_CLANG_TIDY:BOOL=FALSE \ ../micm \ - && make install -j 8 + && make install # now test if we can use the installed files RUN cd /micm/test/integration/cmake/find_package \ diff --git a/include/micm/process/jit_process_set.hpp b/include/micm/process/jit_process_set.hpp index c04f0d969..52351c879 100644 --- a/include/micm/process/jit_process_set.hpp +++ b/include/micm/process/jit_process_set.hpp @@ -33,11 +33,11 @@ namespace micm /// @param compiler JIT compiler /// @param processes Processes to create calculator for /// @param state Solver state - template class MatrixPolicy> + template class MatrixPolicy, template class SparseMatrixPolicy> JitProcessSet( std::shared_ptr compiler, const std::vector &processes, - const State &state); + const State &state); ~JitProcessSet(); @@ -103,11 +103,11 @@ namespace micm } template - template class MatrixPolicy> + template class MatrixPolicy, template class SparseMatrixPolicy> inline JitProcessSet::JitProcessSet( std::shared_ptr compiler, const std::vector &processes, - const State &state) + const State &state) : ProcessSet(processes, state.variable_map_), compiler_(compiler) { diff --git a/include/micm/process/process_set.hpp b/include/micm/process/process_set.hpp index bb8ffa49c..f7836f7c6 100644 --- a/include/micm/process/process_set.hpp +++ b/include/micm/process/process_set.hpp @@ -30,7 +30,7 @@ namespace micm /// @brief Create a process set calculator for a given set of processes /// @param processes Processes to create calculator for /// @param StateParameters Solver state - ProcessSet(const std::vector& processes, std::map variable_map); + ProcessSet(const std::vector& processes, const std::map& variable_map); /// @brief Return the full set of non-zero Jacobian elements for the set of processes /// @return Jacobian elements as a set of index pairs @@ -73,7 +73,7 @@ namespace micm SparseMatrixPolicy& jacobian) const; }; - inline ProcessSet::ProcessSet(const std::vector& processes, std::map variable_map) + inline ProcessSet::ProcessSet(const std::vector& processes, const std::map& variable_map) : number_of_reactants_(), reactant_ids_(), number_of_products_(), diff --git a/test/unit/process/test_jit_process_set.cpp b/test/unit/process/test_jit_process_set.cpp index 51190bfd5..f685ff8b0 100644 --- a/test/unit/process/test_jit_process_set.cpp +++ b/test/unit/process/test_jit_process_set.cpp @@ -30,7 +30,7 @@ TEST(JitProcessSet, VectorMatrix) } testProcessSet>( [&](const std::vector& processes, - const micm::State& state) -> micm::JitProcessSet<2> { + const micm::State& state) -> micm::JitProcessSet<2> { return micm::JitProcessSet<2>{ jit.get(), processes, state }; }); } @@ -43,7 +43,7 @@ TEST(RandomJitProcessSet, VectorMatrix) llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), "[JIT Error]"); EXPECT_TRUE(false); } - testRandomSystem>( + testRandomSystem>( 2000, 20, 30, @@ -51,7 +51,7 @@ TEST(RandomJitProcessSet, VectorMatrix) const micm::State& state) -> micm::JitProcessSet<2000> { return micm::JitProcessSet<2000>{ jit.get(), processes, state }; }); - testRandomSystem>( + testRandomSystem>( 3000, 50, 40, @@ -59,7 +59,7 @@ TEST(RandomJitProcessSet, VectorMatrix) const micm::State& state) -> micm::JitProcessSet<3000> { return micm::JitProcessSet<3000>{ jit.get(), processes, state }; }); - testRandomSystem>( + testRandomSystem>( 3000, 30, 20, @@ -67,7 +67,7 @@ TEST(RandomJitProcessSet, VectorMatrix) const micm::State& state) -> micm::JitProcessSet<3000> { return micm::JitProcessSet<3000>{ jit.get(), processes, state }; }); - testRandomSystem>( + testRandomSystem>( 4000, 100, 80, diff --git a/test/unit/process/test_process_set.cpp b/test/unit/process/test_process_set.cpp index 95a57fbba..ba7a51d85 100644 --- a/test/unit/process/test_process_set.cpp +++ b/test/unit/process/test_process_set.cpp @@ -34,7 +34,7 @@ using Group4SparseVectorMatrix = micm::SparseMatrix( - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); } @@ -42,44 +42,44 @@ TEST(ProcessSet, Matrix) TEST(ProcessSet, VectorMatrix) { testProcessSet( - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); testProcessSet( - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); } TEST(RandomProcessSet, Matrix) { - testRandomSystem( + testRandomSystem( 2000, 500, 400, - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); - testRandomSystem( + testRandomSystem( 3000, 300, 200, - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); - testRandomSystem( + testRandomSystem( 4000, 100, 80, - [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { + [](const std::vector& processes, const micm::State& state) -> micm::ProcessSet { return micm::ProcessSet{ processes, state.variable_map_ }; }); } \ No newline at end of file diff --git a/test/unit/process/test_process_set_policy.hpp b/test/unit/process/test_process_set_policy.hpp index afb0158e4..e8609b605 100644 --- a/test/unit/process/test_process_set_policy.hpp +++ b/test/unit/process/test_process_set_policy.hpp @@ -14,7 +14,7 @@ void compare_pair(const index_pair& a, const index_pair& b) template class MatrixPolicy, template class SparseMatrixPolicy, class ProcessSetPolicy> void testProcessSet( - const std::function&, const micm::State&)> create_set) + const std::function&, const micm::State&)> create_set) { auto foo = micm::Species("foo"); auto bar = micm::Species("bar"); @@ -26,8 +26,9 @@ void testProcessSet( micm::Phase gas_phase{ std::vector{ foo, bar, qux, baz, quz, quuz } }; - micm::State state{ micm::StateParameters{ - .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3 }, .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }, }; + micm::State state( + micm::StateParameters{ .number_of_grid_cells_ = 2, .number_of_rate_constants_ = 3, + .variable_names_{ "foo", "bar", "baz", "quz", "quuz" }}); micm::Process r1 = micm::Process::create().reactants({ foo, baz }).products({ yields(bar, 1), yields(quuz, 2.4) }).phase(gas_phase); @@ -115,12 +116,12 @@ void testProcessSet( EXPECT_EQ(jacobian[1][4][2], 100.0 + 2.4 * 110.0 * 1.1); } -template class MatrixPolicy, class ProcessSetPolicy> +template class MatrixPolicy, template class SparseMatrixPolicy, class ProcessSetPolicy> void testRandomSystem( std::size_t n_cells, std::size_t n_reactions, std::size_t n_species, - const std::function&, const micm::State&)> create_set) + const std::function&, const micm::State&)> create_set) { auto get_n_react = std::bind(std::uniform_int_distribution<>(0, 3), std::default_random_engine()); auto get_n_product = std::bind(std::uniform_int_distribution<>(0, 10), std::default_random_engine()); @@ -135,7 +136,7 @@ void testRandomSystem( species_names.push_back(std::to_string(i)); } micm::Phase gas_phase{ species }; - micm::State state{ micm::StateParameters{ + micm::State state{ micm::StateParameters{ .number_of_grid_cells_ = n_cells, .number_of_rate_constants_ = n_reactions, .variable_names_{ species_names }, From 1c07420a1a44e8f5c6b88f599905d9353ac604c8 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Tue, 24 Oct 2023 12:32:51 -0500 Subject: [PATCH 15/30] thing --- test/unit/solver/test_state.cpp | 100 +++++++++++++++++++------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/test/unit/solver/test_state.cpp b/test/unit/solver/test_state.cpp index 0143cfa3c..db8217afd 100644 --- a/test/unit/solver/test_state.cpp +++ b/test/unit/solver/test_state.cpp @@ -4,10 +4,12 @@ TEST(State, Constructor) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = 3, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 3, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; EXPECT_EQ(state.conditions_.size(), 3); EXPECT_EQ(state.variable_map_["foo"], 0); @@ -26,10 +28,12 @@ TEST(State, Constructor) TEST(State, SettingSingleConcentrationWithInvalidArgumentsThowsException) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = 3, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 3, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; EXPECT_ANY_THROW(state.SetConcentration(micm::Species{ "foo" }, 1.0)); EXPECT_ANY_THROW(state.SetConcentration(micm::Species{ "foo" }, std::vector{ 1.0, 2.0 })); EXPECT_ANY_THROW(state.SetConcentration(micm::Species{ "not foo" }, 1.0)); @@ -39,20 +43,24 @@ TEST(State, SettingSingleConcentrationWithInvalidArgumentsThowsException) TEST(State, SetSingleConcentration) { { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = 3, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 3, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; std::vector concentrations{ 12.0, 42.0, 35.2 }; state.SetConcentration(micm::Species{ "bar" }, concentrations); for (std::size_t i = 0; i < concentrations.size(); ++i) EXPECT_EQ(state.variables_[i][state.variable_map_["bar"]], concentrations[i]); } { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = 1, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; state.SetConcentration(micm::Species{ "bar" }, 324.2); EXPECT_EQ(state.variables_[0][state.variable_map_["bar"]], 324.2); } @@ -60,10 +68,12 @@ TEST(State, SetSingleConcentration) TEST(State, SettingConcentrationsWithInvalidArguementsThrowsException) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = 3, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 3, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; std::unordered_map> concentrations = { { "FUU", { 0.1 } }, { "bar", { 0.2 } }, { "baz", { 0.3 } }, { "quz", { 0.4 } } @@ -77,10 +87,12 @@ TEST(State, SetConcentrations) uint32_t num_grid_cells = 3; uint32_t num_species = 4; - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "quux", "corge" }, - .number_of_grid_cells_ = num_grid_cells, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = num_grid_cells, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "quux", "corge" }, + } }; std::unordered_map> concentrations = { { "bar", { 0.2, 0.22, 0.222 } }, { "baz", { 0.3, 0.33, 0.333 } }, @@ -106,10 +118,12 @@ TEST(State, SetConcentrations) TEST(State, SettingCustomRateParameterWithInvalidVectorSizeThrowsException) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, - .number_of_grid_cells_ = 3, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 3, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, + } }; // user input for custom rate parameters (unordered) std::unordered_map> custom_params = { @@ -121,10 +135,12 @@ TEST(State, SettingCustomRateParameterWithInvalidVectorSizeThrowsException) TEST(State, SettingCustomRateParameterWithInvalidLabelThrowsException) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, - .number_of_grid_cells_ = 1, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, + } }; // user input for custom rate parameters (unordered) std::unordered_map> custom_params = { @@ -136,10 +152,12 @@ TEST(State, SettingCustomRateParameterWithInvalidLabelThrowsException) TEST(State, SetCustomRateParameter) { - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, - .number_of_grid_cells_ = 1, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, + } }; state.SetCustomRateParameter("O2", 42.3); EXPECT_EQ(state.custom_rate_parameters_[0][1], 42.3); @@ -149,10 +167,12 @@ TEST(State, SetCustomRateParameters) { uint32_t num_grid_cells = 3; - micm::State state{ micm::StateParameters{ .variable_names_{ "foo", "bar", "baz", "quz" }, - .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, - .number_of_grid_cells_ = num_grid_cells, - .number_of_rate_constants_ = 10 } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = num_grid_cells, + .number_of_rate_constants_ = 10, + .variable_names_{ "foo", "bar", "baz", "quz" }, + .custom_rate_parameter_labels_{ "O1", "O2", "O3", "AAA", "BBB" }, + } }; // user input for custom rate parameters (unordered) std::unordered_map> custom_params = { { "O3", { 0.3, 0.33, 0.333 } }, From 430864ce744a56467707e861d85c847e477ea811 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Tue, 24 Oct 2023 14:48:17 -0500 Subject: [PATCH 16/30] fixing cuda stuff? --- docker/Dockerfile | 2 +- include/micm/process/cuda_process_set.hpp | 18 +++++-------- include/micm/solver/cuda_lu_decomposition.hpp | 9 +++---- include/micm/solver/rosenbrock.inl | 1 - include/micm/util/cuda_param.hpp | 10 ++++--- src/CMakeLists.txt | 4 --- test/unit/process/test_cuda_process_set.cpp | 26 +++++++++++-------- 7 files changed, 31 insertions(+), 39 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index c13d0eaa4..89d7c89ea 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,7 +20,7 @@ RUN mkdir /build \ -D CMAKE_BUILD_TYPE=debug \ -D ENABLE_CLANG_TIDY:BOOL=FALSE \ ../micm \ - && make install + && make install -j # now test if we can use the installed files RUN cd /micm/test/integration/cmake/find_package \ diff --git a/include/micm/process/cuda_process_set.hpp b/include/micm/process/cuda_process_set.hpp index e3f352fcc..31b3d580a 100644 --- a/include/micm/process/cuda_process_set.hpp +++ b/include/micm/process/cuda_process_set.hpp @@ -5,12 +5,8 @@ #include #include +#include -#ifdef USE_CUDA -# include -#endif - -#ifdef USE_CUDA namespace micm { /// @brief A GPU-based implementation of ProcessSet @@ -20,8 +16,7 @@ namespace micm /// @brief Create a process set calculator for a given set of processes /// @param processes Processes to create calculator for /// @param state Solver state - template class MatrixPolicy> - CudaProcessSet(const std::vector& processes, const State& state); + CudaProcessSet(const std::vector& processes, const std::map& variable_map); template typename MatrixPolicy> requires VectorizableDense> std::chrono::nanoseconds AddForcingTerms( @@ -39,9 +34,8 @@ namespace micm const; }; - template class MatrixPolicy> - inline CudaProcessSet::CudaProcessSet(const std::vector& processes, const State& state) - : ProcessSet(processes, state) + inline CudaProcessSet::CudaProcessSet(const std::vector& processes, const std::map& variable_map) + : ProcessSet(processes, variable_map) { } @@ -73,6 +67,7 @@ namespace micm std::chrono::nanoseconds kernel_duration = micm::cuda::AddForcingTermsKernelDriver(matrix, processSet); return kernel_duration; // time performance of kernel function } + template class MatrixPolicy, template class SparseMatrixPolicy> requires VectorizableDense> && VectorizableSparse> inline std::chrono::nanoseconds CudaProcessSet::AddJacobianTerms( @@ -104,5 +99,4 @@ namespace micm std::chrono::nanoseconds kernel_duration = micm::cuda::AddJacobianTermsKernelDriver(matrix, sparseMatrix, processSet); return kernel_duration; // time performance of kernel function } -} // namespace micm -#endif \ No newline at end of file +} // namespace micm \ No newline at end of file diff --git a/include/micm/solver/cuda_lu_decomposition.hpp b/include/micm/solver/cuda_lu_decomposition.hpp index 7f2d33e17..85aca2a75 100644 --- a/include/micm/solver/cuda_lu_decomposition.hpp +++ b/include/micm/solver/cuda_lu_decomposition.hpp @@ -2,15 +2,13 @@ // // SPDX-License-Identifier: Apache-2.0 #pragma once + #include #include #include #include -#ifdef USE_CUDA -# include -#endif +#include -#ifdef USE_CUDA namespace micm { class CudaLuDecomposition : public LuDecomposition @@ -64,5 +62,4 @@ namespace micm // calling kernelSetup function return micm::cuda::DecomposeKernelDriver(sparseMatrix, solver); } -} // namespace micm -#endif \ No newline at end of file +} // namespace micm \ No newline at end of file diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index fd7e821cb..fbd2ddbf5 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -429,7 +429,6 @@ namespace micm case SolverState::NaNDetected: return "NaNDetected"; default: return "Unknown"; } - return ""; } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> diff --git a/include/micm/util/cuda_param.hpp b/include/micm/util/cuda_param.hpp index 2d95a1ec3..759e2bf4b 100644 --- a/include/micm/util/cuda_param.hpp +++ b/include/micm/util/cuda_param.hpp @@ -1,7 +1,10 @@ +// Copyright (C) 2023 National Center for Atmospheric Research, +// +// SPDX-License-Identifier: Apache-2.0 +#pragma once + #include -#ifndef CUDA_PARAM_HPP -# define CUDA_PARAM_HPP // member data of class CudaProcessSet grouped in struct passing to kernel driver function const size_t BLOCK_SIZE = 320; struct CudaProcessSetParam @@ -63,5 +66,4 @@ struct CudaSparseMatrixParam double* U_; size_t U_size_; size_t n_grids_; -}; -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1766b5172..65e71697f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,10 +80,6 @@ if(ENABLE_CUDA) PUBLIC cudart ) - target_compile_definitions(micm_cuda - PUBLIC - USE_CUDA - ) endif() add_subdirectory(process) diff --git a/test/unit/process/test_cuda_process_set.cpp b/test/unit/process/test_cuda_process_set.cpp index 2fbdc9bd2..cf063e97c 100644 --- a/test/unit/process/test_cuda_process_set.cpp +++ b/test/unit/process/test_cuda_process_set.cpp @@ -38,10 +38,12 @@ void testRandomSystemAddForcingTerms(std::size_t n_cells, std::size_t n_reaction species_names.push_back(std::to_string(i)); } micm::Phase gas_phase{ species }; - micm::State state{ micm::StateParameters{ .state_variable_names_{ species_names }, - .custom_rate_parameter_labels_{}, - .number_of_grid_cells_ = n_cells, - .number_of_rate_constants_ = n_reactions } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = n_cells, + .number_of_rate_constants_ = n_reactions, + .variable_names_{ species_names }, + .custom_rate_parameter_labels_{}, + } }; std::vector processes{}; for (std::size_t i = 0; i < n_reactions; ++i) @@ -61,8 +63,8 @@ void testRandomSystemAddForcingTerms(std::size_t n_cells, std::size_t n_reaction processes.push_back(micm::Process::create().reactants(reactants).products(products).phase(gas_phase)); } - micm::ProcessSet cpu_set{ processes, state }; - micm::CudaProcessSet gpu_set{ processes, state }; + micm::ProcessSet cpu_set{ processes, state.variable_map_ }; + micm::CudaProcessSet gpu_set{ processes, state.variable_map_ }; for (auto& elem : state.variables_.AsVector()) elem = get_double(); @@ -110,9 +112,11 @@ void testRandomSystemAddJacobianTerms(std::size_t n_cells, std::size_t n_reactio species_names.push_back(std::to_string(i)); } micm::Phase gas_phase{ species }; - micm::State state{ micm::StateParameters{ .state_variable_names_{ species_names }, - .number_of_grid_cells_ = n_cells, - .number_of_rate_constants_ = n_reactions } }; + micm::State state{ micm::StateParameters{ + .number_of_grid_cells_ = n_cells, + .number_of_rate_constants_ = n_reactions, + .variable_names_{ species_names }, + } }; std::vector processes{}; for (std::size_t i = 0; i < n_reactions; ++i) @@ -132,8 +136,8 @@ void testRandomSystemAddJacobianTerms(std::size_t n_cells, std::size_t n_reactio processes.push_back(micm::Process::create().reactants(reactants).products(products).phase(gas_phase)); } - micm::ProcessSet cpu_set{ processes, state }; - micm::CudaProcessSet gpu_set{ processes, state }; + micm::ProcessSet cpu_set{ processes, state.variable_map_ }; + micm::CudaProcessSet gpu_set{ processes, state.variable_map_ }; for (auto& elem : state.variables_.AsVector()) elem = get_double(); From 2219aa59857c8d95c1d46d925d7877cafbb5dde5 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Wed, 25 Oct 2023 11:57:34 -0500 Subject: [PATCH 17/30] correcting analytical tests --- include/micm/solver/rosenbrock.hpp | 2 +- include/micm/solver/rosenbrock.inl | 3 +-- include/micm/solver/state.hpp | 1 - test/integration/e5.hpp | 26 +++++++++++++++++++++----- test/integration/hires.hpp | 24 ++++++++++++++++++++---- test/integration/oregonator.hpp | 24 ++++++++++++++++++++---- 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 91ff868ce..f25ebffe9 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -241,7 +241,7 @@ namespace micm /// @brief Returns a state object for use with the solver /// @return A object that can hold the full state of the chemical system - State GetState() const; + virtual State GetState() const; /// @brief Advances the given step over the specified time step /// @param time_step Time [s] to advance the state by diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index fbd2ddbf5..54b98809b 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -520,7 +520,6 @@ namespace micm .number_of_rate_constants_ = processes_.size(), .variable_names_ = system_.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, - .nonzero_jacobian_elements_ = process_set_.NonZeroJacobianElements(), .jacobian_diagonal_elements_ = jacobian_diagonal_elements }; @@ -534,7 +533,7 @@ namespace micm auto state = State{ state_parameters_ }; state.jacobian_ = build_jacobian( - state_parameters_.nonzero_jacobian_elements_, + process_set_.NonZeroJacobianElements(), state_parameters_.number_of_grid_cells_, system_.StateSize() ); diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index 305c0a0c7..acc9d7bc1 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -24,7 +24,6 @@ namespace micm std::map custom_rate_parameter_map_; std::vector variable_names_{}; std::vector custom_rate_parameter_labels_{}; - std::set> nonzero_jacobian_elements_; std::vector jacobian_diagonal_elements_; }; diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index d45964387..3dbc37f17 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -8,6 +8,8 @@ template< class LinearSolverPolicy = micm::LinearSolver> class E5 : public micm::RosenbrockSolver { + std::set> nonzero_jacobian_elements_; + public: /// @brief Builds a Rosenbrock solver for the given system, processes, and solver parameters /// @param system The chemical system to create the solver for @@ -22,13 +24,12 @@ class E5 : public micm::RosenbrockSolverparameters_ = parameters; auto builder = SparseMatrixPolicy::create(4).number_of_blocks(1).initial_value(0.0); - std::set> nonzero_jacobian_elements; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { builder = builder.with_element(i, j); - nonzero_jacobian_elements.insert(std::make_pair(i, j)); + nonzero_jacobian_elements_.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -42,14 +43,13 @@ class E5 : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); - - std::function& variables, const std::size_t i)> state_reordering; + + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), .variable_names_ = system.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, - .nonzero_jacobian_elements_ = nonzero_jacobian_elements, .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; @@ -60,6 +60,22 @@ class E5 : public micm::RosenbrockSolver GetState() const override + { + auto state = micm::State{ this->state_parameters_ }; + + state.jacobian_ = micm::build_jacobian( + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + + auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + state.lower_matrix_ = lower_matrix; + state.upper_matrix_ = upper_matrix; + + return state; + } + /// @brief Calculate a chemical forcing /// @param rate_constants List of rate constants for each needed species /// @param number_densities The number density of each species diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index f10b463d6..5396fe4cf 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -8,6 +8,8 @@ template< class LinearSolverPolicy = micm::LinearSolver> class HIRES : public micm::RosenbrockSolver { + std::set> nonzero_jacobian_elements_; + public: /// @brief Builds a Rosenbrock solver for the given system, processes, and solver parameters /// @param system The chemical system to create the solver for @@ -23,13 +25,12 @@ class HIRES : public micm::RosenbrockSolverparameters_ = parameters; auto builder = SparseMatrixPolicy::create(8).number_of_blocks(1).initial_value(0.0); - std::set> nonzero_jacobian_elements; for (int i = 0; i < 8; ++i) { for (int j = 0; j < 8; ++j) { builder = builder.with_element(i, j); - nonzero_jacobian_elements.insert(std::make_pair(i, j)); + nonzero_jacobian_elements_.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -43,14 +44,13 @@ class HIRES : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); - + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), .variable_names_ = system.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, - .nonzero_jacobian_elements_ = nonzero_jacobian_elements, .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; @@ -61,6 +61,22 @@ class HIRES : public micm::RosenbrockSolver GetState() const override + { + auto state = micm::State{ this->state_parameters_ }; + + state.jacobian_ = micm::build_jacobian( + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + + auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + state.lower_matrix_ = lower_matrix; + state.upper_matrix_ = upper_matrix; + + return state; + } + /// @brief Calculate a chemical forcing /// @param rate_constants List of rate constants for each needed species /// @param number_densities The number density of each species diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index 7c038710e..4f01511d7 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -8,6 +8,8 @@ template< class LinearSolverPolicy = micm::LinearSolver> class Oregonator : public micm::RosenbrockSolver { + std::set> nonzero_jacobian_elements_; + public: /// @brief Builds a Rosenbrock solver for the given system, processes, and solver parameters /// @param system The chemical system to create the solver for @@ -23,13 +25,12 @@ class Oregonator : public micm::RosenbrockSolverparameters_ = parameters; auto builder = SparseMatrixPolicy::create(3).number_of_blocks(1).initial_value(0.0); - std::set> nonzero_jacobian_elements; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { builder = builder.with_element(i, j); - nonzero_jacobian_elements.insert(std::make_pair(i, j)); + nonzero_jacobian_elements_.insert(std::make_pair(i, j)); } } SparseMatrixPolicy jacobian = SparseMatrixPolicy(builder); @@ -43,14 +44,13 @@ class Oregonator : public micm::RosenbrockSolverCustomParameters()) param_labels.push_back(label); - + std::function& variables, const std::size_t i)> state_reordering; this->state_parameters_ = { .number_of_grid_cells_ = 1, .number_of_rate_constants_ = processes.size(), .variable_names_ = system.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, - .nonzero_jacobian_elements_ = nonzero_jacobian_elements, .jacobian_diagonal_elements_ = jacobian_diagonal_elements, }; @@ -61,6 +61,22 @@ class Oregonator : public micm::RosenbrockSolver GetState() const override + { + auto state = micm::State{ this->state_parameters_ }; + + state.jacobian_ = micm::build_jacobian( + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + + auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + state.lower_matrix_ = lower_matrix; + state.upper_matrix_ = upper_matrix; + + return state; + } + /// @brief Calculate a chemical forcing /// @param rate_constants List of rate constants for each needed species /// @param number_densities The number density of each species From 27093e66f1aa0249221fea8edd962f124803c71c Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Wed, 25 Oct 2023 12:23:10 -0500 Subject: [PATCH 18/30] removing duplicate linkage of LLVM with the tests --- cmake/test_util.cmake | 8 -------- include/micm/solver/state.hpp | 1 - src/CMakeLists.txt | 4 ++++ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cmake/test_util.cmake b/cmake/test_util.cmake index eb843efc6..c369165d1 100644 --- a/cmake/test_util.cmake +++ b/cmake/test_util.cmake @@ -25,14 +25,6 @@ function(create_standard_test) target_link_libraries(test_${TEST_NAME} PUBLIC ${library}) endforeach() - if(ENABLE_JSON) - target_link_libraries(test_${TEST_NAME} PRIVATE nlohmann_json::nlohmann_json) - endif() - - if(ENABLE_LLVM) - target_link_libraries(test_${TEST_NAME} PRIVATE ${llvm_libs}) - endif() - if(NOT DEFINED TEST_WORKING_DIRECTORY) set(TEST_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") endif() diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index acc9d7bc1..46a0f3423 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -20,7 +20,6 @@ namespace micm { std::size_t number_of_grid_cells_{ 1 }; std::size_t number_of_rate_constants_{ 0 }; - std::map variable_map_; std::map custom_rate_parameter_map_; std::vector variable_names_{}; std::vector custom_rate_parameter_labels_{}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65e71697f..bf5414137 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,10 @@ if(ENABLE_MPI) target_link_libraries(micm INTERFACE MPI::MPI_CXX) endif() +if(ENABLE_LLVM) + target_link_libraries(micm INTERFACE ${llvm_libs}) +endif() + if(ENABLE_OPENACC OR ENABLE_CUDA) if(NOT GPU_TYPE) message(FATAL_ERROR "GPU_TYPE is not set or is empty. Please provide a GPU type.") From ec754d1260d31a3fa6b247db44c355381f70962a Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Wed, 25 Oct 2023 13:37:50 -0500 Subject: [PATCH 19/30] removing system from rosenbrock solver --- include/micm/solver/rosenbrock.hpp | 1 - include/micm/solver/rosenbrock.inl | 21 ++++++++++----------- include/micm/solver/state.hpp | 1 + include/micm/solver/state.inl | 6 ++++-- test/integration/e5.hpp | 4 ++-- test/integration/hires.hpp | 4 ++-- test/integration/oregonator.hpp | 4 ++-- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index f25ebffe9..5c3fa7dd6 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -204,7 +204,6 @@ namespace micm double final_time_{}; }; - System system_; std::vector processes_; RosenbrockSolverParameters parameters_; StateParameters state_parameters_; diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 54b98809b..4e1b591b2 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -433,8 +433,7 @@ namespace micm template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> inline RosenbrockSolver::RosenbrockSolver() - : system_(), - processes_(), + : processes_(), parameters_(RosenbrockSolverParameters::three_stage_rosenbrock_parameters()), state_parameters_(), process_set_(), @@ -463,8 +462,7 @@ namespace micm const std::vector& processes, const RosenbrockSolverParameters& parameters, const std::function, double)> create_linear_solver) - : system_(system), - processes_(processes), + : processes_(processes), parameters_(parameters), state_parameters_(), process_set_(), @@ -474,7 +472,7 @@ namespace micm std::function& variables, const std::size_t i)> state_reordering; std::size_t index = 0; - for (auto& name : system_.UniqueNames(state_reordering)) + for (auto& name : system.UniqueNames()) variable_map[name] = index++; // generate a state-vector reordering function to reduce fill-in in linear solver @@ -483,7 +481,7 @@ namespace micm // get unsorted Jacobian non-zero elements auto unsorted_process_set = ProcessSet(processes, variable_map); auto unsorted_jac_elements = unsorted_process_set.NonZeroJacobianElements(); - MatrixPolicy unsorted_jac_non_zeros(system_.StateSize(), system_.StateSize(), 0); + MatrixPolicy unsorted_jac_non_zeros(system.StateSize(), system.StateSize(), 0); for (auto& elem : unsorted_jac_elements) unsorted_jac_non_zeros[elem.first][elem.second] = 1; auto reorder_map = DiagonalMarkowitzReorder(unsorted_jac_non_zeros); @@ -492,7 +490,7 @@ namespace micm variable_map.clear(); std::size_t index = 0; - for (auto& name : system_.UniqueNames(state_reordering)) + for (auto& name : system.UniqueNames(state_reordering)) variable_map[name] = index++; } @@ -508,7 +506,7 @@ namespace micm auto jacobian = build_jacobian( process_set_.NonZeroJacobianElements(), parameters_.number_of_grid_cells_, - system_.StateSize() + system.StateSize() ); std::vector jacobian_diagonal_elements; @@ -518,9 +516,10 @@ namespace micm state_parameters_ = { .number_of_grid_cells_ = parameters_.number_of_grid_cells_, .number_of_rate_constants_ = processes_.size(), - .variable_names_ = system_.UniqueNames(state_reordering), + .variable_names_ = system.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, - .jacobian_diagonal_elements_ = jacobian_diagonal_elements + .jacobian_diagonal_elements_ = jacobian_diagonal_elements, + .state_size_ = system.StateSize() }; process_set_.SetJacobianFlatIds(jacobian); @@ -535,7 +534,7 @@ namespace micm state.jacobian_ = build_jacobian( process_set_.NonZeroJacobianElements(), state_parameters_.number_of_grid_cells_, - system_.StateSize() + state_parameters_.state_size_ ); auto lu = linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index 46a0f3423..d6e112bd9 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -24,6 +24,7 @@ namespace micm std::vector variable_names_{}; std::vector custom_rate_parameter_labels_{}; std::vector jacobian_diagonal_elements_; + size_t state_size_; }; template< diff --git a/include/micm/solver/state.inl b/include/micm/solver/state.inl index 5e8d7346f..27bd72b58 100644 --- a/include/micm/solver/state.inl +++ b/include/micm/solver/state.inl @@ -9,7 +9,8 @@ namespace micm : conditions_(), variables_(), custom_rate_parameters_(), - rate_constants_() + rate_constants_(), + jacobian_() { } @@ -34,7 +35,8 @@ namespace micm rate_constants_(parameters.number_of_grid_cells_, parameters.number_of_rate_constants_, 0.0), variable_map_(), custom_rate_parameter_map_(), - variable_names_(parameters.variable_names_) + variable_names_(parameters.variable_names_), + jacobian_() { std::size_t index = 0; for (auto& name : variable_names_) diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index 3dbc37f17..efe968798 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -19,7 +19,6 @@ class E5 : public micm::RosenbrockSolver() { - this->system_ = system; this->processes_ = processes; this->parameters_ = parameters; @@ -51,6 +50,7 @@ class E5 : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -65,7 +65,7 @@ class E5 : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 5396fe4cf..4f7674bd8 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -20,7 +20,6 @@ class HIRES : public micm::RosenbrockSolver() { - this->system_ = system; this->processes_ = processes; this->parameters_ = parameters; @@ -52,6 +51,7 @@ class HIRES : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -66,7 +66,7 @@ class HIRES : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index 4f01511d7..e2477e0a8 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -20,7 +20,6 @@ class Oregonator : public micm::RosenbrockSolver() { - this->system_ = system; this->processes_ = processes; this->parameters_ = parameters; @@ -52,6 +51,7 @@ class Oregonator : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -66,7 +66,7 @@ class Oregonator : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->system_.StateSize()); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); From 887e927fd2dbb3689b68d7ec98763cb569580f9e Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Wed, 25 Oct 2023 13:49:51 -0500 Subject: [PATCH 20/30] moving solver parameters into its own file --- include/micm/solver/rosenbrock.hpp | 94 +--- include/micm/solver/rosenbrock.inl | 361 +------------- .../solver/rosenbrock_solver_parameters.hpp | 462 ++++++++++++++++++ 3 files changed, 464 insertions(+), 453 deletions(-) create mode 100644 include/micm/solver/rosenbrock_solver_parameters.hpp diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 5c3fa7dd6..c5012cd33 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -16,7 +16,6 @@ #pragma once #include -#include #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -37,98 +37,6 @@ namespace micm { - /// @brief Rosenbrock solver parameters - struct RosenbrockSolverParameters - { - size_t stages_{}; - size_t upper_limit_tolerance_{}; - size_t max_number_of_steps_{ 1000 }; - - double round_off_{ std::numeric_limits::epsilon() }; // Unit roundoff (1+round_off)>1 - double factor_min_{ 0.2 }; // solver step size minimum boundary - double factor_max_{ 6 }; // solver step size maximum boundary - double rejection_factor_decrease_{ 0.1 }; // used to decrease the step after 2 successive rejections - double safety_factor_{ 0.9 }; // safety factor in new step size computation - - double h_min_{ 0.0 }; // step size min [s] - double h_max_{ - 0.0 - }; // step size max [s] (if zero or greater than the solver time-step, the time-step passed to the solver will be used) - double h_start_{ 0.0 }; // step size start [s] (if zero, 1.0e-6 will be used, if greater than h_max, h_max will be used) - - // Does the stage i require a new function evaluation (ros_NewF(i)=TRUE) - // or does it re-use the function evaluation from stage i-1 (ros_NewF(i)=FALSE) - std::array - new_function_evaluation_{}; // which steps reuse the previous iterations evaluation or do a new evaluation - - double estimator_of_local_order_{}; // the minumum between the main and the embedded scheme orders plus one - - // The coefficient matrices A and C are strictly lower triangular. - // The lower triangular (subdiagonal) elements are stored in row-wise order: - // A(2,1) = ros_A(1), A(3,1)=ros_A(2), A(3,2)=ros_A(3), etc. - // The general mapping formula is: - // A(i,j) = ros_A( (i-1)*(i-2)/2 + j ) - // C(i,j) = ros_C( (i-1)*(i-2)/2 + j ) - std::array a_{}; // coefficient matrix a - std::array c_{}; // coefficient matrix c - std::array m_{}; // coefficients for new step evaluation - std::array e_{}; // error estimation coefficients - - // Y_stage_i ~ Y( T + H*Alpha_i ) - std::array alpha_{}; - // Gamma_i = \sum_j gamma_{i,j} - std::array gamma_{}; - - double absolute_tolerance_{ 1e-3 }; - double relative_tolerance_{ 1e-4 }; - - size_t number_of_grid_cells_{ 1 }; // Number of grid cells to solve simultaneously - bool reorder_state_{ true }; // Reorder state during solver construction to minimize LU fill-in - bool check_singularity_{ false }; // Check for singular A matrix in linear solve of A x = b - - // Print RosenbrockSolverParameters to console - void print() const; - - /// @brief an L-stable method, 2 stages, order 2 - /// @param number_of_grid_cells - /// @param reorder_state - /// @return - static RosenbrockSolverParameters two_stage_rosenbrock_parameters( - size_t number_of_grid_cells = 1, - bool reorder_state = true); - /// @brief an L-stable method, 3 stages, order 3, 2 function evaluations - /// @param number_of_grid_cells - /// @param reorder_state - /// @return - static RosenbrockSolverParameters three_stage_rosenbrock_parameters( - size_t number_of_grid_cells = 1, - bool reorder_state = true); - /// @brief L-stable rosenbrock method of order 4, with 4 stages - /// @param number_of_grid_cells - /// @param reorder_state - /// @return - static RosenbrockSolverParameters four_stage_rosenbrock_parameters( - size_t number_of_grid_cells = 1, - bool reorder_state = true); - /// @brief A stiffly-stable method, 4 stages, order 3 - /// @param number_of_grid_cells - /// @param reorder_state - /// @return - static RosenbrockSolverParameters four_stage_differential_algebraic_rosenbrock_parameters( - size_t number_of_grid_cells = 1, - bool reorder_state = true); - /// @brief stiffly-stable rosenbrock method of order 4, with 6 stages - /// @param number_of_grid_cells - /// @param reorder_state - /// @return - static RosenbrockSolverParameters six_stage_differential_algebraic_rosenbrock_parameters( - size_t number_of_grid_cells = 1, - bool reorder_state = true); - - private: - RosenbrockSolverParameters() = default; - }; - /// @brief The final state the solver was in after the Solve function finishes enum class SolverState { diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 4e1b591b2..506136795 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -37,366 +37,7 @@ namespace micm return SparseMatrixPolicy(builder); } } - // - // RosenbrockSolverParameters - // - inline void RosenbrockSolverParameters::print() const - { - std::cout << "stages_: " << stages_ << std::endl; - std::cout << "upper_limit_tolerance_: " << upper_limit_tolerance_ << std::endl; - std::cout << "max_number_of_steps_: " << max_number_of_steps_ << std::endl; - std::cout << "round_off_: " << round_off_ << std::endl; - std::cout << "factor_min_: " << factor_min_ << std::endl; - std::cout << "factor_max_: " << factor_max_ << std::endl; - std::cout << "rejection_factor_decrease_: " << rejection_factor_decrease_ << std::endl; - std::cout << "safety_factor_: " << safety_factor_ << std::endl; - std::cout << "h_min_: " << h_min_ << std::endl; - std::cout << "h_max_: " << h_max_ << std::endl; - std::cout << "h_start_: " << h_start_ << std::endl; - std::cout << "new_function_evaluation_: "; - for (bool val : new_function_evaluation_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "estimator_of_local_order_: " << estimator_of_local_order_ << std::endl; - std::cout << "a_: "; - for (double val : a_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "c_: "; - for (double val : c_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "m_: "; - for (double val : m_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "e_: "; - for (double val : e_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "alpha_: "; - for (double val : alpha_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "gamma_: "; - for (double val : gamma_) - std::cout << val << " "; - std::cout << std::endl; - std::cout << "absolute_tolerance_: " << absolute_tolerance_ << std::endl; - std::cout << "relative_tolerance_: " << relative_tolerance_ << std::endl; - std::cout << "number_of_grid_cells_: " << number_of_grid_cells_ << std::endl; - } - - inline RosenbrockSolverParameters RosenbrockSolverParameters::two_stage_rosenbrock_parameters( - size_t number_of_grid_cells, - bool reorder_state) - { - // an L-stable method, 2 stages, order 2 - - RosenbrockSolverParameters parameters; - double g = 1.0 + 1.0 / std::sqrt(2.0); - - parameters.stages_ = 2; - - parameters.a_.fill(0); - parameters.a_[0] = 1.0 / g; - - parameters.c_.fill(0); - parameters.c_[0] = -2.0 / g; - - // Both stages require a new function evaluation - parameters.new_function_evaluation_.fill(true); - - parameters.m_.fill(0); - parameters.m_[0] = (3.0) / (2.0 * g); - parameters.m_[1] = (1.0) / (2.0 * g); - - parameters.e_.fill(0); - parameters.e_[0] = 1.0 / (2.0 * g); - parameters.e_[1] = 1.0 / (2.0 * g); - - parameters.estimator_of_local_order_ = 2.0; - - parameters.alpha_.fill(0); - parameters.alpha_[0] = 0.0; - parameters.alpha_[1] = 1.0; - - parameters.gamma_.fill(0); - parameters.gamma_[0] = g; - parameters.gamma_[1] = -g; - - parameters.number_of_grid_cells_ = number_of_grid_cells; - parameters.reorder_state_ = reorder_state; - - return parameters; - } - - inline RosenbrockSolverParameters RosenbrockSolverParameters::three_stage_rosenbrock_parameters( - size_t number_of_grid_cells, - bool reorder_state) - { - // an L-stable method, 3 stages, order 3, 2 function evaluations - // - // original formaulation for three stages: - // Sandu, A., Verwer, J.G., Blom, J.G., Spee, E.J., Carmichael, G.R., Potra, F.A., 1997. - // Benchmarking stiff ode solvers for atmospheric chemistry problems II: Rosenbrock solvers. - // Atmospheric Environment 31, 3459–3472. https://doi.org/10.1016/S1352-2310(97)83212-8 - RosenbrockSolverParameters parameters; - - parameters.stages_ = 3; - - parameters.a_.fill(0); - parameters.a_[0] = 1; - parameters.a_[1] = 1; - parameters.a_[2] = 0; - - parameters.c_.fill(0); - parameters.c_[0] = -0.10156171083877702091975600115545e+01; - parameters.c_[1] = 0.40759956452537699824805835358067e+01; - parameters.c_[2] = 0.92076794298330791242156818474003e+01; - - parameters.new_function_evaluation_.fill(false); - parameters.new_function_evaluation_[0] = true; - parameters.new_function_evaluation_[1] = true; - parameters.new_function_evaluation_[2] = false; - parameters.m_.fill(0); - parameters.m_[0] = 0.1e+01; - parameters.m_[1] = 0.61697947043828245592553615689730e+01; - parameters.m_[2] = -0.42772256543218573326238373806514; - - parameters.e_.fill(0); - parameters.e_[0] = 0.5; - parameters.e_[1] = -0.29079558716805469821718236208017e+01; - parameters.e_[2] = 0.22354069897811569627360909276199; - - parameters.estimator_of_local_order_ = 3; - - parameters.alpha_.fill(0); - parameters.alpha_[0] = 0; - parameters.alpha_[1] = 0.43586652150845899941601945119356; - parameters.alpha_[2] = 0.43586652150845899941601945119356; - - parameters.gamma_.fill(0); - parameters.gamma_[0] = 0.43586652150845899941601945119356; - parameters.gamma_[1] = 0.24291996454816804366592249683314; - parameters.gamma_[2] = 0.21851380027664058511513169485832e+01; - - parameters.number_of_grid_cells_ = number_of_grid_cells; - parameters.reorder_state_ = reorder_state; - - return parameters; - } - - inline RosenbrockSolverParameters RosenbrockSolverParameters::four_stage_rosenbrock_parameters( - size_t number_of_grid_cells, - bool reorder_state) - { - // L-STABLE ROSENBROCK METHOD OF ORDER 4, WITH 4 STAGES - // L-STABLE EMBEDDED ROSENBROCK METHOD OF ORDER 3 - // - // E. HAIRER AND G. WANNER, SOLVING ORDINARY DIFFERENTIAL - // EQUATIONS II. STIFF AND DIFFERENTIAL-ALGEBRAIC PROBLEMS. - // SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, - // SPRINGER-VERLAG (1990) - RosenbrockSolverParameters parameters; - - parameters.stages_ = 4; - - parameters.a_.fill(0); - parameters.a_[0] = 0.2000000000000000E+01; - parameters.a_[1] = 0.1867943637803922E+01; - parameters.a_[2] = 0.2344449711399156; - parameters.a_[3] = parameters.a_[1]; - parameters.a_[4] = parameters.a_[2]; - parameters.a_[5] = 0.0; - - parameters.c_.fill(0); - parameters.c_[0] = -0.7137615036412310E+01; - parameters.c_[1] = 0.2580708087951457E+01; - parameters.c_[2] = 0.6515950076447975; - parameters.c_[3] = -0.2137148994382534E+01; - parameters.c_[4] = -0.3214669691237626; - parameters.c_[5] = -0.6949742501781779; - - parameters.new_function_evaluation_.fill(false); - parameters.new_function_evaluation_[0] = true; - parameters.new_function_evaluation_[1] = true; - parameters.new_function_evaluation_[2] = true; - parameters.new_function_evaluation_[3] = false; - - parameters.m_.fill(0); - parameters.m_[0] = 0.2255570073418735E+01; - parameters.m_[1] = 0.2870493262186792; - parameters.m_[2] = 0.4353179431840180; - parameters.m_[3] = 0.1093502252409163E+01; - - parameters.e_.fill(0); - parameters.e_[0] = -0.2815431932141155; - parameters.e_[1] = -0.7276199124938920E-01; - parameters.e_[2] = -0.1082196201495311; - parameters.e_[3] = -0.1093502252409163E+01; - - parameters.estimator_of_local_order_ = 4.0; - - parameters.alpha_.fill(0); - parameters.alpha_[0] = 0.0; - parameters.alpha_[1] = 0.1145640000000000E+01; - parameters.alpha_[2] = 0.6552168638155900; - parameters.alpha_[3] = parameters.alpha_[2]; - - parameters.gamma_.fill(0); - parameters.gamma_[0] = 0.5728200000000000; - parameters.gamma_[1] = -0.1769193891319233E+01; - parameters.gamma_[2] = 0.7592633437920482; - parameters.gamma_[3] = -0.1049021087100450; - - parameters.number_of_grid_cells_ = number_of_grid_cells; - parameters.reorder_state_ = reorder_state; - - return parameters; - } - - inline RosenbrockSolverParameters RosenbrockSolverParameters::four_stage_differential_algebraic_rosenbrock_parameters( - size_t number_of_grid_cells, - bool reorder_state) - { - // A STIFFLY-STABLE METHOD, 4 stages, order 3 - RosenbrockSolverParameters parameters; - - // Set the number of stages - parameters.stages_ = 4; - - parameters.a_.fill(0.0); - parameters.a_[0] = 0.0; - parameters.a_[1] = 2.0; - parameters.a_[2] = 0.0; - parameters.a_[3] = 2.0; - parameters.a_[4] = 0.0; - parameters.a_[5] = 1.0; - - parameters.c_.fill(0.0); - parameters.c_[0] = 4.0; - parameters.c_[1] = 1.0; - parameters.c_[2] = -1.0; - parameters.c_[3] = 1.0; - parameters.c_[4] = -1.0; - parameters.c_[5] = -(8.0 / 3.0); - - parameters.new_function_evaluation_.fill(false); - parameters.new_function_evaluation_[0] = true; - parameters.new_function_evaluation_[2] = true; - parameters.new_function_evaluation_[3] = true; - - parameters.m_.fill(0.0); - parameters.m_[0] = 2.0; - parameters.m_[2] = 1.0; - parameters.m_[3] = 1.0; - - parameters.e_.fill(0.0); - parameters.e_[3] = 1.0; - - parameters.estimator_of_local_order_ = 3.0; - - parameters.alpha_.fill(0.0); - parameters.alpha_[2] = 1.0; - parameters.alpha_[3] = 1.0; - - parameters.gamma_.fill(0.0); - parameters.gamma_[0] = 0.5; - parameters.gamma_[1] = 1.5; - - parameters.number_of_grid_cells_ = number_of_grid_cells; - parameters.reorder_state_ = reorder_state; - - return parameters; - } - - inline RosenbrockSolverParameters RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters( - size_t number_of_grid_cells, - bool reorder_state) - { - // STIFFLY-STABLE ROSENBROCK METHOD OF ORDER 4, WITH 6 STAGES - // - // E. HAIRER AND G. WANNER, SOLVING ORDINARY DIFFERENTIAL - // EQUATIONS II. STIFF AND DIFFERENTIAL-ALGEBRAIC PROBLEMS. - // SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, - // SPRINGER-VERLAG (1996) - - RosenbrockSolverParameters parameters; - - parameters.stages_ = 6; - - parameters.alpha_.fill(0.0); - parameters.alpha_[0] = 0.000; - parameters.alpha_[1] = 0.386; - parameters.alpha_[2] = 0.210; - parameters.alpha_[3] = 0.630; - parameters.alpha_[4] = 1.000; - parameters.alpha_[5] = 1.000; - - parameters.gamma_.fill(0.0); - parameters.gamma_[0] = 0.2500000000000000; - parameters.gamma_[1] = -0.1043000000000000; - parameters.gamma_[2] = 0.1035000000000000; - parameters.gamma_[3] = -0.3620000000000023E-01; - parameters.gamma_[4] = 0.0; - parameters.gamma_[5] = 0.0; - - parameters.a_.fill(0.0); - parameters.a_[0] = 0.1544000000000000E+01; - parameters.a_[1] = 0.9466785280815826; - parameters.a_[2] = 0.2557011698983284; - parameters.a_[3] = 0.3314825187068521E+01; - parameters.a_[4] = 0.2896124015972201E+01; - parameters.a_[5] = 0.9986419139977817; - parameters.a_[6] = 0.1221224509226641E+01; - parameters.a_[7] = 0.6019134481288629E+01; - parameters.a_[8] = 0.1253708332932087E+02; - parameters.a_[9] = -0.6878860361058950; - parameters.a_[10] = parameters.a_[6]; - parameters.a_[11] = parameters.a_[7]; - parameters.a_[12] = parameters.a_[8]; - parameters.a_[13] = parameters.a_[9]; - parameters.a_[14] = 1.0; - - parameters.c_.fill(0.0); - parameters.c_[0] = -0.5668800000000000E+01; - parameters.c_[1] = -0.2430093356833875E+01; - parameters.c_[2] = -0.2063599157091915; - parameters.c_[3] = -0.1073529058151375; - parameters.c_[4] = -0.9594562251023355E+01; - parameters.c_[5] = -0.2047028614809616E+02; - parameters.c_[6] = 0.7496443313967647E+01; - parameters.c_[7] = -0.1024680431464352E+02; - parameters.c_[8] = -0.3399990352819905E+02; - parameters.c_[9] = 0.1170890893206160E+02; - parameters.c_[10] = 0.8083246795921522E+01; - parameters.c_[11] = -0.7981132988064893E+01; - parameters.c_[12] = -0.3152159432874371E+02; - parameters.c_[13] = 0.1631930543123136E+02; - parameters.c_[14] = -0.6058818238834054E+01; - - parameters.m_.fill(0.0); - parameters.m_[0] = parameters.a_[6]; - parameters.m_[1] = parameters.a_[7]; - parameters.m_[2] = parameters.a_[8]; - parameters.m_[3] = parameters.a_[9]; - parameters.m_[4] = 1.0; - parameters.m_[5] = 1.0; - - parameters.e_.fill(0.0); - parameters.e_[5] = 1.0; - - parameters.new_function_evaluation_.fill(true); - - parameters.estimator_of_local_order_ = 4.0; - - parameters.number_of_grid_cells_ = number_of_grid_cells; - parameters.reorder_state_ = reorder_state; - - return parameters; - } - + // // RosenbrockSolver // diff --git a/include/micm/solver/rosenbrock_solver_parameters.hpp b/include/micm/solver/rosenbrock_solver_parameters.hpp new file mode 100644 index 000000000..bfb4276fe --- /dev/null +++ b/include/micm/solver/rosenbrock_solver_parameters.hpp @@ -0,0 +1,462 @@ +// Copyright (C) 2023 National Center for Atmospheric Research +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include +#include + +namespace micm +{ + + /// @brief Rosenbrock solver parameters + struct RosenbrockSolverParameters + { + size_t stages_{}; + size_t upper_limit_tolerance_{}; + size_t max_number_of_steps_{ 1000 }; + + double round_off_{ std::numeric_limits::epsilon() }; // Unit roundoff (1+round_off)>1 + double factor_min_{ 0.2 }; // solver step size minimum boundary + double factor_max_{ 6 }; // solver step size maximum boundary + double rejection_factor_decrease_{ 0.1 }; // used to decrease the step after 2 successive rejections + double safety_factor_{ 0.9 }; // safety factor in new step size computation + + double h_min_{ 0.0 }; // step size min [s] + double h_max_{ + 0.0 + }; // step size max [s] (if zero or greater than the solver time-step, the time-step passed to the solver will be used) + double h_start_{ 0.0 }; // step size start [s] (if zero, 1.0e-6 will be used, if greater than h_max, h_max will be used) + + // Does the stage i require a new function evaluation (ros_NewF(i)=TRUE) + // or does it re-use the function evaluation from stage i-1 (ros_NewF(i)=FALSE) + std::array + new_function_evaluation_{}; // which steps reuse the previous iterations evaluation or do a new evaluation + + double estimator_of_local_order_{}; // the minumum between the main and the embedded scheme orders plus one + + // The coefficient matrices A and C are strictly lower triangular. + // The lower triangular (subdiagonal) elements are stored in row-wise order: + // A(2,1) = ros_A(1), A(3,1)=ros_A(2), A(3,2)=ros_A(3), etc. + // The general mapping formula is: + // A(i,j) = ros_A( (i-1)*(i-2)/2 + j ) + // C(i,j) = ros_C( (i-1)*(i-2)/2 + j ) + std::array a_{}; // coefficient matrix a + std::array c_{}; // coefficient matrix c + std::array m_{}; // coefficients for new step evaluation + std::array e_{}; // error estimation coefficients + + // Y_stage_i ~ Y( T + H*Alpha_i ) + std::array alpha_{}; + // Gamma_i = \sum_j gamma_{i,j} + std::array gamma_{}; + + double absolute_tolerance_{ 1e-3 }; + double relative_tolerance_{ 1e-4 }; + + size_t number_of_grid_cells_{ 1 }; // Number of grid cells to solve simultaneously + bool reorder_state_{ true }; // Reorder state during solver construction to minimize LU fill-in + bool check_singularity_{ false }; // Check for singular A matrix in linear solve of A x = b + + // Print RosenbrockSolverParameters to console + void print() const; + + /// @brief an L-stable method, 2 stages, order 2 + /// @param number_of_grid_cells + /// @param reorder_state + /// @return + static RosenbrockSolverParameters two_stage_rosenbrock_parameters( + size_t number_of_grid_cells = 1, + bool reorder_state = true); + /// @brief an L-stable method, 3 stages, order 3, 2 function evaluations + /// @param number_of_grid_cells + /// @param reorder_state + /// @return + static RosenbrockSolverParameters three_stage_rosenbrock_parameters( + size_t number_of_grid_cells = 1, + bool reorder_state = true); + /// @brief L-stable rosenbrock method of order 4, with 4 stages + /// @param number_of_grid_cells + /// @param reorder_state + /// @return + static RosenbrockSolverParameters four_stage_rosenbrock_parameters( + size_t number_of_grid_cells = 1, + bool reorder_state = true); + /// @brief A stiffly-stable method, 4 stages, order 3 + /// @param number_of_grid_cells + /// @param reorder_state + /// @return + static RosenbrockSolverParameters four_stage_differential_algebraic_rosenbrock_parameters( + size_t number_of_grid_cells = 1, + bool reorder_state = true); + /// @brief stiffly-stable rosenbrock method of order 4, with 6 stages + /// @param number_of_grid_cells + /// @param reorder_state + /// @return + static RosenbrockSolverParameters six_stage_differential_algebraic_rosenbrock_parameters( + size_t number_of_grid_cells = 1, + bool reorder_state = true); + + private: + RosenbrockSolverParameters() = default; + }; + + inline void RosenbrockSolverParameters::print() const + { + std::cout << "stages_: " << stages_ << std::endl; + std::cout << "upper_limit_tolerance_: " << upper_limit_tolerance_ << std::endl; + std::cout << "max_number_of_steps_: " << max_number_of_steps_ << std::endl; + std::cout << "round_off_: " << round_off_ << std::endl; + std::cout << "factor_min_: " << factor_min_ << std::endl; + std::cout << "factor_max_: " << factor_max_ << std::endl; + std::cout << "rejection_factor_decrease_: " << rejection_factor_decrease_ << std::endl; + std::cout << "safety_factor_: " << safety_factor_ << std::endl; + std::cout << "h_min_: " << h_min_ << std::endl; + std::cout << "h_max_: " << h_max_ << std::endl; + std::cout << "h_start_: " << h_start_ << std::endl; + std::cout << "new_function_evaluation_: "; + for (bool val : new_function_evaluation_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "estimator_of_local_order_: " << estimator_of_local_order_ << std::endl; + std::cout << "a_: "; + for (double val : a_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "c_: "; + for (double val : c_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "m_: "; + for (double val : m_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "e_: "; + for (double val : e_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "alpha_: "; + for (double val : alpha_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "gamma_: "; + for (double val : gamma_) + std::cout << val << " "; + std::cout << std::endl; + std::cout << "absolute_tolerance_: " << absolute_tolerance_ << std::endl; + std::cout << "relative_tolerance_: " << relative_tolerance_ << std::endl; + std::cout << "number_of_grid_cells_: " << number_of_grid_cells_ << std::endl; + } + + inline RosenbrockSolverParameters RosenbrockSolverParameters::two_stage_rosenbrock_parameters( + size_t number_of_grid_cells, + bool reorder_state) + { + // an L-stable method, 2 stages, order 2 + + RosenbrockSolverParameters parameters; + double g = 1.0 + 1.0 / std::sqrt(2.0); + + parameters.stages_ = 2; + + parameters.a_.fill(0); + parameters.a_[0] = 1.0 / g; + + parameters.c_.fill(0); + parameters.c_[0] = -2.0 / g; + + // Both stages require a new function evaluation + parameters.new_function_evaluation_.fill(true); + + parameters.m_.fill(0); + parameters.m_[0] = (3.0) / (2.0 * g); + parameters.m_[1] = (1.0) / (2.0 * g); + + parameters.e_.fill(0); + parameters.e_[0] = 1.0 / (2.0 * g); + parameters.e_[1] = 1.0 / (2.0 * g); + + parameters.estimator_of_local_order_ = 2.0; + + parameters.alpha_.fill(0); + parameters.alpha_[0] = 0.0; + parameters.alpha_[1] = 1.0; + + parameters.gamma_.fill(0); + parameters.gamma_[0] = g; + parameters.gamma_[1] = -g; + + parameters.number_of_grid_cells_ = number_of_grid_cells; + parameters.reorder_state_ = reorder_state; + + return parameters; + } + + inline RosenbrockSolverParameters RosenbrockSolverParameters::three_stage_rosenbrock_parameters( + size_t number_of_grid_cells, + bool reorder_state) + { + // an L-stable method, 3 stages, order 3, 2 function evaluations + // + // original formaulation for three stages: + // Sandu, A., Verwer, J.G., Blom, J.G., Spee, E.J., Carmichael, G.R., Potra, F.A., 1997. + // Benchmarking stiff ode solvers for atmospheric chemistry problems II: Rosenbrock solvers. + // Atmospheric Environment 31, 3459–3472. https://doi.org/10.1016/S1352-2310(97)83212-8 + RosenbrockSolverParameters parameters; + + parameters.stages_ = 3; + + parameters.a_.fill(0); + parameters.a_[0] = 1; + parameters.a_[1] = 1; + parameters.a_[2] = 0; + + parameters.c_.fill(0); + parameters.c_[0] = -0.10156171083877702091975600115545e+01; + parameters.c_[1] = 0.40759956452537699824805835358067e+01; + parameters.c_[2] = 0.92076794298330791242156818474003e+01; + + parameters.new_function_evaluation_.fill(false); + parameters.new_function_evaluation_[0] = true; + parameters.new_function_evaluation_[1] = true; + parameters.new_function_evaluation_[2] = false; + parameters.m_.fill(0); + parameters.m_[0] = 0.1e+01; + parameters.m_[1] = 0.61697947043828245592553615689730e+01; + parameters.m_[2] = -0.42772256543218573326238373806514; + + parameters.e_.fill(0); + parameters.e_[0] = 0.5; + parameters.e_[1] = -0.29079558716805469821718236208017e+01; + parameters.e_[2] = 0.22354069897811569627360909276199; + + parameters.estimator_of_local_order_ = 3; + + parameters.alpha_.fill(0); + parameters.alpha_[0] = 0; + parameters.alpha_[1] = 0.43586652150845899941601945119356; + parameters.alpha_[2] = 0.43586652150845899941601945119356; + + parameters.gamma_.fill(0); + parameters.gamma_[0] = 0.43586652150845899941601945119356; + parameters.gamma_[1] = 0.24291996454816804366592249683314; + parameters.gamma_[2] = 0.21851380027664058511513169485832e+01; + + parameters.number_of_grid_cells_ = number_of_grid_cells; + parameters.reorder_state_ = reorder_state; + + return parameters; + } + + inline RosenbrockSolverParameters RosenbrockSolverParameters::four_stage_rosenbrock_parameters( + size_t number_of_grid_cells, + bool reorder_state) + { + // L-STABLE ROSENBROCK METHOD OF ORDER 4, WITH 4 STAGES + // L-STABLE EMBEDDED ROSENBROCK METHOD OF ORDER 3 + // + // E. HAIRER AND G. WANNER, SOLVING ORDINARY DIFFERENTIAL + // EQUATIONS II. STIFF AND DIFFERENTIAL-ALGEBRAIC PROBLEMS. + // SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, + // SPRINGER-VERLAG (1990) + RosenbrockSolverParameters parameters; + + parameters.stages_ = 4; + + parameters.a_.fill(0); + parameters.a_[0] = 0.2000000000000000E+01; + parameters.a_[1] = 0.1867943637803922E+01; + parameters.a_[2] = 0.2344449711399156; + parameters.a_[3] = parameters.a_[1]; + parameters.a_[4] = parameters.a_[2]; + parameters.a_[5] = 0.0; + + parameters.c_.fill(0); + parameters.c_[0] = -0.7137615036412310E+01; + parameters.c_[1] = 0.2580708087951457E+01; + parameters.c_[2] = 0.6515950076447975; + parameters.c_[3] = -0.2137148994382534E+01; + parameters.c_[4] = -0.3214669691237626; + parameters.c_[5] = -0.6949742501781779; + + parameters.new_function_evaluation_.fill(false); + parameters.new_function_evaluation_[0] = true; + parameters.new_function_evaluation_[1] = true; + parameters.new_function_evaluation_[2] = true; + parameters.new_function_evaluation_[3] = false; + + parameters.m_.fill(0); + parameters.m_[0] = 0.2255570073418735E+01; + parameters.m_[1] = 0.2870493262186792; + parameters.m_[2] = 0.4353179431840180; + parameters.m_[3] = 0.1093502252409163E+01; + + parameters.e_.fill(0); + parameters.e_[0] = -0.2815431932141155; + parameters.e_[1] = -0.7276199124938920E-01; + parameters.e_[2] = -0.1082196201495311; + parameters.e_[3] = -0.1093502252409163E+01; + + parameters.estimator_of_local_order_ = 4.0; + + parameters.alpha_.fill(0); + parameters.alpha_[0] = 0.0; + parameters.alpha_[1] = 0.1145640000000000E+01; + parameters.alpha_[2] = 0.6552168638155900; + parameters.alpha_[3] = parameters.alpha_[2]; + + parameters.gamma_.fill(0); + parameters.gamma_[0] = 0.5728200000000000; + parameters.gamma_[1] = -0.1769193891319233E+01; + parameters.gamma_[2] = 0.7592633437920482; + parameters.gamma_[3] = -0.1049021087100450; + + parameters.number_of_grid_cells_ = number_of_grid_cells; + parameters.reorder_state_ = reorder_state; + + return parameters; + } + + inline RosenbrockSolverParameters RosenbrockSolverParameters::four_stage_differential_algebraic_rosenbrock_parameters( + size_t number_of_grid_cells, + bool reorder_state) + { + // A STIFFLY-STABLE METHOD, 4 stages, order 3 + RosenbrockSolverParameters parameters; + + // Set the number of stages + parameters.stages_ = 4; + + parameters.a_.fill(0.0); + parameters.a_[0] = 0.0; + parameters.a_[1] = 2.0; + parameters.a_[2] = 0.0; + parameters.a_[3] = 2.0; + parameters.a_[4] = 0.0; + parameters.a_[5] = 1.0; + + parameters.c_.fill(0.0); + parameters.c_[0] = 4.0; + parameters.c_[1] = 1.0; + parameters.c_[2] = -1.0; + parameters.c_[3] = 1.0; + parameters.c_[4] = -1.0; + parameters.c_[5] = -(8.0 / 3.0); + + parameters.new_function_evaluation_.fill(false); + parameters.new_function_evaluation_[0] = true; + parameters.new_function_evaluation_[2] = true; + parameters.new_function_evaluation_[3] = true; + + parameters.m_.fill(0.0); + parameters.m_[0] = 2.0; + parameters.m_[2] = 1.0; + parameters.m_[3] = 1.0; + + parameters.e_.fill(0.0); + parameters.e_[3] = 1.0; + + parameters.estimator_of_local_order_ = 3.0; + + parameters.alpha_.fill(0.0); + parameters.alpha_[2] = 1.0; + parameters.alpha_[3] = 1.0; + + parameters.gamma_.fill(0.0); + parameters.gamma_[0] = 0.5; + parameters.gamma_[1] = 1.5; + + parameters.number_of_grid_cells_ = number_of_grid_cells; + parameters.reorder_state_ = reorder_state; + + return parameters; + } + + inline RosenbrockSolverParameters RosenbrockSolverParameters::six_stage_differential_algebraic_rosenbrock_parameters( + size_t number_of_grid_cells, + bool reorder_state) + { + // STIFFLY-STABLE ROSENBROCK METHOD OF ORDER 4, WITH 6 STAGES + // + // E. HAIRER AND G. WANNER, SOLVING ORDINARY DIFFERENTIAL + // EQUATIONS II. STIFF AND DIFFERENTIAL-ALGEBRAIC PROBLEMS. + // SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, + // SPRINGER-VERLAG (1996) + + RosenbrockSolverParameters parameters; + + parameters.stages_ = 6; + + parameters.alpha_.fill(0.0); + parameters.alpha_[0] = 0.000; + parameters.alpha_[1] = 0.386; + parameters.alpha_[2] = 0.210; + parameters.alpha_[3] = 0.630; + parameters.alpha_[4] = 1.000; + parameters.alpha_[5] = 1.000; + + parameters.gamma_.fill(0.0); + parameters.gamma_[0] = 0.2500000000000000; + parameters.gamma_[1] = -0.1043000000000000; + parameters.gamma_[2] = 0.1035000000000000; + parameters.gamma_[3] = -0.3620000000000023E-01; + parameters.gamma_[4] = 0.0; + parameters.gamma_[5] = 0.0; + + parameters.a_.fill(0.0); + parameters.a_[0] = 0.1544000000000000E+01; + parameters.a_[1] = 0.9466785280815826; + parameters.a_[2] = 0.2557011698983284; + parameters.a_[3] = 0.3314825187068521E+01; + parameters.a_[4] = 0.2896124015972201E+01; + parameters.a_[5] = 0.9986419139977817; + parameters.a_[6] = 0.1221224509226641E+01; + parameters.a_[7] = 0.6019134481288629E+01; + parameters.a_[8] = 0.1253708332932087E+02; + parameters.a_[9] = -0.6878860361058950; + parameters.a_[10] = parameters.a_[6]; + parameters.a_[11] = parameters.a_[7]; + parameters.a_[12] = parameters.a_[8]; + parameters.a_[13] = parameters.a_[9]; + parameters.a_[14] = 1.0; + + parameters.c_.fill(0.0); + parameters.c_[0] = -0.5668800000000000E+01; + parameters.c_[1] = -0.2430093356833875E+01; + parameters.c_[2] = -0.2063599157091915; + parameters.c_[3] = -0.1073529058151375; + parameters.c_[4] = -0.9594562251023355E+01; + parameters.c_[5] = -0.2047028614809616E+02; + parameters.c_[6] = 0.7496443313967647E+01; + parameters.c_[7] = -0.1024680431464352E+02; + parameters.c_[8] = -0.3399990352819905E+02; + parameters.c_[9] = 0.1170890893206160E+02; + parameters.c_[10] = 0.8083246795921522E+01; + parameters.c_[11] = -0.7981132988064893E+01; + parameters.c_[12] = -0.3152159432874371E+02; + parameters.c_[13] = 0.1631930543123136E+02; + parameters.c_[14] = -0.6058818238834054E+01; + + parameters.m_.fill(0.0); + parameters.m_[0] = parameters.a_[6]; + parameters.m_[1] = parameters.a_[7]; + parameters.m_[2] = parameters.a_[8]; + parameters.m_[3] = parameters.a_[9]; + parameters.m_[4] = 1.0; + parameters.m_[5] = 1.0; + + parameters.e_.fill(0.0); + parameters.e_[5] = 1.0; + + parameters.new_function_evaluation_.fill(true); + + parameters.estimator_of_local_order_ = 4.0; + + parameters.number_of_grid_cells_ = number_of_grid_cells; + parameters.reorder_state_ = reorder_state; + + return parameters; + } + + +} \ No newline at end of file From 6aeea86f2d966d09095efac06e483f8fc7d33826 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 11:39:02 -0500 Subject: [PATCH 21/30] removing invalid state constructor --- .../micm/process/arrhenius_rate_constant.hpp | 10 +++++ .../micm/process/branched_rate_constant.hpp | 10 +++++ include/micm/process/rate_constant.hpp | 9 ++++ .../micm/process/surface_rate_constant.hpp | 11 +++++ ...nary_chemical_activation_rate_constant.hpp | 11 +++++ include/micm/process/troe_rate_constant.hpp | 10 +++++ .../micm/process/tunneling_rate_constant.hpp | 10 +++++ .../process/user_defined_rate_constant.hpp | 10 +++++ include/micm/solver/linear_solver.hpp | 4 +- include/micm/solver/linear_solver.inl | 6 --- include/micm/solver/rosenbrock.hpp | 1 + include/micm/solver/rosenbrock.inl | 40 ++--------------- include/micm/solver/state.hpp | 18 +++----- include/micm/solver/state.inl | 31 +++++++------ include/micm/util/exit_codes.hpp | 12 ----- include/micm/util/jacobian.hpp | 24 ++++++++++ include/micm/util/matrix.hpp | 9 ++-- include/micm/util/vector_matrix.hpp | 7 +-- test/integration/e5.hpp | 5 +-- test/integration/hires.hpp | 5 +-- test/integration/oregonator.hpp | 5 +-- .../RosenbrockChapman/chapman_ode_solver.hpp | 17 ++++--- .../process/test_arrhenius_rate_constant.cpp | 34 +++++++------- .../process/test_branched_rate_constant.cpp | 22 +++++----- .../process/test_surface_rate_constant.cpp | 19 +++++++- ...nary_chemical_activation_rate_constant.cpp | 22 +++++----- test/unit/process/test_troe_rate_constant.cpp | 44 +++++++++---------- .../process/test_tunneling_rate_constant.cpp | 16 +++---- .../test_user_defined_rate_constant.cpp | 29 ++++++++++-- .../unit/solver/test_linear_solver_policy.hpp | 7 +-- test/unit/util/test_matrix_policy.hpp | 4 +- 31 files changed, 275 insertions(+), 187 deletions(-) delete mode 100644 include/micm/util/exit_codes.hpp create mode 100644 include/micm/util/jacobian.hpp diff --git a/include/micm/process/arrhenius_rate_constant.hpp b/include/micm/process/arrhenius_rate_constant.hpp index ac4f04bc3..e680903c1 100644 --- a/include/micm/process/arrhenius_rate_constant.hpp +++ b/include/micm/process/arrhenius_rate_constant.hpp @@ -47,6 +47,11 @@ namespace micm /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; + double calculate(const double& temperature, const double& pressure) const; }; @@ -72,6 +77,11 @@ namespace micm return calculate(conditions.temperature_, conditions.pressure_); } + inline double ArrheniusRateConstant::calculate(const Conditions& conditions) const + { + return calculate(conditions.temperature_, conditions.pressure_); + } + inline double ArrheniusRateConstant::calculate(const double& temperature, const double& pressure) const { return parameters_.A_ * std::exp(parameters_.C_ / temperature) * std::pow(temperature / parameters_.D_, parameters_.B_) * diff --git a/include/micm/process/branched_rate_constant.hpp b/include/micm/process/branched_rate_constant.hpp index 58dd177ff..8291bd7dc 100644 --- a/include/micm/process/branched_rate_constant.hpp +++ b/include/micm/process/branched_rate_constant.hpp @@ -54,6 +54,11 @@ namespace micm /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; + /// @brief Calculate the rate constant /// @param temperature Temperature in [K] /// @param air_number_density Number density in [mol m-3] @@ -92,6 +97,11 @@ namespace micm return calculate(conditions.temperature_, conditions.air_density_); } + inline double BranchedRateConstant::calculate(const Conditions& conditions) const + { + return calculate(conditions.temperature_, conditions.air_density_); + } + inline double BranchedRateConstant::calculate(const double& temperature, const double& air_number_density) const { double pre = parameters_.X_ * std::exp(-parameters_.Y_ / temperature); diff --git a/include/micm/process/rate_constant.hpp b/include/micm/process/rate_constant.hpp index 036571190..2dd82e9eb 100644 --- a/include/micm/process/rate_constant.hpp +++ b/include/micm/process/rate_constant.hpp @@ -36,6 +36,15 @@ namespace micm return 0; } + /// @brief Calculate the rate constant for a set of conditions + /// @param conditions The current environmental conditions of the chemical system + /// @param custom_parameters User defined rate constant parameters + /// @return The reaction rate constant + virtual double calculate(const Conditions& conditions) const + { + return 0; + } + /// @brief Calculate the rate constant for a set of conditions /// @param conditions The current environmental conditions of the chemical system /// @param custom_parameters User defined rate constant parameters diff --git a/include/micm/process/surface_rate_constant.hpp b/include/micm/process/surface_rate_constant.hpp index 1781f51f3..e72cb477e 100644 --- a/include/micm/process/surface_rate_constant.hpp +++ b/include/micm/process/surface_rate_constant.hpp @@ -56,6 +56,11 @@ namespace micm /// @param custom_parameters User-defined rate constant parameters /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; }; inline SurfaceRateConstant::SurfaceRateConstant(const SurfaceRateConstantParameters& parameters) @@ -70,6 +75,12 @@ namespace micm return std::unique_ptr{ new SurfaceRateConstant{ *this } }; } + inline double SurfaceRateConstant::calculate( + const Conditions& conditions) const + { + throw std::runtime_error("Surface rate constants must be supplied with a radius and number density using the alternative calculate function"); + } + inline double SurfaceRateConstant::calculate( const Conditions& conditions, std::vector::const_iterator custom_parameters) const diff --git a/include/micm/process/ternary_chemical_activation_rate_constant.hpp b/include/micm/process/ternary_chemical_activation_rate_constant.hpp index 715fce2d2..afd80844f 100644 --- a/include/micm/process/ternary_chemical_activation_rate_constant.hpp +++ b/include/micm/process/ternary_chemical_activation_rate_constant.hpp @@ -52,6 +52,11 @@ namespace micm /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; + /// @brief Calculate the rate constant /// @param temperature Temperature in [K] /// @param air_number_density Number density in [mol m-3] @@ -75,6 +80,12 @@ namespace micm return std::unique_ptr{ new TernaryChemicalActivationRateConstant{ *this } }; } + inline double TernaryChemicalActivationRateConstant::calculate(const Conditions& conditions) const + { + double val = calculate(conditions.temperature_, conditions.air_density_); + return val; + } + inline double TernaryChemicalActivationRateConstant::calculate( const Conditions& conditions, std::vector::const_iterator custom_parameters) const diff --git a/include/micm/process/troe_rate_constant.hpp b/include/micm/process/troe_rate_constant.hpp index 9c6fa85c0..f721720f6 100644 --- a/include/micm/process/troe_rate_constant.hpp +++ b/include/micm/process/troe_rate_constant.hpp @@ -52,6 +52,11 @@ namespace micm /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; + /// @brief Calculate the rate constant /// @param temperature Temperature in [K] /// @param air_number_density Number density in [mol m-3] @@ -74,6 +79,11 @@ namespace micm return std::unique_ptr{ new TroeRateConstant{ *this } }; } + inline double TroeRateConstant::calculate(const Conditions& conditions) const + { + return calculate(conditions.temperature_, conditions.air_density_); + } + inline double TroeRateConstant::calculate( const Conditions& conditions, std::vector::const_iterator custom_parameters) const diff --git a/include/micm/process/tunneling_rate_constant.hpp b/include/micm/process/tunneling_rate_constant.hpp index 26b366b83..deab180c8 100644 --- a/include/micm/process/tunneling_rate_constant.hpp +++ b/include/micm/process/tunneling_rate_constant.hpp @@ -42,6 +42,11 @@ namespace micm /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; + /// @brief Calculate the rate constant /// @param temperature Temperature in [K] /// @return the calculated rate constant @@ -63,6 +68,11 @@ namespace micm return std::unique_ptr{ new TunnelingRateConstant{ *this } }; } + inline double TunnelingRateConstant::calculate(const Conditions& conditions) const + { + return calculate(conditions.temperature_); + } + inline double TunnelingRateConstant::calculate( const Conditions& conditions, std::vector::const_iterator custom_parameters) const diff --git a/include/micm/process/user_defined_rate_constant.hpp b/include/micm/process/user_defined_rate_constant.hpp index 1b9428991..68f48cd38 100644 --- a/include/micm/process/user_defined_rate_constant.hpp +++ b/include/micm/process/user_defined_rate_constant.hpp @@ -43,6 +43,11 @@ namespace micm /// @param custom_parameters User-defined rate constant parameters /// @return A rate constant based off of the conditions in the system double calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const override; + + /// @brief Calculate the rate constant + /// @param conditions The current environmental conditions of the chemical system + /// @return A rate constant based off of the conditions in the system + double calculate(const Conditions& conditions) const override; }; inline UserDefinedRateConstant::UserDefinedRateConstant() @@ -60,6 +65,11 @@ namespace micm return std::unique_ptr{ new UserDefinedRateConstant{ *this } }; } + inline double UserDefinedRateConstant::calculate(const Conditions& conditions) const + { + throw std::runtime_error("User defined rate constants must be supplied with custom rate parameters using the alternative calculate function"); + } + inline double UserDefinedRateConstant::calculate( const Conditions& conditions, std::vector::const_iterator custom_parameters) const diff --git a/include/micm/solver/linear_solver.hpp b/include/micm/solver/linear_solver.hpp index 9ef23eb62..44569dc2a 100644 --- a/include/micm/solver/linear_solver.hpp +++ b/include/micm/solver/linear_solver.hpp @@ -82,9 +82,7 @@ namespace micm void Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); template class MatrixPolicy> requires(VectorizableDense> && VectorizableSparse>) - void Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); - - std::pair, SparseMatrixPolicy> GetLUMatrices(const SparseMatrixPolicy& matrix, T initial_value) const; + void Solve(const MatrixPolicy& b, MatrixPolicy& x, SparseMatrixPolicy& lower_matrix, SparseMatrixPolicy& upper_matrix); }; } // namespace micm diff --git a/include/micm/solver/linear_solver.inl b/include/micm/solver/linear_solver.inl index a77ba9a4c..741958ff6 100644 --- a/include/micm/solver/linear_solver.inl +++ b/include/micm/solver/linear_solver.inl @@ -225,10 +225,4 @@ namespace micm } } } - - template class SparseMatrixPolicy, class LuDecompositionPolicy> - std::pair, SparseMatrixPolicy> LinearSolver::GetLUMatrices(const SparseMatrixPolicy& matrix, T initial_value) const { - return lu_decomp_.GetLUMatrices(matrix, initial_value); - } - } // namespace micm \ No newline at end of file diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index c5012cd33..e78ed639e 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/include/micm/solver/rosenbrock.inl b/include/micm/solver/rosenbrock.inl index 506136795..ed9cb9342 100644 --- a/include/micm/solver/rosenbrock.inl +++ b/include/micm/solver/rosenbrock.inl @@ -17,27 +17,7 @@ } namespace micm -{ - // annonymous namespace to hide jacobian builder - namespace { - template class SparseMatrixPolicy> - SparseMatrixPolicy build_jacobian( - std::set> nonzero_jacobian_elements, - size_t number_of_grid_cells, - size_t state_size - ) - { - auto builder = SparseMatrixPolicy::create(state_size).number_of_blocks(number_of_grid_cells); - for (auto& elem : nonzero_jacobian_elements) - builder = builder.with_element(elem.first, elem.second); - // Always include diagonal elements - for (std::size_t i = 0; i < state_size; ++i) - builder = builder.with_element(i, i); - - return SparseMatrixPolicy(builder); - } - } - +{ // // RosenbrockSolver // @@ -160,7 +140,7 @@ namespace micm .variable_names_ = system.UniqueNames(state_reordering), .custom_rate_parameter_labels_ = param_labels, .jacobian_diagonal_elements_ = jacobian_diagonal_elements, - .state_size_ = system.StateSize() + .nonzero_jacobian_elements_ = process_set_.NonZeroJacobianElements() }; process_set_.SetJacobianFlatIds(jacobian); @@ -170,21 +150,7 @@ namespace micm template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> inline State RosenbrockSolver::GetState() const { - auto state = State{ state_parameters_ }; - - state.jacobian_ = build_jacobian( - process_set_.NonZeroJacobianElements(), - state_parameters_.number_of_grid_cells_, - state_parameters_.state_size_ - ); - - auto lu = linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); - auto lower_matrix = std::move(lu.first); - auto upper_matrix = std::move(lu.second); - state.lower_matrix_ = lower_matrix; - state.upper_matrix_ = upper_matrix; - - return state; + return State{ state_parameters_ }; } template class MatrixPolicy, template class SparseMatrixPolicy, class LinearSolverPolicy> diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index d6e112bd9..18f0239d5 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -20,21 +22,18 @@ namespace micm { std::size_t number_of_grid_cells_{ 1 }; std::size_t number_of_rate_constants_{ 0 }; - std::map custom_rate_parameter_map_; std::vector variable_names_{}; std::vector custom_rate_parameter_labels_{}; std::vector jacobian_diagonal_elements_; - size_t state_size_; + std::set> nonzero_jacobian_elements_; }; - template< - template class MatrixPolicy = Matrix, - template class SparseMatrixPolicy = StandardSparseMatrix> + template class MatrixPolicy = Matrix, template class SparseMatrixPolicy = StandardSparseMatrix> struct State { /// @brief The concentration of chemicals, varies through time MatrixPolicy variables_; - /// @brief Rate paramters particular to user-defined rate constants, may vary in time + /// @brief Rate paramters particular to user-defined rate constants, may vary in time MatrixPolicy custom_rate_parameters_; /// @brief The reaction rates, may vary in time MatrixPolicy rate_constants_; @@ -48,16 +47,11 @@ namespace micm std::vector variable_names_{}; SparseMatrixPolicy lower_matrix_; SparseMatrixPolicy upper_matrix_; + size_t state_size_; /// @brief State(); - /// @brief - /// @param state_size The number of System state variables - /// @param custom_parameters_size The number of custom rate parameters - /// @param process_size The number of processes to store rate constants for - State(const std::size_t state_size, const std::size_t custom_parameters_size, const std::size_t process_size); - /// @brief /// @param parameters State dimension information State(const StateParameters& parameters); diff --git a/include/micm/solver/state.inl b/include/micm/solver/state.inl index 27bd72b58..ae9b91d3c 100644 --- a/include/micm/solver/state.inl +++ b/include/micm/solver/state.inl @@ -14,19 +14,6 @@ namespace micm { } - template class MatrixPolicy, template class SparseMatrixPolicy> - inline State::State( - const std::size_t state_size, - const std::size_t custom_parameters_size, - const std::size_t process_size) - : conditions_(1), - variables_(1, state_size, 0.0), - custom_rate_parameters_(1, custom_parameters_size, 0.0), - rate_constants_(1, process_size, 0.0), - jacobian_() - { - } - template class MatrixPolicy, template class SparseMatrixPolicy> inline State::State(const StateParameters& parameters) : conditions_(parameters.number_of_grid_cells_), @@ -36,14 +23,30 @@ namespace micm variable_map_(), custom_rate_parameter_map_(), variable_names_(parameters.variable_names_), - jacobian_() + jacobian_(), + lower_matrix_(), + upper_matrix_(), + state_size_(parameters.variable_names_.size()) { + assert(state_size_ > 0); std::size_t index = 0; for (auto& name : variable_names_) variable_map_[name] = index++; index = 0; for (auto& label : parameters.custom_rate_parameter_labels_) custom_rate_parameter_map_[label] = index++; + + jacobian_ = build_jacobian( + parameters.nonzero_jacobian_elements_, + parameters.number_of_grid_cells_, + state_size_ + ); + + auto lu = LuDecomposition::GetLUMatrices(jacobian_, 1.0e-30); + auto lower_matrix = std::move(lu.first); + auto upper_matrix = std::move(lu.second); + lower_matrix_ = lower_matrix; + upper_matrix_ = upper_matrix; } template class MatrixPolicy, template class SparseMatrixPolicy> diff --git a/include/micm/util/exit_codes.hpp b/include/micm/util/exit_codes.hpp deleted file mode 100644 index b5027fb81..000000000 --- a/include/micm/util/exit_codes.hpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2023 National Center for Atmospheric Research, -// -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -namespace micm -{ - enum ExitCodes - { - InvalidMatrixDimension = 1, - }; -} \ No newline at end of file diff --git a/include/micm/util/jacobian.hpp b/include/micm/util/jacobian.hpp new file mode 100644 index 000000000..ad18dc3d4 --- /dev/null +++ b/include/micm/util/jacobian.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2023 National Center for Atmospheric Research, +// +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +namespace micm +{ + // annonymous namespace to hide jacobian builder + template class SparseMatrixPolicy> + SparseMatrixPolicy build_jacobian( + std::set> nonzero_jacobian_elements, + size_t number_of_grid_cells, + size_t state_size) + { + auto builder = SparseMatrixPolicy::create(state_size).number_of_blocks(number_of_grid_cells); + for (auto& elem : nonzero_jacobian_elements) + builder = builder.with_element(elem.first, elem.second); + // Always include diagonal elements + for (std::size_t i = 0; i < state_size; ++i) + builder = builder.with_element(i, i); + + return SparseMatrixPolicy(builder); + } +} // namespace micm \ No newline at end of file diff --git a/include/micm/util/matrix.hpp b/include/micm/util/matrix.hpp index fe98bc3a4..9eb4284c7 100644 --- a/include/micm/util/matrix.hpp +++ b/include/micm/util/matrix.hpp @@ -5,7 +5,6 @@ #include #include -#include #include namespace micm @@ -49,8 +48,7 @@ namespace micm // check that this row matches the expected rectangular matrix dimensions if (other.size() < y_dim_) { - std::cerr << "Matrix row size mismatch in assignment from vector"; - std::exit(micm::ExitCodes::InvalidMatrixDimension); + throw std::runtime_error("Matrix row size mismatch in assignment from vector"); } auto other_elem = other.begin(); for (auto &elem : *this) @@ -163,8 +161,7 @@ namespace micm // check that this row matches the expected rectangular matrix dimensions if (other[x].size() != y_dim) { - std::cerr << "Invalid vector for matrix assignment\n"; - std::exit(micm::ExitCodes::InvalidMatrixDimension); + throw std::runtime_error("Invalid vector for matrix assignment"); } for (std::size_t y{}; y < y_dim; ++y) { @@ -217,4 +214,4 @@ namespace micm } }; -} // namespace micm \ No newline at end of file +} // namespace micm diff --git a/include/micm/util/vector_matrix.hpp b/include/micm/util/vector_matrix.hpp index a8507f6f9..465aadd85 100644 --- a/include/micm/util/vector_matrix.hpp +++ b/include/micm/util/vector_matrix.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #ifndef DEFAULT_VECTOR_SIZE @@ -52,8 +51,7 @@ namespace micm { if (other.size() < y_dim_) { - std::cerr << "Matrix row size mismatch in assignment from vector"; - std::exit(micm::ExitCodes::InvalidMatrixDimension); + throw std::runtime_error("Matrix row size mismatch in assignment from vector."); } auto iter = std::next(matrix_.data_.begin(), group_index_ * y_dim_ * L + row_index_); std::for_each( @@ -165,8 +163,7 @@ namespace micm { if (other_row.size() != y_dim) { - std::cerr << "Invalid vector for matrix assignment\n"; - std::exit(micm::ExitCodes::InvalidMatrixDimension); + throw std::runtime_error("Invalid vector for matrix assignment"); } auto iter = std::next(data.begin(), std::floor(i_row / (double)L) * y_dim * L + i_row % L); for (auto &elem : other_row) diff --git a/test/integration/e5.hpp b/test/integration/e5.hpp index efe968798..f5763df1e 100644 --- a/test/integration/e5.hpp +++ b/test/integration/e5.hpp @@ -50,7 +50,6 @@ class E5 : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -65,9 +64,9 @@ class E5 : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.variable_names_.size()); - auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lu = micm::LuDecomposition::GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); auto upper_matrix = std::move(lu.second); state.lower_matrix_ = lower_matrix; diff --git a/test/integration/hires.hpp b/test/integration/hires.hpp index 4f7674bd8..0c39a896f 100644 --- a/test/integration/hires.hpp +++ b/test/integration/hires.hpp @@ -51,7 +51,6 @@ class HIRES : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -66,9 +65,9 @@ class HIRES : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.variable_names_.size()); - auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lu = micm::LuDecomposition::GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); auto upper_matrix = std::move(lu.second); state.lower_matrix_ = lower_matrix; diff --git a/test/integration/oregonator.hpp b/test/integration/oregonator.hpp index e2477e0a8..6c457c282 100644 --- a/test/integration/oregonator.hpp +++ b/test/integration/oregonator.hpp @@ -51,7 +51,6 @@ class Oregonator : public micm::RosenbrockSolverlinear_solver_ = LinearSolverPolicy(jacobian, 1.0e-30); @@ -66,9 +65,9 @@ class Oregonator : public micm::RosenbrockSolver{ this->state_parameters_ }; state.jacobian_ = micm::build_jacobian( - nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.state_size_); + nonzero_jacobian_elements_, this->state_parameters_.number_of_grid_cells_, this->state_parameters_.variable_names_.size()); - auto lu = this->linear_solver_.GetLUMatrices(state.jacobian_, 1.0e-30); + auto lu = micm::LuDecomposition::GetLUMatrices(state.jacobian_, 1.0e-30); auto lower_matrix = std::move(lu.first); auto upper_matrix = std::move(lu.second); state.lower_matrix_ = lower_matrix; diff --git a/test/regression/RosenbrockChapman/chapman_ode_solver.hpp b/test/regression/RosenbrockChapman/chapman_ode_solver.hpp index b38477363..917710fc8 100644 --- a/test/regression/RosenbrockChapman/chapman_ode_solver.hpp +++ b/test/regression/RosenbrockChapman/chapman_ode_solver.hpp @@ -124,11 +124,11 @@ namespace micm /// @brief Returns a list of species that participate in photolysis /// @return vector of strings - std::vector photolysis_names(); + std::vector photolysis_names() const; /// @brief Returns a list of species names /// @return vector of strings - std::vector species_names(); + std::vector species_names() const; /// @brief Calculate a chemical forcing /// @param rate_constants List of rate constants for each needed species @@ -305,7 +305,14 @@ namespace micm inline State<> ChapmanODESolver::GetState() const { - return State{ 9, 3, 7 }; + auto state_parameters = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 7, + .variable_names_ = species_names(), + .custom_rate_parameter_labels_ = photolysis_names(), + }; + + return micm::State{ state_parameters }; } inline ChapmanODESolver::SolverResult ChapmanODESolver::Solve(double time_start, double time_end, State<>& state) noexcept @@ -488,7 +495,7 @@ namespace micm return std::vector{ "O2_1", "O3_1", "O3_2", "N2_O1D_1", "O1D_O2_1", "O_O3_1", "M_O_O2_1" }; } - inline std::vector ChapmanODESolver::photolysis_names() + inline std::vector ChapmanODESolver::photolysis_names() const { return std::vector{ "O2_1", @@ -497,7 +504,7 @@ namespace micm }; } - inline std::vector ChapmanODESolver::species_names() + inline std::vector ChapmanODESolver::species_names() const { return std::vector{ "M", "Ar", "CO2", "H2O", "N2", "O1D", "O", "O2", "O3", diff --git a/test/unit/process/test_arrhenius_rate_constant.cpp b/test/unit/process/test_arrhenius_rate_constant.cpp index 54dcd0f64..286d7279e 100644 --- a/test/unit/process/test_arrhenius_rate_constant.cpp +++ b/test/unit/process/test_arrhenius_rate_constant.cpp @@ -7,73 +7,75 @@ TEST(ArrheniusRateConstant, CalculateWithSystem) { micm::ArrheniusRateConstant zero{}; - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); - auto k = zero.calculate(state.conditions_[0], params); + micm::Conditions conditions = { + .temperature_ = 301.24 // [K] + }; + + auto k = zero.calculate(conditions); EXPECT_NEAR(k, 1, 0.01); micm::ArrheniusRateConstantParameters parameters; parameters.A_ = 1; micm::ArrheniusRateConstant basic(parameters); - k = basic.calculate(state.conditions_[0], params); + k = basic.calculate(conditions); EXPECT_NEAR(k, 1, 0.01); // values from https://jpldataeval.jpl.nasa.gov/pdf/JPL_00-03.pdf parameters.A_ = 2.2e-10; micm::ArrheniusRateConstant o1d(parameters); - k = o1d.calculate(state.conditions_[0], params); + k = o1d.calculate(conditions); EXPECT_NEAR(k, 2.2e-10, 0.01); // O + HO2 -> OH + O2 parameters.A_ = 3e-11; parameters.C_ = -200; micm::ArrheniusRateConstant hox(parameters); - k = hox.calculate(state.conditions_[0], params); + k = hox.calculate(conditions); EXPECT_NEAR(k, 3e-11 * std::exp(-200 / 301.24), 0.01); // OH + HCl → H2O + Cl parameters.A_ = 2.6e-12; parameters.C_ = -350; micm::ArrheniusRateConstant clox(parameters); - k = clox.calculate(state.conditions_[0], params); + k = clox.calculate(conditions); EXPECT_NEAR(k, 2.6e-12 * std::exp(-350 / 301.24), 0.01); } TEST(ArrheniusRateConstant, CalculateWithPrescribedArugments) { - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions = { + .temperature_ = 301.24 // [K] + }; + micm::ArrheniusRateConstant zero{}; - auto k = zero.calculate(state.conditions_[0], params); + auto k = zero.calculate(conditions); EXPECT_NEAR(k, 1, 0.01); micm::ArrheniusRateConstantParameters parameters; parameters.A_ = 1; micm::ArrheniusRateConstant basic(parameters); - k = basic.calculate(state.conditions_[0], params); + k = basic.calculate(conditions); EXPECT_NEAR(k, 1, 0.01); // values from https://jpldataeval.jpl.nasa.gov/pdf/JPL_00-03.pdf parameters.A_ = 2.2e-10; micm::ArrheniusRateConstant o1d(parameters); - k = o1d.calculate(state.conditions_[0], params); + k = o1d.calculate(conditions); EXPECT_NEAR(k, 2.2e-10, 0.01); // O + HO2 -> OH + O2 parameters.A_ = 3e-11; parameters.C_ = -200; micm::ArrheniusRateConstant hox(parameters); - k = hox.calculate(state.conditions_[0], params); + k = hox.calculate(conditions); EXPECT_NEAR(k, 3e-11 * std::exp(200 / 301.24), 0.01); // OH + HCl → H2O + Cl parameters.A_ = 2.6e-12; parameters.C_ = -350; micm::ArrheniusRateConstant clox(parameters); - k = clox.calculate(state.conditions_[0], params); + k = clox.calculate(conditions); EXPECT_NEAR(k, 2.6e-12 * std::exp(-350 / 301.24), 0.01); } diff --git a/test/unit/process/test_branched_rate_constant.cpp b/test/unit/process/test_branched_rate_constant.cpp index 8430c1b4b..d1f57a6af 100644 --- a/test/unit/process/test_branched_rate_constant.cpp +++ b/test/unit/process/test_branched_rate_constant.cpp @@ -7,14 +7,15 @@ TEST(BranchedRateConstant, CalculateAlkoxyBranchWithAllArugments) { - micm::State state{ 0, 0, 1 }; double temperature = 301.24; - state.conditions_[0].temperature_ = temperature; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions = { + .temperature_ = temperature, // [K] + .air_density_ = 42.2 // [mol mol-1] + }; + micm::BranchedRateConstant branched{ micm::BranchedRateConstantParameters{ .branch_ = micm::BranchedRateConstantParameters::Branch::Alkoxy, .X_ = 1.2, .Y_ = 204.3, .a0_ = 1.0e-3, .n_ = 2 } }; - auto k = branched.calculate(state.conditions_[0], params); + auto k = branched.calculate(conditions); double air_dens_n_cm3 = 42.2 * AVOGADRO_CONSTANT * 1.0e-6; double a = 2.0e-22 * std::exp(2) * 2.45e19; double b = 0.43 * std::pow((293.0 / 298.0), -8.0); @@ -28,14 +29,15 @@ TEST(BranchedRateConstant, CalculateAlkoxyBranchWithAllArugments) TEST(BranchedRateConstant, CalculateNitrateBranchWithAllArugments) { - micm::State state{ 0, 0, 1 }; double temperature = 301.24; - state.conditions_[0].temperature_ = temperature; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions = { + .temperature_ = temperature, // [K] + .air_density_ = 42.2 // [mol mol-1] + }; + micm::BranchedRateConstant branched{ micm::BranchedRateConstantParameters{ .branch_ = micm::BranchedRateConstantParameters::Branch::Nitrate, .X_ = 1.2, .Y_ = 204.3, .a0_ = 1.0e-3, .n_ = 2 } }; - auto k = branched.calculate(state.conditions_[0], params); + auto k = branched.calculate(conditions); double air_dens_n_cm3 = 42.2 * AVOGADRO_CONSTANT * 1.0e-6; double a = 2.0e-22 * std::exp(2) * 2.45e19; double b = 0.43 * std::pow((293.0 / 298.0), -8.0); diff --git a/test/unit/process/test_surface_rate_constant.cpp b/test/unit/process/test_surface_rate_constant.cpp index 0444e7f48..5046cb7e1 100644 --- a/test/unit/process/test_surface_rate_constant.cpp +++ b/test/unit/process/test_surface_rate_constant.cpp @@ -7,7 +7,15 @@ TEST(SurfaceRateConstant, CalculateDefaultProbability) { micm::Species foo("foo", { { "molecular weight [kg mol-1]", 0.025 }, { "diffusion coefficient [m2 s-1]", 2.3e2 } }); - micm::State state{ 0, 2, 1 }; + + auto state_parameters_ = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 1, + .variable_names_ = {"surface"}, + .custom_rate_parameter_labels_ = { "effective radius [m]", "particle number concentration [# m-3]" }, + }; + + micm::State state{ state_parameters_ }; state.custom_rate_parameters_[0][0] = 1.0e-7; // effective radius [m] state.custom_rate_parameters_[0][1] = 2.5e6; // particle concentration [# m-3] state.conditions_[0].temperature_ = 273.65; // K @@ -25,7 +33,14 @@ TEST(SurfaceRateConstant, CalculateDefaultProbability) TEST(SurfaceRateConstant, CalculateSpecifiedProbability) { micm::Species foo("foo", { { "molecular weight [kg mol-1]", 0.025 }, { "diffusion coefficient [m2 s-1]", 2.3e2 } }); - micm::State state{ 0, 2, 1 }; + auto state_parameters_ = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 1, + .variable_names_ = {"surface"}, + .custom_rate_parameter_labels_ = { "effective radius [m]", "particle number concentration [# m-3]" }, + }; + + micm::State state{ state_parameters_ }; state.custom_rate_parameters_[0][0] = 1.0e-7; // effective radius [m] state.custom_rate_parameters_[0][1] = 2.5e6; // particle concentration [# m-3] state.conditions_[0].temperature_ = 273.65; // K diff --git a/test/unit/process/test_ternary_chemical_activation_rate_constant.cpp b/test/unit/process/test_ternary_chemical_activation_rate_constant.cpp index 85b39bdf1..630ec135b 100644 --- a/test/unit/process/test_ternary_chemical_activation_rate_constant.cpp +++ b/test/unit/process/test_ternary_chemical_activation_rate_constant.cpp @@ -6,15 +6,15 @@ TEST(TernaryChemicalActivationRateConstant, CalculateWithMinimalArugments) { - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = 301.24, // [K] + .air_density_ = 42.2, // [mol mol-1] + }; micm::TernaryChemicalActivationRateConstantParameters ternary_params; ternary_params.k0_A_ = 1.0; ternary_params.kinf_A_ = 1.0; micm::TernaryChemicalActivationRateConstant ternary{ ternary_params }; - auto k = ternary.calculate(state.conditions_[0], params); + auto k = ternary.calculate(conditions); double k0 = 1.0; double kinf = 1.0; EXPECT_EQ(k, k0 / (1.0 + k0 * 42.2 / kinf) * std::pow(0.6, 1.0 / (1 + std::pow(std::log10(k0 * 42.2 / kinf), 2)))); @@ -22,11 +22,11 @@ TEST(TernaryChemicalActivationRateConstant, CalculateWithMinimalArugments) TEST(TernaryChemicalActivationRateConstant, CalculateWithAllArugments) { - micm::State state{ 0, 0, 1 }; - double temperature = 301.24; - state.conditions_[0].temperature_ = temperature; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + double temperature = 301.24; // [K] + micm::Conditions conditions { + .temperature_ = temperature, + .air_density_ = 42.2, // [mol mol-1] + }; micm::TernaryChemicalActivationRateConstant ternary{ micm::TernaryChemicalActivationRateConstantParameters{ .k0_A_ = 1.2, .k0_B_ = 2.3, @@ -36,7 +36,7 @@ TEST(TernaryChemicalActivationRateConstant, CalculateWithAllArugments) .kinf_C_ = 402.1, .Fc_ = 0.9, .N_ = 1.2 } }; - auto k = ternary.calculate(state.conditions_[0], params); + auto k = ternary.calculate(conditions); double k0 = 1.2 * std::exp(302.3 / temperature) * std::pow(temperature / 300.0, 2.3); double kinf = 2.6 * std::exp(402.1 / temperature) * std::pow(temperature / 300.0, -3.1); EXPECT_EQ( diff --git a/test/unit/process/test_troe_rate_constant.cpp b/test/unit/process/test_troe_rate_constant.cpp index 029def7d2..674631b8f 100644 --- a/test/unit/process/test_troe_rate_constant.cpp +++ b/test/unit/process/test_troe_rate_constant.cpp @@ -6,15 +6,15 @@ TEST(TroeRateConstant, CalculateWithMinimalArugments) { - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = 301.24, // [K] + .air_density_ = 42.2, // [mol mol-1] + }; micm::TroeRateConstantParameters troe_params; troe_params.k0_A_ = 1.0; troe_params.kinf_A_ = 1.0; micm::TroeRateConstant troe{ troe_params }; - auto k = troe.calculate(state.conditions_[0], params); + auto k = troe.calculate(conditions); double k0 = 1.0; double kinf = 1.0; EXPECT_EQ(k, 42.2 * k0 / (1.0 + 42.2 * k0 / kinf) * std::pow(0.6, 1.0 / (1 + std::pow(std::log10(42.2 * k0 / kinf), 2)))); @@ -22,11 +22,11 @@ TEST(TroeRateConstant, CalculateWithMinimalArugments) TEST(TroeRateConstant, CalculateWithAllArugments) { - micm::State state{ 0, 0, 1 }; - double temperature = 301.24; - state.conditions_[0].temperature_ = temperature; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + double temperature = 301.24; // [K] + micm::Conditions conditions { + .temperature_ = temperature, + .air_density_ = 42.2, // [mol mol-1] + }; micm::TroeRateConstant troe{ micm::TroeRateConstantParameters{ .k0_A_ = 1.2, .k0_B_ = 2.3, .k0_C_ = 302.3, @@ -35,7 +35,7 @@ TEST(TroeRateConstant, CalculateWithAllArugments) .kinf_C_ = 402.1, .Fc_ = 0.9, .N_ = 1.2 } }; - auto k = troe.calculate(state.conditions_[0], params); + auto k = troe.calculate(conditions); double k0 = 1.2 * std::exp(302.3 / temperature) * std::pow(temperature / 300.0, 2.3); double kinf = 2.6 * std::exp(402.1 / temperature) * std::pow(temperature / 300.0, -3.1); EXPECT_EQ( @@ -47,17 +47,16 @@ TEST(TroeRateConstant, CalculateWithAllArugments) TEST(TroeRateConstant, AnalyticalTroeExampleAB) { // based off of the troe rate constants in the analytical integration test: - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - - auto params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = 301.24, // [K] + .air_density_ = 42.2, // [mol mol-1] + }; micm::TroeRateConstantParameters troe_params; troe_params.k0_A_ = 4.0e-18; micm::TroeRateConstant troe{ troe_params }; - auto k = troe.calculate(state.conditions_[0], params); + auto k = troe.calculate(conditions); double k_0 = 4.0e-18; double k_inf = 1; @@ -70,18 +69,17 @@ TEST(TroeRateConstant, AnalyticalTroeExampleAB) TEST(TroeRateConstant, AnalyticalTroeExampleBC) { // based off of the troe rate constants in the analytical integration test: - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - state.conditions_[0].air_density_ = 42.2; // [mol mol-1] - - auto params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = 301.24, // [K] + .air_density_ = 42.2, // [mol mol-1] + }; micm::TroeRateConstantParameters troe_params{ .k0_A_ = 1.2e-12, .k0_B_ = 167.0, .k0_C_ = 3.0, .kinf_A_ = 136.0, .kinf_B_ = 5.0, .kinf_C_ = 24.0, .Fc_ = 0.9, .N_ = 0.8 }; micm::TroeRateConstant troe{ troe_params }; - auto k = troe.calculate(state.conditions_[0], params); + auto k = troe.calculate(conditions); double k_0 = 1.2e-12 * std::exp(3.0 / 301.24) * std::pow(301.24 / 300.0, 167.0); double k_inf = 136.0 * std::exp(24.0 / 301.24) * std::pow(301.24 / 300.0, 5.0); diff --git a/test/unit/process/test_tunneling_rate_constant.cpp b/test/unit/process/test_tunneling_rate_constant.cpp index 212f32c33..e83ee5af1 100644 --- a/test/unit/process/test_tunneling_rate_constant.cpp +++ b/test/unit/process/test_tunneling_rate_constant.cpp @@ -6,22 +6,22 @@ TEST(TunnelingRateConstant, CalculateWithMinimalArugments) { - micm::State state{ 0, 0, 1 }; - state.conditions_[0].temperature_ = 301.24; // [K] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = 301.24, // [K] + }; micm::TunnelingRateConstantParameters tunneling_params; micm::TunnelingRateConstant tunneling{ tunneling_params }; - auto k = tunneling.calculate(state.conditions_[0], params); + auto k = tunneling.calculate(conditions); EXPECT_NEAR(k, 1.0, 1.0e-8); } TEST(TunnelingRateConstant, CalculateWithAllArugments) { - micm::State state{ 0, 0, 1 }; double temperature = 301.24; - state.conditions_[0].temperature_ = temperature; // [K] - std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); + micm::Conditions conditions { + .temperature_ = temperature, // [K] + }; micm::TunnelingRateConstant tunneling{ micm::TunnelingRateConstantParameters{ .A_ = 1.2, .B_ = 2.3, .C_ = 302.3 } }; - auto k = tunneling.calculate(state.conditions_[0], params); + auto k = tunneling.calculate(conditions); EXPECT_NEAR(k, 1.2 * std::exp(-2.3 / temperature) * std::exp(302.3 / std::pow(temperature, 3)), 1.0e-8); } diff --git a/test/unit/process/test_user_defined_rate_constant.cpp b/test/unit/process/test_user_defined_rate_constant.cpp index 9be644134..a92d9d641 100644 --- a/test/unit/process/test_user_defined_rate_constant.cpp +++ b/test/unit/process/test_user_defined_rate_constant.cpp @@ -6,8 +6,16 @@ TEST(UserDefinedRateConstant, CalculateWithSystem) { - micm::State state{ 0, 1, 1 }; + auto state_parameters_ = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 1, + .variable_names_ = {"user"}, + .custom_rate_parameter_labels_ = { "my rate", }, + }; + + micm::State state{ state_parameters_ }; state.custom_rate_parameters_[0][0] = 0.5; + std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); micm::UserDefinedRateConstant photo{}; auto k = photo.calculate(state.conditions_[0], params); @@ -16,8 +24,16 @@ TEST(UserDefinedRateConstant, CalculateWithSystem) TEST(UserDefinedRateConstant, ConstructorWithRate) { - micm::State state{ 0, 1, 1 }; + auto state_parameters_ = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 1, + .variable_names_ = {"user"}, + .custom_rate_parameter_labels_ = { "my rate", }, + }; + + micm::State state{ state_parameters_ }; state.custom_rate_parameters_[0][0] = 1.1; + std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); micm::UserDefinedRateConstant photo{}; auto k = photo.calculate(state.conditions_[0], params); @@ -26,7 +42,14 @@ TEST(UserDefinedRateConstant, ConstructorWithRate) TEST(UserDefinedRateConstant, ConstructorWithRateAndName) { - micm::State state{ 0, 1, 1 }; + auto state_parameters_ = micm::StateParameters{ + .number_of_grid_cells_ = 1, + .number_of_rate_constants_ = 1, + .variable_names_ = {"user"}, + .custom_rate_parameter_labels_ = { "my rate", }, + }; + + micm::State state{ state_parameters_ }; state.custom_rate_parameters_[0][0] = 1.1; std::vector::const_iterator params = state.custom_rate_parameters_[0].begin(); micm::UserDefinedRateConstant photo({ .label_ = "a name" }); diff --git a/test/unit/solver/test_linear_solver_policy.hpp b/test/unit/solver/test_linear_solver_policy.hpp index 03c33e203..8bdeca9b0 100644 --- a/test/unit/solver/test_linear_solver_policy.hpp +++ b/test/unit/solver/test_linear_solver_policy.hpp @@ -2,6 +2,7 @@ #include #include +#include template class MatrixPolicy, template class SparseMatrixPolicy> void check_results( @@ -84,7 +85,7 @@ void testDenseMatrix(const std::function testConversionFromVector() std::vector> bad_vector = { { 3 }, { 4, 5 }, { 5 } }; MatrixPolicy bad_matrix; - EXPECT_DEATH(bad_matrix = bad_vector, "Invalid vector for matrix assignment"); + EXPECT_ANY_THROW(bad_matrix = bad_vector); return matrix; } @@ -199,7 +199,7 @@ MatrixPolicy testAssignmentFromVector() EXPECT_EQ(matrix[2][2], 65.7); EXPECT_EQ(matrix[3][0], 0.0); - EXPECT_DEATH(matrix[2] = small_other, "Matrix row size mismatch in assignment from vector"); + EXPECT_ANY_THROW(matrix[2] = small_other); return matrix; } From 2aa76f17bfb3c3a096f0e0a9ba695c90bddf03f4 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 11:41:26 -0500 Subject: [PATCH 22/30] removing state from jit process set --- include/micm/process/jit_process_set.hpp | 12 +++--------- test/unit/process/test_jit_process_set.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/micm/process/jit_process_set.hpp b/include/micm/process/jit_process_set.hpp index 52351c879..077de39df 100644 --- a/include/micm/process/jit_process_set.hpp +++ b/include/micm/process/jit_process_set.hpp @@ -33,11 +33,10 @@ namespace micm /// @param compiler JIT compiler /// @param processes Processes to create calculator for /// @param state Solver state - template class MatrixPolicy, template class SparseMatrixPolicy> JitProcessSet( std::shared_ptr compiler, const std::vector &processes, - const State &state); + const std::map& variable_map); ~JitProcessSet(); @@ -103,20 +102,15 @@ namespace micm } template - template class MatrixPolicy, template class SparseMatrixPolicy> inline JitProcessSet::JitProcessSet( std::shared_ptr compiler, const std::vector &processes, - const State &state) - : ProcessSet(processes, state.variable_map_), + const std::map& variable_map) + : ProcessSet(processes, variable_map), compiler_(compiler) { forcing_function_ = NULL; jacobian_function_ = NULL; - if (state.variables_.size() != L || state.variables_.GroupVectorSize() != L) - { - throw std::runtime_error("Invalid state for JitProcessSet. Check the the VectorMatrix template parameters."); - } this->GenerateForcingFunction(); } diff --git a/test/unit/process/test_jit_process_set.cpp b/test/unit/process/test_jit_process_set.cpp index f685ff8b0..e1476070d 100644 --- a/test/unit/process/test_jit_process_set.cpp +++ b/test/unit/process/test_jit_process_set.cpp @@ -31,7 +31,7 @@ TEST(JitProcessSet, VectorMatrix) testProcessSet>( [&](const std::vector& processes, const micm::State& state) -> micm::JitProcessSet<2> { - return micm::JitProcessSet<2>{ jit.get(), processes, state }; + return micm::JitProcessSet<2>{ jit.get(), processes, state.variable_map_ }; }); } @@ -49,7 +49,7 @@ TEST(RandomJitProcessSet, VectorMatrix) 30, [&](const std::vector& processes, const micm::State& state) -> micm::JitProcessSet<2000> { - return micm::JitProcessSet<2000>{ jit.get(), processes, state }; + return micm::JitProcessSet<2000>{ jit.get(), processes, state.variable_map_ }; }); testRandomSystem>( 3000, @@ -57,7 +57,7 @@ TEST(RandomJitProcessSet, VectorMatrix) 40, [&](const std::vector& processes, const micm::State& state) -> micm::JitProcessSet<3000> { - return micm::JitProcessSet<3000>{ jit.get(), processes, state }; + return micm::JitProcessSet<3000>{ jit.get(), processes, state.variable_map_ }; }); testRandomSystem>( 3000, @@ -65,7 +65,7 @@ TEST(RandomJitProcessSet, VectorMatrix) 20, [&](const std::vector& processes, const micm::State& state) -> micm::JitProcessSet<3000> { - return micm::JitProcessSet<3000>{ jit.get(), processes, state }; + return micm::JitProcessSet<3000>{ jit.get(), processes, state.variable_map_ }; }); testRandomSystem>( 4000, @@ -73,6 +73,6 @@ TEST(RandomJitProcessSet, VectorMatrix) 80, [&](const std::vector& processes, const micm::State& state) -> micm::JitProcessSet<4000> { - return micm::JitProcessSet<4000>{ jit.get(), processes, state }; + return micm::JitProcessSet<4000>{ jit.get(), processes, state.variable_map_ }; }); } \ No newline at end of file From e4b5e70b300f6eadf4c9b26c62ea75181bf3aee9 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 11:50:56 -0500 Subject: [PATCH 23/30] removing assert --- include/micm/solver/state.inl | 1 - 1 file changed, 1 deletion(-) diff --git a/include/micm/solver/state.inl b/include/micm/solver/state.inl index ae9b91d3c..b6e71c72e 100644 --- a/include/micm/solver/state.inl +++ b/include/micm/solver/state.inl @@ -28,7 +28,6 @@ namespace micm upper_matrix_(), state_size_(parameters.variable_names_.size()) { - assert(state_size_ > 0); std::size_t index = 0; for (auto& name : variable_names_) variable_map_[name] = index++; From 81686cef4100e4dfc00b00e35e938f3285f988bc Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 12:15:28 -0500 Subject: [PATCH 24/30] setting variable names --- include/micm/version.hpp | 66 +++++++++++++++--------------- test/unit/process/test_process.cpp | 1 + 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/include/micm/version.hpp b/include/micm/version.hpp index 6a5992c97..bebd0ee47 100644 --- a/include/micm/version.hpp +++ b/include/micm/version.hpp @@ -1,33 +1,33 @@ -// clang-format off -#pragma once - -#ifdef __cplusplus -namespace micm { -extern "C" { -#endif - - const char* getMicmVersion() - { - return "3.2.0"; - } - unsigned getMicmVersionMajor() - { - return 3; - } - unsigned getMicmVersionMinor() - { - return 2+0; - } - unsigned getMicmVersionPatch() - { - return 0+0; - } - unsigned getMicmVersionTweak() - { - return +0; - } - -#ifdef __cplusplus -} // extern "C" -} // namespace micm -#endif +// clang-format off +#pragma once + +#ifdef __cplusplus +namespace micm { +extern "C" { +#endif + + const char* getMicmVersion() + { + return "3.2.0"; + } + unsigned getMicmVersionMajor() + { + return 3; + } + unsigned getMicmVersionMinor() + { + return 2+0; + } + unsigned getMicmVersionPatch() + { + return 0+0; + } + unsigned getMicmVersionTweak() + { + return +0; + } + +#ifdef __cplusplus +} // extern "C" +} // namespace micm +#endif diff --git a/test/unit/process/test_process.cpp b/test/unit/process/test_process.cpp index 3529540dc..aa8ed0be5 100644 --- a/test/unit/process/test_process.cpp +++ b/test/unit/process/test_process.cpp @@ -32,6 +32,7 @@ void testProcessUpdateState(const std::size_t number_of_grid_cells) param_labels.push_back(label); micm::State state{ micm::StateParameters{ .number_of_grid_cells_ = number_of_grid_cells, .number_of_rate_constants_ = processes.size(), + .variable_names_ = { "foo", "bar'" }, .custom_rate_parameter_labels_ = param_labels, } }; From f98d981a68c19429770a693e4abfb7b95ed8e43b Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 12:44:57 -0500 Subject: [PATCH 25/30] removing parallel build to see if clang builds --- .github/workflows/ubuntu.yml | 2 +- include/micm/solver/state.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 3cd9aad7c..fbb131848 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -48,7 +48,7 @@ jobs: run: cmake -S . -B build -D CMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: Build - run: cmake --build build --parallel 10 + run: cmake --build build - name: Run tests run: | diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index 18f0239d5..5b7750439 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -24,8 +24,8 @@ namespace micm std::size_t number_of_rate_constants_{ 0 }; std::vector variable_names_{}; std::vector custom_rate_parameter_labels_{}; - std::vector jacobian_diagonal_elements_; - std::set> nonzero_jacobian_elements_; + std::vector jacobian_diagonal_elements_{}; + std::set> nonzero_jacobian_elements_{}; }; template class MatrixPolicy = Matrix, template class SparseMatrixPolicy = StandardSparseMatrix> From 3f80301a6b9e7cad6d39ca843ba5b40c05c97123 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 12:51:12 -0500 Subject: [PATCH 26/30] verbose build on clang --- .github/workflows/ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index fbb131848..64b81798f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -48,7 +48,7 @@ jobs: run: cmake -S . -B build -D CMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: Build - run: cmake --build build + run: cmake --build build --verbose - name: Run tests run: | From 7e554640d174f493283bd21e890eb34b9af30b14 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 13:19:45 -0500 Subject: [PATCH 27/30] attempting to force libc++ for clang to make test pass --- CMakeLists.txt | 6 ++++ include/micm/version.hpp | 66 ++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ea8bc748..95a710bbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,12 @@ endif() add_compile_definitions(DEFAULT_VECTOR_SIZE=${DEFAULT_VECTOR_MATRIX_SIZE}) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # If the compiler is Clang, use libc++ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +endif() + ################################################################################ # Dependencies diff --git a/include/micm/version.hpp b/include/micm/version.hpp index bebd0ee47..6a5992c97 100644 --- a/include/micm/version.hpp +++ b/include/micm/version.hpp @@ -1,33 +1,33 @@ -// clang-format off -#pragma once - -#ifdef __cplusplus -namespace micm { -extern "C" { -#endif - - const char* getMicmVersion() - { - return "3.2.0"; - } - unsigned getMicmVersionMajor() - { - return 3; - } - unsigned getMicmVersionMinor() - { - return 2+0; - } - unsigned getMicmVersionPatch() - { - return 0+0; - } - unsigned getMicmVersionTweak() - { - return +0; - } - -#ifdef __cplusplus -} // extern "C" -} // namespace micm -#endif +// clang-format off +#pragma once + +#ifdef __cplusplus +namespace micm { +extern "C" { +#endif + + const char* getMicmVersion() + { + return "3.2.0"; + } + unsigned getMicmVersionMajor() + { + return 3; + } + unsigned getMicmVersionMinor() + { + return 2+0; + } + unsigned getMicmVersionPatch() + { + return 0+0; + } + unsigned getMicmVersionTweak() + { + return +0; + } + +#ifdef __cplusplus +} // extern "C" +} // namespace micm +#endif From 9829a9e93af9b2f235b190456055165b0db60c72 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 13:39:33 -0500 Subject: [PATCH 28/30] only linking libc++ if on linux... --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95a710bbf..57fba0e6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ endif() add_compile_definitions(DEFAULT_VECTOR_SIZE=${DEFAULT_VECTOR_MATRIX_SIZE}) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +if (NOT ${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux" AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # If the compiler is Clang, use libc++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() From aa60756b3ea9d3b360543b578ad9e07f75899e8c Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 13:49:39 -0500 Subject: [PATCH 29/30] matching linux properly --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57fba0e6d..9ac8e3758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ endif() add_compile_definitions(DEFAULT_VECTOR_SIZE=${DEFAULT_VECTOR_MATRIX_SIZE}) -if (NOT ${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux" AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux" AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # If the compiler is Clang, use libc++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() From c50352ea5867846cbe31b99378834e73c3e40679 Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Thu, 26 Oct 2023 14:11:33 -0500 Subject: [PATCH 30/30] comment --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ac8e3758..9d40148da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ endif() add_compile_definitions(DEFAULT_VECTOR_SIZE=${DEFAULT_VECTOR_MATRIX_SIZE}) - +# on ubuntu with clang, an incorrect version of the c++ standard library was being linked if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux" AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # If the compiler is Clang, use libc++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")