From 42cf33fff4d4a7eb94f0c420d8793728c15b2485 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 6 Jun 2023 20:34:25 -0600 Subject: [PATCH 01/21] commit solver config with the return type of std::variant --- include/micm/configure/solver_config.hpp | 493 +++++++++++++++++++++++ 1 file changed, 493 insertions(+) create mode 100644 include/micm/configure/solver_config.hpp diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp new file mode 100644 index 000000000..90829d9b8 --- /dev/null +++ b/include/micm/configure/solver_config.hpp @@ -0,0 +1,493 @@ +/* Copyright (C) 2023 National Center for Atmospheric Research, + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_JSON +# include +#endif + +using json = nlohmann::json; + +namespace micm +{ + template + class ThrowPolicy + { + class Exception : public std::exception + { + public: + const char* msg_; + + public: + Exception(const char* msg) + : msg_(msg) + { + } + + virtual const char* what() + { + return msg_; + } + }; + + public: + Object OnError(std::string message) + { + throw Exception(message.c_str()); + } + }; + + template + class NoThrowPolicy + { + public: + Object OnError(std::string message) + { + std::cerr << message << std::endl; + return Object(); + } + }; + + /// Solover parameters + struct SolverParameters + { + micm::System system_; + std::vector processes_; + }; + + // Error code + enum class ConfigErrorCode + { + None = 0, + NoAcess, + FileNotFound, + KeyNotFound, + }; + + template + class JsonReaderPolicy : public ErrorPolicy + { + private: + std::vector species_; + std::vector emissions_; + std::vector first_order_loss_; + std::vector processes_; + micm::Phase phase_; + + public: + // Constants + static const inline std::string SPECIES_CONFIG = "species.json"; // TODO:jiwon 6/6 - instead of searching + static const inline std::string REACTIONS_CONFIG = "mechanism.json"; // TODO:jiwon 6/6 + + static const inline std::string CAMP_FILES = "camp-files"; + static const inline std::string CAMP_DATA = "camp-data"; + + static const inline std::string TYPE = "type"; + + // Functions + + /// @brief read and parse JSON objects + /// @param + /// @return SolverParameters if success, else ConfigErrorCode + std::variant ReadAndParse(const std::filesystem::path& path) + { + // Check whether file to path exists + if (!std::filesystem::exists(path)) + { + std::string err_msg = "Configuration file at path " + path.string() + " does not exist\n"; + this->OnError(err_msg); + + return micm::ConfigErrorCode::FileNotFound; + } + + // Read file to get the list of configure files + json data = json::parse(std::ifstream(path)); + if (!ValidateJsonWithKey(data, CAMP_FILES)) + { + return micm::ConfigErrorCode::KeyNotFound; + } + + // Check whether the listed files exist, and determine the sequence to read files. + std::string species_file; + std::vector other_files; + bool found_species_file = false; + + for (const auto& file : data[CAMP_FILES].get>()) + { + if (!std::filesystem::exists(file)) + { + std::string err_msg = "Configuration file at path " + file + " does not exist\n"; + this->OnError(err_msg); + + return micm::ConfigErrorCode::FileNotFound; + } + + // Find species file to read first + std::size_t found = file.find(SPECIES_CONFIG); + if (found != std::string::npos) + { + species_file = file; + found_species_file = true; + } + else + { + other_files.push_back(file); + } + } + + // Read species file to create Species and Phase that needs to be known to System and Process + if (found_species_file) + { + if (!ConfigureSpecies(species_file)) + { + return micm::ConfigErrorCode::KeyNotFound; + } + } + else + { + std::string err_msg = "Species configure file does not exist\n"; + this->OnError(err_msg); + + return micm::ConfigErrorCode::FileNotFound; + } + + // Read files, eg. reactions.json + for (const auto& file : other_files) + { + json file_data = json::parse(std::ifstream(file)); + if (!ValidateJsonWithKey(file_data, CAMP_DATA)) + { + return micm::ConfigErrorCode::KeyNotFound; + } + + std::vector objects; + for (const auto& element : file_data[CAMP_DATA]) + { + objects.push_back(element); + } + + if (!ParseObjectArray(objects)) + { + return micm::ConfigErrorCode::KeyNotFound; + } + } + + micm::SystemParameters sysParams = { phase_, std::vector() }; // TODO: jiwon 6/6 - second param + + return micm::SolverParameters{ micm::System(sysParams), processes_ }; + } + + // create species and phase + bool ConfigureSpecies(const std::string& file) + { + json file_data = json::parse(std::ifstream(file)); + + if (!ValidateJsonWithKey(file_data, CAMP_DATA)) + return false; + + std::vector objects; + for (const auto& element : file_data[CAMP_DATA]) + objects.push_back(element); + + for (const auto& object : objects) + { + if (!ValidateJsonWithKey(object, TYPE)) + return false; + + std::string type = object[TYPE].get(); + + if (type == "CHEM_SPEC") + { + if (!ParseChemicalSpecies(object)) + return false; + } + else if (type == "RELATIVE_TOLERANCE") + { + if (!ParseRelativeTolerance(object)) + return false; + } + } + // After creating Species, create Phase + phase_.species_ = species_; + + return true; + } + + bool ValidateJsonWithKey(const json& object, const std::string& key) + { + if (!object.contains(key)) + { + this->OnError("Key " + key + " was not found in the config file"); + + return false; + } + return true; + } + + bool ParseObjectArray(const std::vector& objects) + { + for (const auto& object : objects) + { + if (!ValidateJsonWithKey(object, TYPE)) + return false; + + std::string type = object[TYPE].get(); + + if (type == "MECHANISM") + { + if (!ParseMechanism(object)) + return false; + } + else if (type == "PHOTOLYSIS") + { + if (!ParsePhotolysis(object)) + return false; + } + else if (type == "ARRHENIUS") + { + if (!ParseArrhenius(object)) + return false; + } + else if (type == "EMISSION") + { + if (!ParseEmission(object)) + return false; + } + else if (type == "FIRST_ORDER_LOSS") + { + if (!ParseFirstOrderLoss(object)) + return false; + } + else + { + this->OnError("Unknown key in config file: " + type); + return false; + } + } + return true; + } + + bool ParseChemicalSpecies(const json& object) + { + std::vector required_keys = { "name" }; + std::vector optional_keys = { "absolute tolerance" }; + + for (const auto& key : required_keys) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + + std::string name = object["name"].get(); + + std::string key = "absolute tolerance"; + + if (object.contains(key)) + { + double abs_tol = object[key].get(); + auto species = Species(name, Property(key, "", abs_tol)); + species_.push_back(species); + } + else + { + species_.push_back(Species(name)); + } + + return true; + } + + bool ParseRelativeTolerance(const json& object) + { + // TODO: what is this? + return true; + } + + bool ParseMechanism(const json& object) + { + std::vector required_keys = { "name", "reactions" }; + for (const auto& key : required_keys) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + std::vector objects; + for (const auto& element : object["reactions"]) + { + objects.push_back(element); + } + + return ParseObjectArray(objects); + } + + bool ParsePhotolysis(const json& object) + { + const std::string REACTANTS = "reactants"; + const std::string PRODUCTS = "products"; + const std::string MUSICA_NAME = "MUSICA name"; + const std::string YIELD = "yield"; + + const double DEFAULT_YEILD = 1.0; + + for (const auto& key : { REACTANTS, PRODUCTS, MUSICA_NAME }) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + + // Create process + std::vector reactants; + for (auto& [key, value] : object[REACTANTS].items()) + { + reactants.push_back(micm::Species(key)); + } + + std::vector> products; + for (auto& [key, value] : object[PRODUCTS].items()) + { + if (value.contains(YIELD)) + { + products.push_back(std::make_pair(micm::Species(key), value[YIELD])); + } + else + { + products.push_back(std::make_pair(micm::Species(key), DEFAULT_YEILD)); + } + } + + std::shared_ptr rate_ptr = + std::make_shared(object[MUSICA_NAME].get()); + + processes_.push_back(micm::Process(reactants, products, rate_ptr, phase_)); + + return true; + } + + bool ParseArrhenius(const json& object) + { + const std::string REACTANTS = "reactants"; + const std::string PRODUCTS = "products"; + const std::string YIELD = "yield"; + + const double DEFAULT_YEILD = 1.0; + + // Check required json objects exist + for (const auto& key : { REACTANTS, PRODUCTS }) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + + // Create process + std::vector reactants; + for (auto& [key, value] : object[REACTANTS].items()) + { + reactants.push_back(micm::Species(key)); + } + + std::vector> products; + for (auto& [key, value] : object[PRODUCTS].items()) + { + if (value.contains(YIELD)) + { + products.push_back(std::make_pair(micm::Species(key), value[YIELD])); + } + else + { + products.push_back(std::make_pair(micm::Species(key), DEFAULT_YEILD)); + } + } + + micm::ArrheniusRateConstantParameters parameters; + if (object.contains("A")) + { + parameters.A_ = object["A"].get(); + } + if (object.contains("B")) + { + parameters.B_ = object["B"].get(); + } + if (object.contains("C")) + { + parameters.C_ = object["C"].get(); + } + if (object.contains("D")) + { + parameters.D_ = object["D"].get(); + } + if (object.contains("E")) + { + parameters.E_ = object["E"].get(); + } + + std::shared_ptr rate_ptr = + std::make_shared(micm::ArrheniusRateConstantParameters(parameters)); + + processes_.push_back(micm::Process(reactants, products, rate_ptr, phase_)); + + return true; + } + + bool ParseEmission(const json& object) + { + std::vector required_keys = { "species" }; + std::vector optional_keys = { "MUSICA name" }; + for (const auto& key : required_keys) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + + std::string name = object["species"].get(); + + emissions_.push_back(Species(name)); + + return true; + } + + bool ParseFirstOrderLoss(const json& object) + { + std::vector required_keys = { "species" }; + std::vector optional_keys = { "MUSICA name" }; + for (const auto& key : required_keys) + { + if (!ValidateJsonWithKey(object, key)) + return false; + } + + std::string name = object["species"].get(); + + first_order_loss_.push_back(Species(name)); + + return true; + } + }; + + template class ConfigTypePolicy = JsonReaderPolicy, template class ErrorPolicy = NoThrowPolicy> + class SolverConfig : public ConfigTypePolicy>> + { + public: + std::variant Configure(const std::filesystem::path& path) + { + return this->ReadAndParse(path); + } + }; + +} // namespace micm From 6ea6ab7dae2927a320e68d7d86994b3af3c68c52 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Wed, 7 Jun 2023 21:17:30 -0600 Subject: [PATCH 02/21] update rate constant and its derived classes --- .../micm/process/arrhenius_rate_constant.hpp | 8 ++++++-- .../micm/process/photolysis_rate_constant.hpp | 4 ++-- include/micm/process/process.hpp | 19 +++++++++++++------ include/micm/process/rate_constant.hpp | 8 ++------ include/micm/process/troe_rate_constant.hpp | 10 +++++++--- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/include/micm/process/arrhenius_rate_constant.hpp b/include/micm/process/arrhenius_rate_constant.hpp index e00f5fd26..eef61a4fe 100644 --- a/include/micm/process/arrhenius_rate_constant.hpp +++ b/include/micm/process/arrhenius_rate_constant.hpp @@ -44,10 +44,14 @@ namespace micm /// @brief An explicit constructor where each term can be set. Set B and E to zero to get the common form of the /// Arrhenius equation /// @param parameters A set of arrhenius rate constants - ArrheniusRateConstant(ArrheniusRateConstantParameters parameters); + ArrheniusRateConstant(const ArrheniusRateConstantParameters& parameters); /// @brief Deep copy std::unique_ptr clone() const override; + + /// @brief Returns the number of parameters + /// @return Number of custom rate constant parameters + std::size_t SizeCustomParameters() const override { return 5; } // TODO: jiwon 6/7 - is this right? 5 = A,B,C,D,E /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system @@ -63,7 +67,7 @@ namespace micm { } - inline ArrheniusRateConstant::ArrheniusRateConstant(ArrheniusRateConstantParameters parameters) + inline ArrheniusRateConstant::ArrheniusRateConstant(const ArrheniusRateConstantParameters& parameters) : parameters_(parameters) { } diff --git a/include/micm/process/photolysis_rate_constant.hpp b/include/micm/process/photolysis_rate_constant.hpp index 0d36df790..217de06ac 100644 --- a/include/micm/process/photolysis_rate_constant.hpp +++ b/include/micm/process/photolysis_rate_constant.hpp @@ -25,7 +25,7 @@ namespace micm /// @brief /// @param name A name for this reaction - PhotolysisRateConstant(const std::string name); + PhotolysisRateConstant(const std::string& name); /// @brief Deep copy std::unique_ptr clone() const override; @@ -50,7 +50,7 @@ namespace micm { } - inline PhotolysisRateConstant::PhotolysisRateConstant(const std::string name) + inline PhotolysisRateConstant::PhotolysisRateConstant(const std::string& name) : name_(name) { } diff --git a/include/micm/process/process.hpp b/include/micm/process/process.hpp index 0cf2b9df9..2f53d5fd8 100644 --- a/include/micm/process/process.hpp +++ b/include/micm/process/process.hpp @@ -21,14 +21,12 @@ namespace micm return Yield(species, yield); }; - class ProcessBuilder; - struct Process { - const std::vector reactants_; - const std::vector products_; - const std::unique_ptr rate_constant_; - const Phase phase_; + std::vector reactants_; + std::vector products_; + std::shared_ptr rate_constant_; + Phase phase_; /// @brief Update the solver state rate constants /// @param processes The set of processes being solved @@ -39,6 +37,15 @@ namespace micm static ProcessBuilder create(); Process(ProcessBuilder& builder); Process(const Process& other); + + + Process(const std::vector& reactants, const std::vector& products, std::shared_ptr rate_constant, const Phase& phase) + : reactants_(reactants), + products_(products), + rate_constant_(rate_constant), // TODO: jiwon 6/7 - need to be ptr, shared ptr okay? + phase_(phase) + { + } }; class ProcessBuilder diff --git a/include/micm/process/rate_constant.hpp b/include/micm/process/rate_constant.hpp index 1d3bf69ae..95306ca1a 100644 --- a/include/micm/process/rate_constant.hpp +++ b/include/micm/process/rate_constant.hpp @@ -27,7 +27,8 @@ namespace micm virtual std::unique_ptr clone() const = 0; /// @brief Returns the number of doubles needed to hold user-defined rate constant parameters /// @return Number of user-defined rate constant parameters - virtual std::size_t SizeCustomParameters() const; + virtual std::size_t SizeCustomParameters() 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 @@ -40,9 +41,4 @@ namespace micm private: }; - inline std::size_t RateConstant::SizeCustomParameters() const - { - return 0; - } - } // namespace micm \ No newline at end of file diff --git a/include/micm/process/troe_rate_constant.hpp b/include/micm/process/troe_rate_constant.hpp index fba14dbb9..edce23b32 100644 --- a/include/micm/process/troe_rate_constant.hpp +++ b/include/micm/process/troe_rate_constant.hpp @@ -47,15 +47,19 @@ namespace micm /// @param parameters A set of troe rate constants TroeRateConstant(TroeRateConstantParameters parameters); + /// @brief Deep copy + std::unique_ptr clone() const override; + + /// @brief Returns the number of parameters + /// @return Number of custom rate constant parameters + virtual std::size_t SizeCustomParameters() const override { return 8; } // TODO: jiwon 6/7 - should we make this function photolysis specific? (non virtual) + /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system /// @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 Deep copy - std::unique_ptr clone() const override; - /// @brief Calculate the rate constant /// @param temperature Temperature in [K] /// @param air_number_density Number density in [# cm-3] From f21cb5ebf6814f6cb175463fefc1498a2cf8d080 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Thu, 8 Jun 2023 15:01:01 -0600 Subject: [PATCH 03/21] fixed syntax error in RateConstant and its subclasses --- .../micm/process/arrhenius_rate_constant.hpp | 15 +++++-------- .../micm/process/photolysis_rate_constant.hpp | 14 +++++++----- include/micm/process/rate_constant.hpp | 17 +++++++------- include/micm/process/troe_rate_constant.hpp | 22 +++++++++++-------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/include/micm/process/arrhenius_rate_constant.hpp b/include/micm/process/arrhenius_rate_constant.hpp index eef61a4fe..df9f612ef 100644 --- a/include/micm/process/arrhenius_rate_constant.hpp +++ b/include/micm/process/arrhenius_rate_constant.hpp @@ -9,9 +9,6 @@ namespace micm { - - class System; - struct ArrheniusRateConstantParameters { /// @brief Pre-exponential factor, (cm−3)^(−(𝑛−1))s−1 @@ -48,16 +45,13 @@ namespace micm /// @brief Deep copy std::unique_ptr clone() const override; - - /// @brief Returns the number of parameters - /// @return Number of custom rate constant parameters - std::size_t SizeCustomParameters() const override { return 5; } // TODO: jiwon 6/7 - is this right? 5 = A,B,C,D,E /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system /// @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; + double calculate(const Conditions& conditions, const std::vector::const_iterator& custom_parameters) + const override; double calculate(const double& temperature, const double& pressure) const; }; @@ -77,8 +71,9 @@ namespace micm return std::unique_ptr{ new ArrheniusRateConstant{ *this } }; } - inline double ArrheniusRateConstant::calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) - const + inline double ArrheniusRateConstant::calculate( + const Conditions& conditions, + const std::vector::const_iterator& custom_parameters) const { return calculate(conditions.temperature_, conditions.pressure_); } diff --git a/include/micm/process/photolysis_rate_constant.hpp b/include/micm/process/photolysis_rate_constant.hpp index 217de06ac..399c8bf66 100644 --- a/include/micm/process/photolysis_rate_constant.hpp +++ b/include/micm/process/photolysis_rate_constant.hpp @@ -17,7 +17,7 @@ namespace micm class PhotolysisRateConstant : public RateConstant { public: - const std::string name_; + std::string name_; public: /// @brief Default constructor. @@ -36,13 +36,14 @@ namespace micm /// The single editable parameter is the unscaled rate constant for /// the photolysis reaction /// @return Number of custom rate constant parameters - std::size_t SizeCustomParameters() const override; + std::size_t SizeCustomParameters() override; /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system /// @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; + double calculate(const Conditions& conditions, const std::vector::const_iterator& custom_parameters) + const override; }; inline PhotolysisRateConstant::PhotolysisRateConstant() @@ -60,13 +61,14 @@ namespace micm return std::unique_ptr{ new PhotolysisRateConstant{ *this } }; } - inline double PhotolysisRateConstant::calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) - const + inline double PhotolysisRateConstant::calculate( + const Conditions& conditions, + const std::vector::const_iterator& custom_parameters) const { return (double)*custom_parameters; } - inline std::size_t PhotolysisRateConstant::SizeCustomParameters() const + inline std::size_t PhotolysisRateConstant::SizeCustomParameters() { return 1; } diff --git a/include/micm/process/rate_constant.hpp b/include/micm/process/rate_constant.hpp index 95306ca1a..b37778812 100644 --- a/include/micm/process/rate_constant.hpp +++ b/include/micm/process/rate_constant.hpp @@ -11,9 +11,6 @@ namespace micm { - - class System; - /** * @brief A base class for any type of rate constant * @@ -27,18 +24,20 @@ namespace micm virtual std::unique_ptr clone() const = 0; /// @brief Returns the number of doubles needed to hold user-defined rate constant parameters /// @return Number of user-defined rate constant parameters - virtual std::size_t SizeCustomParameters() const { return 0; } - + virtual std::size_t SizeCustomParameters() + { + 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, std::vector::const_iterator custom_parameters) const + virtual double calculate(const Conditions& conditions, const std::vector::const_iterator& custom_parameters) + const { return 0; - }; - - private: + } }; } // namespace micm \ No newline at end of file diff --git a/include/micm/process/troe_rate_constant.hpp b/include/micm/process/troe_rate_constant.hpp index edce23b32..70c230818 100644 --- a/include/micm/process/troe_rate_constant.hpp +++ b/include/micm/process/troe_rate_constant.hpp @@ -40,25 +40,22 @@ namespace micm const TroeRateConstantParameters parameters_; public: - /// @brief Default constructor is not allowed - TroeRateConstant() = delete; + /// @brief Default constructor. + TroeRateConstant(); /// @brief An explicit constructor /// @param parameters A set of troe rate constants - TroeRateConstant(TroeRateConstantParameters parameters); + TroeRateConstant(const TroeRateConstantParameters& parameters); /// @brief Deep copy std::unique_ptr clone() const override; - /// @brief Returns the number of parameters - /// @return Number of custom rate constant parameters - virtual std::size_t SizeCustomParameters() const override { return 8; } // TODO: jiwon 6/7 - should we make this function photolysis specific? (non virtual) - /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system /// @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; + double calculate(const Conditions& conditions, const std::vector::const_iterator& custom_parameters) + const override; /// @brief Calculate the rate constant /// @param temperature Temperature in [K] @@ -67,6 +64,11 @@ namespace micm double calculate(const double& temperature, const double& air_number_density) const; }; + inline TroeRateConstant::TroeRateConstant() + : parameters_() + { + } + inline TroeRateConstant::TroeRateConstant(TroeRateConstantParameters parameters) : parameters_(parameters) { @@ -77,7 +79,9 @@ namespace micm return std::unique_ptr{ new TroeRateConstant{ *this } }; } - inline double TroeRateConstant::calculate(const Conditions& conditions, std::vector::const_iterator custom_parameters) const + inline double TroeRateConstant::calculate( + const Conditions& conditions, + const std::vector::const_iterator& custom_parameters) const { return calculate(conditions.temperature_, conditions.air_density_); } From 02a1344808bce9d3b8091f6177fdcb3cff8c2316 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Thu, 8 Jun 2023 15:21:42 -0600 Subject: [PATCH 04/21] delete external rate constant --- .../micm/process/external_rate_constant.hpp | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 include/micm/process/external_rate_constant.hpp diff --git a/include/micm/process/external_rate_constant.hpp b/include/micm/process/external_rate_constant.hpp deleted file mode 100644 index dd3681618..000000000 --- a/include/micm/process/external_rate_constant.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2023 National Center for Atmospheric Research, - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#include - -namespace micm -{ - - /** - * @brief A rate constant from an external model - * - */ - class ExternalRateConstant : public RateConstant - { - public: - /// @brief The rate - const double rate_; - /// @brief The condition this rate applies to - const Condition condition_; - - public: - /// @brief Default constructor - ExternalRateConstant(); - - /// @brief Calculate a reaction rate - /// @param system A defined system - /// @return A reaction rate - double calculate(const System& system) override; - }; - - inline ExternalRateConstant::ExternalRateConstant() - : rate_(), - condition_("", "") - { - } - - inline double ExternalRateConstant::calculate(const System& system) - { - return 0.0; - } - -} // namespace micm \ No newline at end of file From 02a8d5e7db998afc5eee7ab58c3cfc0d8627fbc6 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Thu, 8 Jun 2023 18:32:25 -0600 Subject: [PATCH 05/21] added set header in solver class, fixed bugs in rate constant subclasses, update chapman test using config --- include/micm/configure/solver_config.hpp | 17 +++++---- .../micm/process/arrhenius_rate_constant.hpp | 2 +- include/micm/process/process.hpp | 2 ++ include/micm/process/process_set.hpp | 1 + include/micm/process/troe_rate_constant.hpp | 2 +- include/micm/solver/rosenbrock.hpp | 27 ++++++++++++-- include/micm/system/phase.hpp | 18 +++++----- include/micm/util/sparse_matrix.hpp | 1 + test/integration/chapman.cpp | 36 ++++++++++++++++++- 9 files changed, 85 insertions(+), 21 deletions(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index 90829d9b8..a22b4f27c 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -6,24 +6,27 @@ #pragma once +#define USE_JSON + #include #include #include #include -#include #include #include #include #include #include #include -#include + #include -#ifdef USE_JSON -# include -#endif +// #ifdef USE_JSON +// #include +// using json = nlohmann::json; +// #endif +#include using json = nlohmann::json; namespace micm @@ -85,6 +88,8 @@ namespace micm template class JsonReaderPolicy : public ErrorPolicy { + // using json = nlohmann::json; + private: std::vector species_; std::vector emissions_; @@ -190,7 +195,7 @@ namespace micm } } - micm::SystemParameters sysParams = { phase_, std::vector() }; // TODO: jiwon 6/6 - second param + micm::SystemParameters sysParams = { phase_, std::unordered_map() }; // TODO: jiwon 6/6 - second param return micm::SolverParameters{ micm::System(sysParams), processes_ }; } diff --git a/include/micm/process/arrhenius_rate_constant.hpp b/include/micm/process/arrhenius_rate_constant.hpp index df9f612ef..d62b52501 100644 --- a/include/micm/process/arrhenius_rate_constant.hpp +++ b/include/micm/process/arrhenius_rate_constant.hpp @@ -35,7 +35,7 @@ namespace micm const ArrheniusRateConstantParameters parameters_; public: - /// @brief Default constructor. All terms will be zero + /// @brief Default constructor. ArrheniusRateConstant(); /// @brief An explicit constructor where each term can be set. Set B and E to zero to get the common form of the diff --git a/include/micm/process/process.hpp b/include/micm/process/process.hpp index 2f53d5fd8..a579951ac 100644 --- a/include/micm/process/process.hpp +++ b/include/micm/process/process.hpp @@ -21,6 +21,8 @@ namespace micm return Yield(species, yield); }; + class ProcessBuilder; + struct Process { std::vector reactants_; diff --git a/include/micm/process/process_set.hpp b/include/micm/process/process_set.hpp index d677e6b6b..5726910d1 100644 --- a/include/micm/process/process_set.hpp +++ b/include/micm/process/process_set.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace micm { diff --git a/include/micm/process/troe_rate_constant.hpp b/include/micm/process/troe_rate_constant.hpp index 70c230818..ddef02d2f 100644 --- a/include/micm/process/troe_rate_constant.hpp +++ b/include/micm/process/troe_rate_constant.hpp @@ -69,7 +69,7 @@ namespace micm { } - inline TroeRateConstant::TroeRateConstant(TroeRateConstantParameters parameters) + inline TroeRateConstant::TroeRateConstant(const TroeRateConstantParameters& parameters) : parameters_(parameters) { } diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index a71f5827f..ac702dd54 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -93,7 +93,8 @@ namespace micm /// @brief Builds a Rosenbrock solver for the given system, processes, and solver parameters /// @param system The chemical system to create the solver for /// @param processes The collection of chemical processes that will be applied during solving - RosenbrockSolver(const System& system, std::vector&& processes, const RosenbrockSolverParameters parameters); + // RosenbrockSolver(const System& system, std::vector&& processes, const RosenbrockSolverParameters parameters); // TODO: jiwon - 6/7 original + RosenbrockSolver(const System& system, const std::vector& processes, const RosenbrockSolverParameters parameters); virtual ~RosenbrockSolver(); @@ -207,12 +208,32 @@ namespace micm three_stage_rosenbrock(); } + // original + // inline RosenbrockSolver::RosenbrockSolver( + // const System& system, + // std::vector&& processes, + // const RosenbrockSolverParameters parameters) + // : system_(system), + // processes_(std::move(processes)), + // parameters_(parameters), + // process_set_(processes_, GetState()), + // stats_(), + // jacobian_() + // { + // auto builder = SparseMatrix::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); + // jacobian_ = builder; + // process_set_.SetJacobianFlatIds(jacobian_); + + // TODO - jiwon 6/8 inline RosenbrockSolver::RosenbrockSolver( const System& system, - std::vector&& processes, + const std::vector& processes, const RosenbrockSolverParameters parameters) : system_(system), - processes_(std::move(processes)), + processes_(processes), parameters_(parameters), process_set_(processes_, GetState()), stats_(), diff --git a/include/micm/system/phase.hpp b/include/micm/system/phase.hpp index 6a79adadf..e54636777 100644 --- a/include/micm/system/phase.hpp +++ b/include/micm/system/phase.hpp @@ -19,24 +19,24 @@ namespace micm { public: /// @brief The list of species - const std::vector species_; + std::vector species_; public: - Phase(); - Phase operator=(const Phase& other); + /// @brief Default constructor + Phase() + : species_() + { + } /// @brief Create a phase with a set of species /// @param species A unique list of species - Phase(const std::vector species) + Phase(const std::vector& species) : species_(species) { } - }; - Phase::Phase() - : species_() - { - } + Phase operator=(const Phase& other); + }; Phase Phase::operator=(const Phase& other) { diff --git a/include/micm/util/sparse_matrix.hpp b/include/micm/util/sparse_matrix.hpp index a1781df6e..62d83595b 100644 --- a/include/micm/util/sparse_matrix.hpp +++ b/include/micm/util/sparse_matrix.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace micm { diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index 4a4378b5d..53b73526d 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -1,5 +1,8 @@ +#pragma once + #include +#include #include #include #include @@ -91,4 +94,35 @@ TEST(ChapmanIntegration, CanBuildChapmanSystem) auto result = solver.Solve(t, t + 0.5, state); // output state } -} \ No newline at end of file +} + +TEST(ChapmanIntegrationWithConfigFile, ReadConfigAndBuildChapmanSystem) +{ + // Configure params for solver + micm::SolverConfig solverConfig{}; // Throw policy + std::variant configs = + solverConfig.Configure("./test/unit/unit_configs/chapman/config.json"); + + micm::SolverParameters& solver_params = + std::get(configs); // return type must be + + micm::RosenbrockSolver solver{ solver_params.system_, + solver_params.processes_, + micm::RosenbrockSolverParameters{} }; // TODO: jiwon 6/8 - talk about solver param + + micm::State 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; + std::vector photo_rates{ 0.1, 0.2, 0.3 }; + state.custom_rate_parameters_[0] = photo_rates; + state.conditions_[0].temperature_ = 2; + state.conditions_[0].pressure_ = 3; + + for (double t{}; t < 100; ++t) + { + state.custom_rate_parameters_[0] = photo_rates; + auto result = solver.Solve(t, t + 0.5, state); + // output state + } +} From 0307cbe6e6f3fa60dedf15d720e4f6e942044a32 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Mon, 12 Jun 2023 15:35:49 -0600 Subject: [PATCH 06/21] add a missing header --- include/micm/solver/state.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/micm/solver/state.hpp b/include/micm/solver/state.hpp index 08e76823b..48af8bd3f 100644 --- a/include/micm/solver/state.hpp +++ b/include/micm/solver/state.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace micm { From b2c324fb810583ae31efc4870b0575c3319dee90 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Mon, 12 Jun 2023 21:00:34 -0600 Subject: [PATCH 07/21] added unit tests --- include/micm/configure/solver_config.hpp | 52 +++++++++++----------- include/micm/process/process.hpp | 7 ++- include/micm/system/system.hpp | 1 + test/unit/configure/CMakeLists.txt | 2 +- test/unit/configure/test_solver_config.cpp | 44 ++++++++++++++++++ 5 files changed, 75 insertions(+), 31 deletions(-) create mode 100644 test/unit/configure/test_solver_config.cpp diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index a22b4f27c..3dea9857b 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -6,8 +6,6 @@ #pragma once -#define USE_JSON - #include #include #include @@ -18,13 +16,12 @@ #include #include #include - #include -// #ifdef USE_JSON -// #include -// using json = nlohmann::json; -// #endif +#ifdef USE_JSON +# include +using json = nlohmann::json; +#endif #include using json = nlohmann::json; @@ -69,7 +66,7 @@ namespace micm } }; - /// Solover parameters + // Solover parameters struct SolverParameters { micm::System system_; @@ -85,21 +82,22 @@ namespace micm KeyNotFound, }; + // JSON Configure paser template class JsonReaderPolicy : public ErrorPolicy { - // using json = nlohmann::json; - - private: + public: + // Set to "public" for "NoThrowPolcy" std::vector species_; std::vector emissions_; std::vector first_order_loss_; std::vector processes_; - micm::Phase phase_; + micm::Phase gas_phase_; + std::unordered_map phases_; - public: // Constants - static const inline std::string SPECIES_CONFIG = "species.json"; // TODO:jiwon 6/6 - instead of searching + static const inline std::string SPECIES_CONFIG = + "species.json"; // TODO:jiwon 6/6 - instead of searching, pass the configure path static const inline std::string REACTIONS_CONFIG = "mechanism.json"; // TODO:jiwon 6/6 static const inline std::string CAMP_FILES = "camp-files"; @@ -111,10 +109,10 @@ namespace micm /// @brief read and parse JSON objects /// @param - /// @return SolverParameters if success, else ConfigErrorCode + /// @return SolverParameters if parsing is success, else returns ConfigErrorCode std::variant ReadAndParse(const std::filesystem::path& path) { - // Check whether file to path exists + // Check whether file exists if (!std::filesystem::exists(path)) { std::string err_msg = "Configuration file at path " + path.string() + " does not exist\n"; @@ -130,7 +128,7 @@ namespace micm return micm::ConfigErrorCode::KeyNotFound; } - // Check whether the listed files exist, and determine the sequence to read files. + // Check whether the listed files exist and determine the sequence to read files. std::string species_file; std::vector other_files; bool found_species_file = false; @@ -195,12 +193,14 @@ namespace micm } } - micm::SystemParameters sysParams = { phase_, std::unordered_map() }; // TODO: jiwon 6/6 - second param + micm::SystemParameters sysParams = { gas_phase_, phases_ }; return micm::SolverParameters{ micm::System(sysParams), processes_ }; } - // create species and phase + /// @brief Create 'Species' and 'Phase' + /// @param path to 'Species' file + /// @return True at success bool ConfigureSpecies(const std::string& file) { json file_data = json::parse(std::ifstream(file)); @@ -231,7 +231,7 @@ namespace micm } } // After creating Species, create Phase - phase_.species_ = species_; + gas_phase_.species_ = species_; return true; } @@ -377,10 +377,10 @@ namespace micm } } - std::shared_ptr rate_ptr = - std::make_shared(object[MUSICA_NAME].get()); + std::unique_ptr rate_ptr = + std::make_unique(object[MUSICA_NAME].get()); - processes_.push_back(micm::Process(reactants, products, rate_ptr, phase_)); + processes_.push_back(micm::Process(reactants, products, std::move(rate_ptr), gas_phase_)); return true; } @@ -442,10 +442,10 @@ namespace micm parameters.E_ = object["E"].get(); } - std::shared_ptr rate_ptr = - std::make_shared(micm::ArrheniusRateConstantParameters(parameters)); + std::unique_ptr rate_ptr = + std::make_unique(micm::ArrheniusRateConstantParameters(parameters)); - processes_.push_back(micm::Process(reactants, products, rate_ptr, phase_)); + processes_.push_back(micm::Process(reactants, products, std::move(rate_ptr), gas_phase_)); return true; } diff --git a/include/micm/process/process.hpp b/include/micm/process/process.hpp index a579951ac..ce2fcc13a 100644 --- a/include/micm/process/process.hpp +++ b/include/micm/process/process.hpp @@ -27,7 +27,7 @@ namespace micm { std::vector reactants_; std::vector products_; - std::shared_ptr rate_constant_; + std::unique_ptr rate_constant_; Phase phase_; /// @brief Update the solver state rate constants @@ -39,12 +39,11 @@ namespace micm static ProcessBuilder create(); Process(ProcessBuilder& builder); Process(const Process& other); - - Process(const std::vector& reactants, const std::vector& products, std::shared_ptr rate_constant, const Phase& phase) + Process(const std::vector& reactants, const std::vector& products, std::unique_ptr rate_constant, const Phase& phase) : reactants_(reactants), products_(products), - rate_constant_(rate_constant), // TODO: jiwon 6/7 - need to be ptr, shared ptr okay? + rate_constant_(std::move(rate_constant)), phase_(phase) { } diff --git a/include/micm/system/system.hpp b/include/micm/system/system.hpp index f8b414278..9a3d82d72 100644 --- a/include/micm/system/system.hpp +++ b/include/micm/system/system.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace micm { diff --git a/test/unit/configure/CMakeLists.txt b/test/unit/configure/CMakeLists.txt index 86fc68e93..b26e7b326 100644 --- a/test/unit/configure/CMakeLists.txt +++ b/test/unit/configure/CMakeLists.txt @@ -6,4 +6,4 @@ include(test_util) ################################################################################ # Tests -#create_standard_test(NAME system_builder SOURCES test_system_builder.cpp) +create_standard_test(NAME solver_config SOURCES test_solver_config.cpp) diff --git a/test/unit/configure/test_solver_config.cpp b/test/unit/configure/test_solver_config.cpp new file mode 100644 index 000000000..768c23b93 --- /dev/null +++ b/test/unit/configure/test_solver_config.cpp @@ -0,0 +1,44 @@ +#ifdef USE_JSON +# include +#endif + +#include + +#ifdef USE_JSON +TEST(SolverConfig, DetectsInvalidConfigFileAndThrow) +{ + micm::SolverConfig solverConfig{}; + EXPECT_ANY_THROW(solverConfig.Configure("not_a_config_file.json")); +} + +TEST(SolverConfig, DetectsInvalidConfigFileAndNoThrowDoesntThrow) +{ + micm::SolverConfig solverConfig{}; + EXPECT_NO_THROW(solverConfig.Configure("not_a_config_file.json")); + + std::variant configs = solverConfig.Configure("not_a_config_file.json"); + EXPECT_EQ(std::get(configs), micm::ConfigErrorCode::FileNotFound); +} + +TEST(SolverConfig, ReadAndParse) +{ + micm::SolverConfig solverConfig{}; + std::variant configs = solverConfig.Configure("./unit_configs/chapman/config.json"); + auto* solver_params_ptr = std::get_if(&configs); + + EXPECT_TRUE(solver_params_ptr!= nullptr); + + micm::SolverParameters& solver_params = *solver_params_ptr; + + EXPECT_EQ(solver_params.system_.gas_phase_.species_.size(), 9); + EXPECT_EQ(solver_params.processes_.size(), 7); + + int num_reactants_in_each_process[] = {1, 1, 1, 2, 2, 2, 3}; + short idx = 0; + for (const auto& p : solver_params.processes_) + { + EXPECT_EQ(p.reactants_.size(), num_reactants_in_each_process[idx]); + idx++; + } +} +#endif \ No newline at end of file From 725c7c9b8b3253664b6d086fcadebaf1ce4c50ed Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Mon, 12 Jun 2023 21:08:59 -0600 Subject: [PATCH 08/21] comment out integration test --- test/integration/chapman.cpp | 61 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index 53b73526d..acfa3bdbc 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -96,33 +96,34 @@ TEST(ChapmanIntegration, CanBuildChapmanSystem) } } -TEST(ChapmanIntegrationWithConfigFile, ReadConfigAndBuildChapmanSystem) -{ - // Configure params for solver - micm::SolverConfig solverConfig{}; // Throw policy - std::variant configs = - solverConfig.Configure("./test/unit/unit_configs/chapman/config.json"); - - micm::SolverParameters& solver_params = - std::get(configs); // return type must be - - micm::RosenbrockSolver solver{ solver_params.system_, - solver_params.processes_, - micm::RosenbrockSolverParameters{} }; // TODO: jiwon 6/8 - talk about solver param - - micm::State 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; - std::vector photo_rates{ 0.1, 0.2, 0.3 }; - state.custom_rate_parameters_[0] = photo_rates; - state.conditions_[0].temperature_ = 2; - state.conditions_[0].pressure_ = 3; - - for (double t{}; t < 100; ++t) - { - state.custom_rate_parameters_[0] = photo_rates; - auto result = solver.Solve(t, t + 0.5, state); - // output state - } -} +// TEST(ChapmanIntegrationWithConfigFile, ReadConfigAndBuildChapmanSystem) +// { +// // Configure params for solver +// micm::SolverConfig solverConfig{}; // Throw policy +// std::variant configs = +// solverConfig.Configure("./test/unit/unit_configs/chapman/config.json"); + +// micm::SolverParameters solver_params = +// std::get(configs); // return type must be + +// std::vector p = solver_params.processes_; +// micm::RosenbrockSolver solver{ solver_params.system_, +// p, +// micm::RosenbrockSolverParameters{} }; // TODO: jiwon 6/8 - talk about solver param + +// micm::State 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; +// std::vector photo_rates{ 0.1, 0.2, 0.3 }; +// state.custom_rate_parameters_[0] = photo_rates; +// state.conditions_[0].temperature_ = 2; +// state.conditions_[0].pressure_ = 3; + +// for (double t{}; t < 100; ++t) +// { +// state.custom_rate_parameters_[0] = photo_rates; +// auto result = solver.Solve(t, t + 0.5, state); +// // output state +// } +// } From aafc931c55635f8c2ed367e1286f0b672d1715a7 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Mon, 12 Jun 2023 21:17:26 -0600 Subject: [PATCH 09/21] fix macro --- include/micm/configure/solver_config.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index 3dea9857b..469ccd395 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -19,12 +19,9 @@ #include #ifdef USE_JSON -# include -using json = nlohmann::json; -#endif - #include using json = nlohmann::json; +#endif namespace micm { From f63ea8c1518cf4c9d37b165fd891ce176aee124d Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 13 Jun 2023 14:46:15 -0600 Subject: [PATCH 10/21] added more unit tests for solver configure --- CMakeLists.txt | 2 +- test/unit/configure/test_solver_config.cpp | 101 +++++++++++++++------ 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c42fa7955..b5583e954 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ option(ENABLE_MPI "Enable MPI parallel support" OFF) option(ENABLE_OPENMP "Enable OpenMP support" OFF) option(ENABLE_COVERAGE "Enable code coverage output" OFF) option(ENABLE_MEMCHECK "Enable memory checking in tests" OFF) -option(ENABLE_JSON "Enable json configureation file reading" OFF) +option(ENABLE_JSON "Enable json configureation file reading" ON) option(ENABLE_REGESSION_TESTS "Enable regression tests against the old pre-processed version of micm" ON) option(BUILD_DOCS "Build the documentation" OFF) diff --git a/test/unit/configure/test_solver_config.cpp b/test/unit/configure/test_solver_config.cpp index 768c23b93..52198430a 100644 --- a/test/unit/configure/test_solver_config.cpp +++ b/test/unit/configure/test_solver_config.cpp @@ -1,44 +1,87 @@ -#ifdef USE_JSON -# include -#endif - #include #ifdef USE_JSON +# include + TEST(SolverConfig, DetectsInvalidConfigFileAndThrow) { - micm::SolverConfig solverConfig{}; - EXPECT_ANY_THROW(solverConfig.Configure("not_a_config_file.json")); + micm::SolverConfig solverConfig{}; + EXPECT_ANY_THROW(solverConfig.Configure("not_a_config_file.json")); } TEST(SolverConfig, DetectsInvalidConfigFileAndNoThrowDoesntThrow) { - micm::SolverConfig solverConfig{}; - EXPECT_NO_THROW(solverConfig.Configure("not_a_config_file.json")); + micm::SolverConfig solverConfig{}; + EXPECT_NO_THROW(solverConfig.Configure("not_a_config_file.json")); - std::variant configs = solverConfig.Configure("not_a_config_file.json"); - EXPECT_EQ(std::get(configs), micm::ConfigErrorCode::FileNotFound); + std::variant configs = solverConfig.Configure("not_a_config_file.json"); + EXPECT_EQ(std::get(configs), micm::ConfigErrorCode::FileNotFound); } -TEST(SolverConfig, ReadAndParse) +TEST(SolverConfig, ReadAndParseSystem) { - micm::SolverConfig solverConfig{}; - std::variant configs = solverConfig.Configure("./unit_configs/chapman/config.json"); - auto* solver_params_ptr = std::get_if(&configs); - - EXPECT_TRUE(solver_params_ptr!= nullptr); - - micm::SolverParameters& solver_params = *solver_params_ptr; - - EXPECT_EQ(solver_params.system_.gas_phase_.species_.size(), 9); - EXPECT_EQ(solver_params.processes_.size(), 7); - - int num_reactants_in_each_process[] = {1, 1, 1, 2, 2, 2, 3}; - short idx = 0; - for (const auto& p : solver_params.processes_) - { - EXPECT_EQ(p.reactants_.size(), num_reactants_in_each_process[idx]); - idx++; - } + micm::SolverConfig solverConfig{}; + std::variant configs = + solverConfig.Configure("./unit_configs/chapman/config.json"); + auto* solver_params_ptr = std::get_if(&configs); + + EXPECT_TRUE(solver_params_ptr != nullptr); + + micm::SolverParameters& solver_params = *solver_params_ptr; + + EXPECT_EQ(solver_params.system_.gas_phase_.species_.size(), 9); + EXPECT_EQ(solver_params.system_.phases_.size(), 0); + + std::vector> species_name_and_num_properties = { + std::make_pair("M", 0), std::make_pair("Ar", 1), std::make_pair("CO2", 1), + std::make_pair("H2O", 1), std::make_pair("N2", 1), std::make_pair("O1D", 1), + std::make_pair("O", 1), std::make_pair("O2", 1), std::make_pair("O3", 1) + }; + + short idx = 0; + for (const auto& s : solver_params.system_.gas_phase_.species_) + { + EXPECT_EQ(s.name_, species_name_and_num_properties[idx].first); + EXPECT_EQ(s.properties_.size(), species_name_and_num_properties[idx].second); + idx++; + } +} + +TEST(SolverConfig, ReadAndParseProcess) +{ + micm::SolverConfig solverConfig{}; + std::variant configs = + solverConfig.Configure("./unit_configs/chapman/config.json"); + auto* solver_params_ptr = std::get_if(&configs); + + EXPECT_TRUE(solver_params_ptr != nullptr); + + micm::SolverParameters& solver_params = *solver_params_ptr; + + int num_processes = 7; + int num_reactants_in_each_process[] = { 1, 1, 1, 2, 2, 2, 3 }; + int num_products_in_each_process[] = { 1, 2, 2, 2, 2, 1, 2 }; + double yield_value_of_first_product_in_each_process[] = { 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0 }; + std::size_t size_custom_parameters_of_rate_constant_in_each_process[] = { 1, 1, 1, 0, 0, 0, 0 }; + int num_phase_in_each_process = 9; + + EXPECT_EQ(solver_params.processes_.size(), num_processes); + + short idx = 0; + for (const auto& p : solver_params.processes_) + { + EXPECT_EQ(p.reactants_.size(), num_reactants_in_each_process[idx]); + EXPECT_EQ(p.products_.size(), num_products_in_each_process[idx]); + EXPECT_EQ(p.products_[0].second, yield_value_of_first_product_in_each_process[idx]); + EXPECT_EQ(p.phase_.species_.size(), num_phase_in_each_process); + idx++; + } + + idx = 0; + std::vector::iterator it; + for (it = solver_params.processes_.begin(); it != solver_params.processes_.end(); it++, idx++) + { + EXPECT_EQ(it->rate_constant_->SizeCustomParameters(), size_custom_parameters_of_rate_constant_in_each_process[idx]); + } } #endif \ No newline at end of file From eadd459733676033d771d2f7813c4f10ab14aa51 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 13 Jun 2023 14:59:07 -0600 Subject: [PATCH 11/21] delete changes --- include/micm/solver/rosenbrock.hpp | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/include/micm/solver/rosenbrock.hpp b/include/micm/solver/rosenbrock.hpp index 06c09143c..8a8981524 100644 --- a/include/micm/solver/rosenbrock.hpp +++ b/include/micm/solver/rosenbrock.hpp @@ -92,8 +92,7 @@ namespace micm /// @brief Builds a Rosenbrock solver for the given system, processes, and solver parameters /// @param system The chemical system to create the solver for /// @param processes The collection of chemical processes that will be applied during solving - // RosenbrockSolver(const System& system, std::vector&& processes, const RosenbrockSolverParameters parameters); // TODO: jiwon - 6/7 original - RosenbrockSolver(const System& system, const std::vector& processes, const RosenbrockSolverParameters parameters); + RosenbrockSolver(const System& system, std::vector&& processes, const RosenbrockSolverParameters parameters); virtual ~RosenbrockSolver(); @@ -207,32 +206,12 @@ namespace micm three_stage_rosenbrock(); } - // original - // inline RosenbrockSolver::RosenbrockSolver( - // const System& system, - // std::vector&& processes, - // const RosenbrockSolverParameters parameters) - // : system_(system), - // processes_(std::move(processes)), - // parameters_(parameters), - // process_set_(processes_, GetState()), - // stats_(), - // jacobian_() - // { - // auto builder = SparseMatrix::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); - // jacobian_ = builder; - // process_set_.SetJacobianFlatIds(jacobian_); - - // TODO - jiwon 6/8 inline RosenbrockSolver::RosenbrockSolver( const System& system, - const std::vector& processes, + std::vector&& processes, const RosenbrockSolverParameters parameters) : system_(system), - processes_(processes), + processes_(std::move(processes)), parameters_(parameters), process_set_(processes_, GetState()), stats_(), From 49d376462bbaa1ecae7ac7e678e6215b9a741244 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 13 Jun 2023 16:16:10 -0600 Subject: [PATCH 12/21] added use Json macro --- include/micm/configure/solver_config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index 469ccd395..4eb38ee3f 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -21,7 +21,6 @@ #ifdef USE_JSON #include using json = nlohmann::json; -#endif namespace micm { @@ -493,3 +492,4 @@ namespace micm }; } // namespace micm +#endif \ No newline at end of file From 5e2b99104d046b41935eee6043a60653ba2640bb Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 13 Jun 2023 16:27:47 -0600 Subject: [PATCH 13/21] auto-formatted, remove duplicate headers --- include/micm/configure/solver_config.hpp | 2 +- include/micm/process/arrhenius_rate_constant.hpp | 2 +- include/micm/process/process_set.hpp | 1 - include/micm/process/troe_rate_constant.hpp | 2 +- include/micm/util/sparse_matrix.hpp | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index 4eb38ee3f..84bf58de2 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -19,7 +19,7 @@ #include #ifdef USE_JSON -#include +# include using json = nlohmann::json; namespace micm diff --git a/include/micm/process/arrhenius_rate_constant.hpp b/include/micm/process/arrhenius_rate_constant.hpp index d62b52501..ed8131a04 100644 --- a/include/micm/process/arrhenius_rate_constant.hpp +++ b/include/micm/process/arrhenius_rate_constant.hpp @@ -35,7 +35,7 @@ namespace micm const ArrheniusRateConstantParameters parameters_; public: - /// @brief Default constructor. + /// @brief Default constructor ArrheniusRateConstant(); /// @brief An explicit constructor where each term can be set. Set B and E to zero to get the common form of the diff --git a/include/micm/process/process_set.hpp b/include/micm/process/process_set.hpp index 5726910d1..d677e6b6b 100644 --- a/include/micm/process/process_set.hpp +++ b/include/micm/process/process_set.hpp @@ -8,7 +8,6 @@ #include #include #include -#include namespace micm { diff --git a/include/micm/process/troe_rate_constant.hpp b/include/micm/process/troe_rate_constant.hpp index ddef02d2f..cf1319889 100644 --- a/include/micm/process/troe_rate_constant.hpp +++ b/include/micm/process/troe_rate_constant.hpp @@ -40,7 +40,7 @@ namespace micm const TroeRateConstantParameters parameters_; public: - /// @brief Default constructor. + /// @brief Default constructor TroeRateConstant(); /// @brief An explicit constructor diff --git a/include/micm/util/sparse_matrix.hpp b/include/micm/util/sparse_matrix.hpp index 9448b6f05..5db9e26d8 100644 --- a/include/micm/util/sparse_matrix.hpp +++ b/include/micm/util/sparse_matrix.hpp @@ -9,7 +9,6 @@ #include #include #include -#include namespace micm { From 460a3e2f140d34823283565637cb70f1fa5b1c48 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Tue, 13 Jun 2023 16:33:54 -0600 Subject: [PATCH 14/21] remove unnecessary preprocessor --- test/integration/chapman.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index b4f29fe5e..6a3090a77 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -1,5 +1,3 @@ -#pragma once - #include #include From da69131ccde0c167d7e072390c1517d76143438c Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Wed, 14 Jun 2023 10:53:29 -0600 Subject: [PATCH 15/21] add subdirectory for config, roll back to the original of chapman test --- include/micm/configure/solver_config.hpp | 6 ++-- test/integration/chapman.cpp | 35 +----------------------- test/unit/CMakeLists.txt | 4 ++- test/unit/configure/CMakeLists.txt | 2 +- 4 files changed, 7 insertions(+), 40 deletions(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index 84bf58de2..eb2297a40 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -16,10 +16,9 @@ #include #include #include +#include #include -#ifdef USE_JSON -# include using json = nlohmann::json; namespace micm @@ -491,5 +490,4 @@ namespace micm } }; -} // namespace micm -#endif \ No newline at end of file +} // namespace micm \ No newline at end of file diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index 6a3090a77..9034900a7 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -1,6 +1,5 @@ #include -#include #include #include #include @@ -92,36 +91,4 @@ TEST(ChapmanIntegration, CanBuildChapmanSystem) auto result = solver.Solve(t, t + 0.5, state); // output state } -} - -// TEST(ChapmanIntegrationWithConfigFile, ReadConfigAndBuildChapmanSystem) -// { -// // Configure params for solver -// micm::SolverConfig solverConfig{}; // Throw policy -// std::variant configs = -// solverConfig.Configure("./test/unit/unit_configs/chapman/config.json"); - -// micm::SolverParameters solver_params = -// std::get(configs); // return type must be - -// std::vector p = solver_params.processes_; -// micm::RosenbrockSolver solver{ solver_params.system_, -// p, -// micm::RosenbrockSolverParameters{} }; // TODO: jiwon 6/8 - talk about solver param - -// micm::State 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; -// std::vector photo_rates{ 0.1, 0.2, 0.3 }; -// state.custom_rate_parameters_[0] = photo_rates; -// state.conditions_[0].temperature_ = 2; -// state.conditions_[0].pressure_ = 3; - -// for (double t{}; t < 100; ++t) -// { -// state.custom_rate_parameters_[0] = photo_rates; -// auto result = solver.Solve(t, t + 0.5, state); -// // output state -// } -// } +} \ No newline at end of file diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b844bc2f4..2f61327bd 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,4 +1,6 @@ -add_subdirectory(configure) +if(ENABLE_JSON) + add_subdirectory(configure) +endif() add_subdirectory(process) add_subdirectory(solver) add_subdirectory(system) diff --git a/test/unit/configure/CMakeLists.txt b/test/unit/configure/CMakeLists.txt index b26e7b326..f8b91a056 100644 --- a/test/unit/configure/CMakeLists.txt +++ b/test/unit/configure/CMakeLists.txt @@ -6,4 +6,4 @@ include(test_util) ################################################################################ # Tests -create_standard_test(NAME solver_config SOURCES test_solver_config.cpp) +create_standard_test(NAME solver_config SOURCES test_solver_config.cpp) \ No newline at end of file From 9b0b9c05d6ce02227cac6f154c315ce995d1027a Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Wed, 14 Jun 2023 11:00:34 -0600 Subject: [PATCH 16/21] delete files that are not used anymore --- include/micm/configure/system_builder.hpp | 319 ------------------ include/micm/process/intraphase_process.hpp | 41 --- .../process/intraphase_process_builder.hpp | 86 ----- test/unit/configure/test_system_builder.cpp | 42 --- 4 files changed, 488 deletions(-) delete mode 100644 include/micm/configure/system_builder.hpp delete mode 100644 include/micm/process/intraphase_process.hpp delete mode 100644 include/micm/process/intraphase_process_builder.hpp delete mode 100644 test/unit/configure/test_system_builder.cpp diff --git a/include/micm/configure/system_builder.hpp b/include/micm/configure/system_builder.hpp deleted file mode 100644 index 33c2d7b8c..000000000 --- a/include/micm/configure/system_builder.hpp +++ /dev/null @@ -1,319 +0,0 @@ -/* Copyright (C) 2023 National Center for Atmospheric Research, - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef USE_JSON -# include -#endif - -namespace micm -{ - - template - class ThrowPolicy - { - class Exception : public std::exception - { - public: - const char* msg_; - - public: - Exception(const char* msg) - : msg_(msg) - { - } - - virtual const char* what() - { - return msg_; - } - }; - - public: - Object OnError(std::string message) - { - throw Exception(message.c_str()); - } - }; - - template - class NoThrowPolicy - { - public: - Object OnError(std::string message) - { - std::cerr << message << std::endl; - return Object(); - } - }; - - template - class JsonReaderPolicy : public ErrorPolicy - { - using json = nlohmann::json; - std::vector species_; - std::vector emissions_; - std::vector first_order_loss_; - std::vector> photolysis_reactions_; - std::vector> arrhenius_reactions_; - - public: - std::unique_ptr ReadAndParse(std::filesystem::path path) - { - species_.clear(); - emissions_.clear(); - first_order_loss_.clear(); - photolysis_reactions_.clear(); - arrhenius_reactions_.clear(); - - if (!std::filesystem::exists(path)) - { - std::string err_msg = "Configuration file at path " + path.string() + " does not exist\n"; - return this->OnError(err_msg); - } - - json data = json::parse(std::ifstream(path)); - - std::string key = "camp-files"; - ValidateJsonWithKey(data, key); - - std::vector files = data[key].get>(); - - key = "camp-data"; - for (const auto& file : files) - { - if (!std::filesystem::exists(path)) - { - std::string err_msg = "Configuration file at path " + path.string() + " does not exist\n"; - return this->OnError(err_msg); - } - json file_data = json::parse(std::ifstream(file)); - ValidateJsonWithKey(file_data, key); - std::vector objects; - for (const auto& element : file_data[key]) - { - objects.push_back(element); - } - - ParseObjectArray(objects); - } - - micm::SystemParameters parameters; - parameters.arrhenius_reactions_ = arrhenius_reactions_; - parameters.photolysis_reactions_ = photolysis_reactions_; - parameters.gas_phase_ = micm::Phase(species_); - - return std::make_unique(micm::System(parameters)); - } - - void ValidateJsonWithKey(const json& object, std::string key) - { - if (!object.contains(key)) - { - this->OnError("Key " + key + " was not found in the config file"); - } - } - - void ParseObjectArray(const std::vector& objects) - { - for (const auto& object : objects) - { - std::string key = "type"; - ValidateJsonWithKey(object, key); - std::string type = object[key].get(); - - if (type == "CHEM_SPEC") - { - ParseChemicalSpecies(object); - } - else if (type == "RELATIVE_TOLERANCE") - { - ParseRelativeTolerance(object); - } - else if (type == "MECHANISM") - { - ParseMechanism(object); - } - else if (type == "PHOTOLYSIS") - { - ParsePhotolysis(object); - } - else if (type == "ARRHENIUS") - { - ParseArrhenius(object); - } - else if (type == "EMISSION") - { - ParseEmission(object); - } - else if (type == "FIRST_ORDER_LOSS") - { - ParseFirstOrderLoss(object); - } - else - { - this->OnError("Unknown key in config file: " + type); - } - } - } - - void ParseChemicalSpecies(const json& object) - { - std::vector required_keys = { "name" }; - std::vector optional_keys = { "absolute tolerance" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::string name = object["name"].get(); - - std::string key = "absolute tolerance"; - - if (object.contains(key)) - { - double abs_tol = object[key].get(); - auto species = Species(name, Property(key, "", abs_tol)); - species_.push_back(species); - } - else - { - species_.push_back(Species(name)); - } - } - - void ParseRelativeTolerance(const json& object) - { - // TODO: what is this? - } - - void ParseMechanism(const json& object) - { - std::vector required_keys = { "name", "reactions" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::vector objects; - for (const auto& element : object["reactions"]) - { - objects.push_back(element); - } - - ParseObjectArray(objects); - } - - void ParsePhotolysis(const json& object) - { - std::vector required_keys = { "reactants", "products", "MUSICA name" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::vector reactants; - for (auto& [key, value] : object["reactants"].items()) - { - reactants.push_back(Species(key)); - } - std::vector products; - for (auto& [key, value] : object["products"].items()) - { - products.push_back(Species(key)); - } - std::string name = object["MUSICA name"].get(); - - using reaction = IntraPhaseProcess; - photolysis_reactions_.push_back(reaction(reactants, products, PhotolysisRateConstant(0, name))); - } - - void ParseArrhenius(const json& object) - { - std::vector required_keys = { "reactants", "products" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::vector reactants; - for (auto& [key, value] : object["reactants"].items()) - { - reactants.push_back(Species(key)); - } - std::vector products; - for (auto& [key, value] : object["products"].items()) - { - products.push_back(Species(key)); - } - - ArrheniusRateConstantParameters parameters; - - if (object.contains("A")) - { - parameters.A_ = object["A"].get(); - } - if (object.contains("B")) - { - parameters.B_ = object["B"].get(); - } - if (object.contains("C")) - { - parameters.C_ = object["C"].get(); - } - if (object.contains("D")) - { - parameters.D_ = object["D"].get(); - } - if (object.contains("E")) - { - parameters.E_ = object["E"].get(); - } - - using reaction = IntraPhaseProcess; - arrhenius_reactions_.push_back(reaction(reactants, products, ArrheniusRateConstant(parameters))); - } - - void ParseEmission(const json& object) - { - std::vector required_keys = { "species" }; - std::vector optional_keys = { "MUSICA name" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::string name = object["species"].get(); - - emissions_.push_back(Species(name)); - } - - void ParseFirstOrderLoss(const json& object) - { - std::vector required_keys = { "species" }; - std::vector optional_keys = { "MUSICA name" }; - for (const auto& key : required_keys) - ValidateJsonWithKey(object, key); - - std::string name = object["species"].get(); - - first_order_loss_.push_back(Species(name)); - } - }; - - template class ConfigTypePolicy = JsonReaderPolicy, template class ErrorPolicy = ThrowPolicy> - class SystemBuilder : public ConfigTypePolicy>> - { - public: - std::unique_ptr Build(std::filesystem::path path) - { - return this->ReadAndParse(path); - } - }; - -} // namespace micm \ No newline at end of file diff --git a/include/micm/process/intraphase_process.hpp b/include/micm/process/intraphase_process.hpp deleted file mode 100644 index 081a4693d..000000000 --- a/include/micm/process/intraphase_process.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2023 National Center for Atmospheric Research, - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#include - -namespace micm -{ - - /** - * @brief An intraphase process - * - */ - template - class IntraPhaseProcess - { - public: - const std::vector reactants_; - const std::vector products_; - const Rate rate_; - - public: - /// @brief - /// @param reactants - /// @param products - /// @param rate - IntraPhaseProcess(std::vector reactants, std::vector products, Rate rate); - }; - - template - inline IntraPhaseProcess::IntraPhaseProcess(std::vector reactants, std::vector products, Rate rate) - : reactants_(reactants), - products_(products), - rate_(rate) - { - } - -} // namespace micm \ No newline at end of file diff --git a/include/micm/process/intraphase_process_builder.hpp b/include/micm/process/intraphase_process_builder.hpp deleted file mode 100644 index d4b354a85..000000000 --- a/include/micm/process/intraphase_process_builder.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2023 National Center for Atmospheric Research, - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#include -#include - -namespace micm -{ - - /** - * @brief Creates any type of intraphase process builder - * - */ - class IntraPhaseProcessBuilder - { - private: - public: - /// @brief Adds an additional phase to the state of the process - /// @param phase A phase - /// @return A reference to this object - IntraPhaseProcessBuilder& For(const Phase& phase); - /// @brief Adds an additional species to the process - /// @param species A species - /// @return A reference to this object - IntraPhaseProcessBuilder& With(const Species& species); - /// @brief Adds a reacting species - /// @param reactant A Species - /// @return A reference to this object - IntraPhaseProcessBuilder& Reacting(const Species& reactant); - /// @brief Adds a species that will be produced - /// @param product A species - /// @return A reference to this object - IntraPhaseProcessBuilder& Producing(const Species& product); - /// @brief Provides a yield in the amount of TODO UNITS - /// @param yield A value - /// @return A reference to this object - IntraPhaseProcessBuilder& WithYield(const double yield); - /// @brief Add a rate contant - /// @param rate_constant A rate constant - /// @return A reference to this object - IntraPhaseProcessBuilder& WithRateConstant(const RateConstant& rate_constant); - /// @brief Create the final process - /// @return A reference to this object - IntraPhaseProcessBuilder& Build(); - }; - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::For(const Phase& phase) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::With(const Species& species) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::Reacting(const Species& reactant) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::Producing(const Species& product) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::WithYield(const double yield) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::WithRateConstant(const RateConstant& rate_constant) - { - return *this; - } - - inline IntraPhaseProcessBuilder& IntraPhaseProcessBuilder::Build() - { - return *this; - } - -} // namespace micm \ No newline at end of file diff --git a/test/unit/configure/test_system_builder.cpp b/test/unit/configure/test_system_builder.cpp deleted file mode 100644 index 4dcad6d71..000000000 --- a/test/unit/configure/test_system_builder.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifdef USE_JSON -#include -#endif - -#include - -#ifdef USE_JSON -TEST(SystemBuilder, DefaultConstructor){ - micm::SystemBuilder builder{}; -} - -TEST(SystemBuilder, DetectsInvalidConfigFile){ - micm::SystemBuilder builder{}; - EXPECT_ANY_THROW(builder.Build("not_a_config_file.json")); -} - -TEST(SystemBuilder, DetectsInvalidConfigFileAndNoThrowDoesntThrow){ - micm::SystemBuilder builder{}; - EXPECT_NO_THROW(builder.Build("not_a_config_file.json")); - - auto system = builder.Build("not_a_config_file.json"); - ASSERT_TRUE(system.get() == nullptr); -} - -TEST(SystemBuilder, JsonBuilder){ - micm::SystemBuilder builder{}; - auto system = builder.Build("unit_configs/chapman/config.json"); - - EXPECT_TRUE(system != nullptr); - EXPECT_EQ(system->gas_phase_.species_.size(), 9); - for(auto& species : system->gas_phase_.species_){ - if (species.name_ == "M") { - EXPECT_EQ(species.properties_.size(), 0); - } - else{ - EXPECT_EQ(species.properties_.size(), 1); - } - } - EXPECT_EQ(system->photolysis_reactions_.size(), 3); - EXPECT_EQ(system->arrhenius_reactions_.size(), 4); -} -#endif \ No newline at end of file From 0685707bc212d6c7c272c2f308f123723fc9356e Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Wed, 14 Jun 2023 11:26:27 -0600 Subject: [PATCH 17/21] move using json namespace inside the function --- include/micm/configure/solver_config.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index eb2297a40..ba314ddbc 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -19,8 +19,6 @@ #include #include -using json = nlohmann::json; - namespace micm { template @@ -81,8 +79,9 @@ namespace micm template class JsonReaderPolicy : public ErrorPolicy { + using json = nlohmann::json; + public: - // Set to "public" for "NoThrowPolcy" std::vector species_; std::vector emissions_; std::vector first_order_loss_; From faa4ce9487c9544e8b0bd1abbc1f8acc8ccc9d9e Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Thu, 15 Jun 2023 12:14:02 -0600 Subject: [PATCH 18/21] put 'const' back to the size getter function in rate constant classes --- include/micm/process/photolysis_rate_constant.hpp | 4 ++-- include/micm/process/rate_constant.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/micm/process/photolysis_rate_constant.hpp b/include/micm/process/photolysis_rate_constant.hpp index 399c8bf66..9a64a1a37 100644 --- a/include/micm/process/photolysis_rate_constant.hpp +++ b/include/micm/process/photolysis_rate_constant.hpp @@ -36,7 +36,7 @@ namespace micm /// The single editable parameter is the unscaled rate constant for /// the photolysis reaction /// @return Number of custom rate constant parameters - std::size_t SizeCustomParameters() override; + std::size_t SizeCustomParameters() const override; /// @brief Calculate the rate constant /// @param conditions The current environmental conditions of the chemical system @@ -68,7 +68,7 @@ namespace micm return (double)*custom_parameters; } - inline std::size_t PhotolysisRateConstant::SizeCustomParameters() + inline std::size_t PhotolysisRateConstant::SizeCustomParameters() const { return 1; } diff --git a/include/micm/process/rate_constant.hpp b/include/micm/process/rate_constant.hpp index b37778812..1243250f2 100644 --- a/include/micm/process/rate_constant.hpp +++ b/include/micm/process/rate_constant.hpp @@ -24,7 +24,7 @@ namespace micm virtual std::unique_ptr clone() const = 0; /// @brief Returns the number of doubles needed to hold user-defined rate constant parameters /// @return Number of user-defined rate constant parameters - virtual std::size_t SizeCustomParameters() + virtual std::size_t SizeCustomParameters() const { return 0; } From a1276ae3aa4a78a3a55ba638a103099331eb0a2d Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Thu, 15 Jun 2023 18:49:23 -0600 Subject: [PATCH 19/21] add unit tests for rate constants --- test/unit/configure/test_solver_config.cpp | 57 +++++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/test/unit/configure/test_solver_config.cpp b/test/unit/configure/test_solver_config.cpp index 52198430a..25d9254d2 100644 --- a/test/unit/configure/test_solver_config.cpp +++ b/test/unit/configure/test_solver_config.cpp @@ -23,15 +23,20 @@ TEST(SolverConfig, ReadAndParseSystem) micm::SolverConfig solverConfig{}; std::variant configs = solverConfig.Configure("./unit_configs/chapman/config.json"); - auto* solver_params_ptr = std::get_if(&configs); + // Check if parsing is successful and returns 'Solverparameters' + auto* solver_params_ptr = std::get_if(&configs); EXPECT_TRUE(solver_params_ptr != nullptr); micm::SolverParameters& solver_params = *solver_params_ptr; + // Check 'gas_phase' in 'System' EXPECT_EQ(solver_params.system_.gas_phase_.species_.size(), 9); + + // Check 'phases' in 'System' EXPECT_EQ(solver_params.system_.phases_.size(), 0); + // Check 'name' and 'properties' in 'Species' std::vector> species_name_and_num_properties = { std::make_pair("M", 0), std::make_pair("Ar", 1), std::make_pair("CO2", 1), std::make_pair("H2O", 1), std::make_pair("N2", 1), std::make_pair("O1D", 1), @@ -52,23 +57,26 @@ TEST(SolverConfig, ReadAndParseProcess) micm::SolverConfig solverConfig{}; std::variant configs = solverConfig.Configure("./unit_configs/chapman/config.json"); - auto* solver_params_ptr = std::get_if(&configs); + // Check if parsing is successful and returns 'Solverparameters' + auto* solver_params_ptr = std::get_if(&configs); EXPECT_TRUE(solver_params_ptr != nullptr); micm::SolverParameters& solver_params = *solver_params_ptr; + auto& process_vector = solver_params.processes_; - int num_processes = 7; + // Check the number of 'Process' created + EXPECT_EQ(process_vector.size(), 7); + + // Check the number of 'reactants' and 'products' in each 'Process' + // Check 'yield' value for the first product and the number of 'spieces in 'phase' in each 'Process' int num_reactants_in_each_process[] = { 1, 1, 1, 2, 2, 2, 3 }; int num_products_in_each_process[] = { 1, 2, 2, 2, 2, 1, 2 }; double yield_value_of_first_product_in_each_process[] = { 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0 }; - std::size_t size_custom_parameters_of_rate_constant_in_each_process[] = { 1, 1, 1, 0, 0, 0, 0 }; int num_phase_in_each_process = 9; - EXPECT_EQ(solver_params.processes_.size(), num_processes); - short idx = 0; - for (const auto& p : solver_params.processes_) + for (const auto& p : process_vector) { EXPECT_EQ(p.reactants_.size(), num_reactants_in_each_process[idx]); EXPECT_EQ(p.products_.size(), num_products_in_each_process[idx]); @@ -77,6 +85,41 @@ TEST(SolverConfig, ReadAndParseProcess) idx++; } + // Check the name for 'PhotolysisRateConstant' + micm::PhotolysisRateConstant* photolysis_rate_const = nullptr; + std::string photolysis_name[] = { "O2_1", "O3_1", "O3_2" }; + + for (short i = 0; i < 3; i++) + { + photolysis_rate_const = dynamic_cast(process_vector[i].rate_constant_.get()); + + EXPECT_TRUE(photolysis_rate_const != nullptr); + EXPECT_EQ(photolysis_rate_const->name_, photolysis_name[i]); + } + + // Check the parameters for 'ArrheniusRateConstant' + micm::ArrheniusRateConstant* arrhenius_rate_const = nullptr; + double A_param[] = { 2.15e-11, 3.3e-11, 8.0e-12, 6.0e-34 }; + double B_param[] = { 0.0, 0.0, 0.0, 2.4 }; + double C_param[] = { 110.0, 55.0, -2060.00, 0.0 }; + double D_param[] = { 300.0, 300.0, 300.0, 300.0 }; + double E_param[] = { 0.0, 0.0, 0.0, 0.0 }; + + for (short i = 3; i < 7; i++) + { + arrhenius_rate_const = dynamic_cast(process_vector[i].rate_constant_.get()); + + EXPECT_TRUE(arrhenius_rate_const != nullptr); + EXPECT_EQ(arrhenius_rate_const->parameters_.A_, A_param[i - 3]); + EXPECT_EQ(arrhenius_rate_const->parameters_.B_, B_param[i - 3]); + EXPECT_EQ(arrhenius_rate_const->parameters_.C_, C_param[i - 3]); + EXPECT_EQ(arrhenius_rate_const->parameters_.D_, D_param[i - 3]); + EXPECT_EQ(arrhenius_rate_const->parameters_.E_, E_param[i - 3]); + } + + // Check the number of custom parameters of 'rate constant' in each 'Process' + std::size_t size_custom_parameters_of_rate_constant_in_each_process[] = { 1, 1, 1, 0, 0, 0, 0 }; + idx = 0; std::vector::iterator it; for (it = solver_params.processes_.begin(); it != solver_params.processes_.end(); it++, idx++) From eeb08d34501dfa08ae819bca4f20939f28496cb6 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Fri, 16 Jun 2023 10:21:37 -0600 Subject: [PATCH 20/21] fixed a typo --- include/micm/configure/solver_config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/micm/configure/solver_config.hpp b/include/micm/configure/solver_config.hpp index ba314ddbc..fd880c387 100644 --- a/include/micm/configure/solver_config.hpp +++ b/include/micm/configure/solver_config.hpp @@ -59,7 +59,7 @@ namespace micm } }; - // Solover parameters + // Solver parameters struct SolverParameters { micm::System system_; From d7d5cc1377f6912eb5c67b922c1769e3b7cba133 Mon Sep 17 00:00:00 2001 From: Jiwon Gim Date: Fri, 16 Jun 2023 16:06:09 -0600 Subject: [PATCH 21/21] add an assign function in sparse matrix class and chapman integration test using config --- include/micm/util/sparse_matrix.hpp | 10 ++++ test/integration/chapman.cpp | 89 ++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/include/micm/util/sparse_matrix.hpp b/include/micm/util/sparse_matrix.hpp index 5db9e26d8..80bf4e6b3 100644 --- a/include/micm/util/sparse_matrix.hpp +++ b/include/micm/util/sparse_matrix.hpp @@ -97,6 +97,16 @@ namespace micm { } + SparseMatrix& operator=(SparseMatrixBuilder& builder) + { + number_of_blocks_ = builder.number_of_blocks_; + data_ = std::vector(builder.NumberOfElements(), builder.initial_value_); + row_ids_ = builder.RowIdsVector(); + row_start_ = builder.RowStartVector(); + + return *this; + } + std::vector& AsVector() { return data_; diff --git a/test/integration/chapman.cpp b/test/integration/chapman.cpp index 9034900a7..bd742456f 100644 --- a/test/integration/chapman.cpp +++ b/test/integration/chapman.cpp @@ -12,6 +12,42 @@ using yields = std::pair; +#ifdef USE_JSON +# include +TEST(ChapmanIntegration, CanBuildChapmanSystemUsingConfig) +{ + micm::SolverConfig solverConfig{}; // Throw policy + std::variant configs = + solverConfig.Configure("./unit_configs/chapman/config.json"); + + // Check if parsing is successful and returns 'Solverparameters' + auto* solver_params_ptr = std::get_if(&configs); + EXPECT_TRUE(solver_params_ptr != nullptr); + + micm::SolverParameters& solver_params = *solver_params_ptr; + + micm::RosenbrockSolver solver{ solver_params.system_, + std::move(solver_params.processes_), + micm::RosenbrockSolverParameters{} }; + + micm::State 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; + std::vector photo_rates{ 0.1, 0.2, 0.3 }; + state.custom_rate_parameters_[0] = photo_rates; + state.conditions_[0].temperature_ = 2; + state.conditions_[0].pressure_ = 3; + + for (double t{}; t < 100; ++t) + { + state.custom_rate_parameters_[0] = photo_rates; + auto result = solver.Solve(t, t + 0.5, state); + // output state + } +} +#endif + TEST(ChapmanIntegration, CanBuildChapmanSystem) { auto o = micm::Species("O"); @@ -26,33 +62,32 @@ TEST(ChapmanIntegration, CanBuildChapmanSystem) micm::Phase gas_phase{ std::vector{ o, o1d, o2, o3, m, ar, n2, h2o, co2 } }; - micm::Process r1 = - micm::Process::create() - .reactants({ o1d, n2 }) - .products({ yields(o, 1), yields(n2, 1) }) - .rate_constant(micm::ArrheniusRateConstant({ .A_ = 2.15e-11, .B_= 0, .C_ = 110 })) - .phase(gas_phase); - - micm::Process r2 = - micm::Process::create() - .reactants({ o1d, o2 }) - .products({ yields(o, 1), yields(o2, 1) }) - .rate_constant(micm::ArrheniusRateConstant(micm::ArrheniusRateConstantParameters{ .A_ = 3.3e-11, .B_ = 0, .C_ = 55 })) - .phase(gas_phase); - - micm::Process r3 = - micm::Process::create() - .reactants({ o, o3 }) - .products({ yields(o2, 2) }) - .rate_constant(micm::ArrheniusRateConstant(micm::ArrheniusRateConstantParameters{ .A_ = 8e-12, .B_ = 0, .C_ = -2060 })) - .phase(gas_phase); - - micm::Process r4 = - micm::Process::create() - .reactants({ o, o2, m }) - .products({ yields(o3, 1), yields(m, 1) }) - .rate_constant(micm::ArrheniusRateConstant(micm::ArrheniusRateConstantParameters{ .A_ = 6.0e-34, .B_ = 0, .C_ = 2.4 })) - .phase(gas_phase); + micm::Process r1 = micm::Process::create() + .reactants({ o1d, n2 }) + .products({ yields(o, 1), yields(n2, 1) }) + .rate_constant(micm::ArrheniusRateConstant({ .A_ = 2.15e-11, .B_ = 0, .C_ = 110 })) + .phase(gas_phase); + + micm::Process r2 = micm::Process::create() + .reactants({ o1d, o2 }) + .products({ yields(o, 1), yields(o2, 1) }) + .rate_constant(micm::ArrheniusRateConstant( + micm::ArrheniusRateConstantParameters{ .A_ = 3.3e-11, .B_ = 0, .C_ = 55 })) + .phase(gas_phase); + + micm::Process r3 = micm::Process::create() + .reactants({ o, o3 }) + .products({ yields(o2, 2) }) + .rate_constant(micm::ArrheniusRateConstant( + micm::ArrheniusRateConstantParameters{ .A_ = 8e-12, .B_ = 0, .C_ = -2060 })) + .phase(gas_phase); + + micm::Process r4 = micm::Process::create() + .reactants({ o, o2, m }) + .products({ yields(o3, 1), yields(m, 1) }) + .rate_constant(micm::ArrheniusRateConstant( + micm::ArrheniusRateConstantParameters{ .A_ = 6.0e-34, .B_ = 0, .C_ = 2.4 })) + .phase(gas_phase); micm::Process photo_1 = micm::Process::create() .reactants({ o2 })