diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index ba3628a..73d2d2a 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -1,6 +1,11 @@ name: Mac -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} @@ -8,7 +13,6 @@ concurrency: jobs: xcode_macos_13: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: macos-13 strategy: matrix: @@ -35,7 +39,6 @@ jobs: ctest -C ${{ matrix.build_type }} --rerun-failed --output-on-failure . --verbose -j 10 macos_lateset: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: macos-latest strategy: matrix: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 3ffe526..3403814 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,6 +1,11 @@ name: Ubuntu -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} @@ -8,7 +13,6 @@ concurrency: jobs: gcc: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest strategy: matrix: @@ -34,7 +38,6 @@ jobs: ctest -C ${{ matrix.build_type }} --rerun-failed --output-on-failure . --verbose -j 10 clang: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 23751d5..b4544f4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,6 +1,11 @@ name: Windows -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} @@ -8,7 +13,6 @@ concurrency: jobs: msvc2022: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: windows-latest strategy: matrix: diff --git a/CMakeLists.txt b/CMakeLists.txt index f4328d2..c112e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,7 @@ message(STATUS "CMake build configuration for ${PROJECT_NAME} (${CMAKE_BUILD_TYP set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake") -option(ENABLE_TESTS "Build the tests" ON) -option(ENABLE_JSON "Include JSON support" ON) -option(ENABLE_YAML "Include YAML support" ON) +option(OPEN_ATMOS_ENABLE_TESTS "Build the tests" ON) ################################################################################ # Dependencies @@ -32,14 +30,14 @@ option(ENABLE_YAML "Include YAML support" ON) include(cmake/dependencies.cmake) ################################################################################ -# micm targets and documentation +# project source code add_subdirectory(src) ################################################################################ # Tests -if(PROJECT_IS_TOP_LEVEL AND ENABLE_TESTS) +if(PROJECT_IS_TOP_LEVEL AND OPEN_ATMOS_ENABLE_TESTS) enable_testing() add_subdirectory(test) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index dc405d6..a2c745c 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -3,7 +3,7 @@ include(FetchContent) ################################################################################ # google test -if(PROJECT_IS_TOP_LEVEL AND ENABLE_TESTS) +if(PROJECT_IS_TOP_LEVEL AND OPEN_ATMOS_ENABLE_TESTS) FetchContent_Declare(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 @@ -15,24 +15,11 @@ if(PROJECT_IS_TOP_LEVEL AND ENABLE_TESTS) FetchContent_MakeAvailable(googletest) endif() -################################################################################ -# nlohmann::json - -if(ENABLE_JSON) - FetchContent_Declare(json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.2 - ) - FetchContent_MakeAvailable(json) -endif() - ################################################################################ # yaml-cpp -if(ENABLE_YAML) - FetchContent_Declare(yaml - GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git - GIT_TAG 0.8.0 - ) - FetchContent_MakeAvailable(yaml) -endif() \ No newline at end of file +FetchContent_Declare(yaml + GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git + GIT_TAG 0.8.0 +) +FetchContent_MakeAvailable(yaml) \ No newline at end of file diff --git a/include/open_atmos/mechanism_configuration/json_parser.hpp b/include/open_atmos/mechanism_configuration/json_parser.hpp deleted file mode 100644 index dc7ee8f..0000000 --- a/include/open_atmos/mechanism_configuration/json_parser.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign -// -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace open_atmos -{ - namespace mechanism_configuration - { - class JsonParser - { - public: - /// @brief Reads a configuration from a json object - /// @param object a json object - /// @return A pair containing the parsing status and mechanism - std::pair Parse(const nlohmann::json &object); - - /// @brief Reads a configuration from a file path - /// @param file_path A path to single json configuration - /// @return A pair containing the parsing status and mechanism - std::pair Parse(const std::filesystem::path &file_path); - - /// @brief Reads a configuration from a file path - /// @param file_path A path to single json configuration - /// @return A pair containing the parsing status and mechanism - std::pair Parse(const std::string &file_path); - }; - } // namespace mechanism_configuration -} // namespace open_atmos diff --git a/include/open_atmos/mechanism_configuration/yaml_parser.hpp b/include/open_atmos/mechanism_configuration/parser.hpp similarity index 95% rename from include/open_atmos/mechanism_configuration/yaml_parser.hpp rename to include/open_atmos/mechanism_configuration/parser.hpp index 88adad3..d84c6e7 100644 --- a/include/open_atmos/mechanism_configuration/yaml_parser.hpp +++ b/include/open_atmos/mechanism_configuration/parser.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace open_atmos { namespace mechanism_configuration { - class YamlParser + class Parser { public: /// @brief Reads a configuration from a YAML node diff --git a/include/open_atmos/mechanism_configuration/parser_types.hpp b/include/open_atmos/mechanism_configuration/parser_types.hpp new file mode 100644 index 0000000..437d50d --- /dev/null +++ b/include/open_atmos/mechanism_configuration/parser_types.hpp @@ -0,0 +1,158 @@ +// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign +// +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + class CondensedPhaseArrheniusParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class TroeParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class BranchedParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class TunnelingParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class SurfaceParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class CondensedPhasePhotolysisParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class SimpolPhaseTransferParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class EmissionParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class PhotolysisParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class FirstOrderLossParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class AqueousEquilibriumParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class WetDepositionParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class HenrysLawParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + + class ArrheniusParser : public IReactionParser + { + public: + ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) override; + }; + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/include/open_atmos/mechanism_configuration/utils.hpp b/include/open_atmos/mechanism_configuration/utils.hpp new file mode 100644 index 0000000..95d94f6 --- /dev/null +++ b/include/open_atmos/mechanism_configuration/utils.hpp @@ -0,0 +1,91 @@ +// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign +// +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + class IReactionParser + { + public: + virtual ConfigParseStatus parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + types::Reactions& reactions) = 0; + virtual ~IReactionParser() = default; + }; + + std::unordered_map + GetComments(const YAML::Node& object, const std::vector& required_keys, const std::vector& optional_keys); + + ConfigParseStatus + ValidateSchema(const YAML::Node& object, const std::vector& required_keys, const std::vector& optional_keys); + + std::pair> ParseSpecies(const YAML::Node& objects); + + std::pair> ParsePhases(const YAML::Node& objects, const std::vector existing_species); + + std::pair ParseReactionComponent(const YAML::Node& object); + + std::vector ParseReactantsOrProducts(const std::string& key, const YAML::Node& object, ConfigParseStatus& status); + + template + bool ContainsUniqueObjectsByName(const std::vector& collection) + { + for (size_t i = 0; i < collection.size(); ++i) + { + for (size_t j = i + 1; j < collection.size(); ++j) + { + if (collection[i].name == collection[j].name) + { + return false; + } + } + } + return true; + } + + template + bool RequiresUnknownSpecies(const std::vector& requested_species, const std::vector& existing_species) + { + for (const auto& spec : requested_species) + { + auto it = std::find_if( + existing_species.begin(), + existing_species.end(), + [&spec](const auto& existing) + { + if constexpr (std::is_same::value) + { + return existing == spec; + } + else + { + return existing.name == spec; + } + }); + + if (it == existing_species.end()) + { + return true; + } + } + return false; + } + + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/include/open_atmos/mechanism_configuration/validation.hpp b/include/open_atmos/mechanism_configuration/validation.hpp index 15cf8bb..ab27d94 100644 --- a/include/open_atmos/mechanism_configuration/validation.hpp +++ b/include/open_atmos/mechanism_configuration/validation.hpp @@ -11,6 +11,26 @@ namespace open_atmos { namespace validation { + extern struct Keys keys; + extern struct Mechanism mechanism; + extern struct Species species; + extern struct Phase phase; + extern struct ReactionComponent reaction_component; + extern struct Arrhenius arrhenius; + extern struct CondensedPhaseArrhenius condensed_phase_arrhenius; + extern struct Troe troe; + extern struct Branched branched; + extern struct Tunneling tunneling; + extern struct Surface surface; + extern struct Photolysis photolysis; + extern struct CondensedPhasePhotolysis condensed_phase_photolysis; + extern struct Emission emission; + extern struct FirstOrderLoss first_order_loss; + extern struct SimpolPhaseTransfer simpol_phase_transfer; + extern struct WetDeposition wet_deposition; + extern struct HenrysLaw henrys_law; + extern struct AqueousEquilibrium aqueous_equilibrium; + struct Keys { // Shared, but also Mechanism @@ -149,13 +169,13 @@ namespace open_atmos // aerosol-phase water // aerosol-phase species - } keys; + }; struct Mechanism { const std::vector required_keys{ keys.version, keys.species, keys.phases, keys.reactions }; const std::vector optional_keys{ keys.name }; - } mechanism; + }; struct Species { @@ -167,31 +187,31 @@ namespace open_atmos keys.henrys_law_constant_exponential_factor, keys.n_star, keys.density }; - } species; + }; struct Phase { const std::vector required_keys{ keys.name, keys.species }; const std::vector optional_keys{}; - } phase; + }; struct ReactionComponent { const std::vector required_keys{ keys.species_name }; const std::vector optional_keys{ keys.coefficient }; - } reaction_component; + }; struct Arrhenius { const std::vector required_keys{ keys.products, keys.reactants, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.A, keys.B, keys.C, keys.D, keys.E, keys.Ea, keys.name }; - } arrhenius; + }; struct CondensedPhaseArrhenius { const std::vector required_keys{ keys.products, keys.reactants, keys.type, keys.aerosol_phase, keys.aerosol_phase_water }; const std::vector optional_keys{ keys.A, keys.B, keys.C, keys.D, keys.E, keys.Ea, keys.name }; - } condensed_phase_arrhenius; + }; struct Troe { @@ -199,62 +219,62 @@ namespace open_atmos const std::vector optional_keys{ keys.name, keys.k0_A, keys.k0_B, keys.k0_C, keys.kinf_A, keys.kinf_B, keys.kinf_C, keys.Fc, keys.N }; - } troe; + }; struct Branched { const std::vector required_keys{ keys.nitrate_products, keys.alkoxy_products, keys.reactants, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.name, keys.X, keys.Y, keys.a0, keys.n }; - } branched; + }; struct Tunneling { const std::vector required_keys{ keys.products, keys.reactants, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.name, keys.A, keys.B, keys.C }; - } tunneling; + }; struct Surface { const std::vector required_keys{ keys.gas_phase_products, keys.gas_phase_species, keys.type, keys.gas_phase, keys.aerosol_phase }; const std::vector optional_keys{ keys.name, keys.reaction_probability }; - } surface; + }; struct Photolysis { const std::vector required_keys{ keys.reactants, keys.products, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; - } photolysis; + }; struct CondensedPhasePhotolysis { const std::vector required_keys{ keys.reactants, keys.products, keys.type, keys.aerosol_phase, keys.aerosol_phase_water }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; - } condensed_phase_photolysis; + }; struct Emission { const std::vector required_keys{ keys.products, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; - } emission; + }; struct FirstOrderLoss { const std::vector required_keys{ keys.reactants, keys.type, keys.gas_phase }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; - } first_order_loss; + }; struct SimpolPhaseTransfer { const std::vector required_keys{ keys.type, keys.gas_phase, keys.gas_phase_species, keys.aerosol_phase, keys.aerosol_phase_species, keys.B }; const std::vector optional_keys{ keys.name }; - } simpol_phase_transfer; + }; struct WetDeposition { const std::vector required_keys{ keys.aerosol_phase, keys.type }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; - } wet_deposition; + }; struct HenrysLaw { @@ -262,13 +282,13 @@ namespace open_atmos keys.type, keys.gas_phase, keys.gas_phase_species, keys.aerosol_phase, keys.aerosol_phase_species, keys.aerosol_phase_water }; const std::vector optional_keys{ keys.name }; - } henrys_law; + }; struct AqueousEquilibrium { const std::vector required_keys{ keys.type, keys.reactants, keys.products, keys.aerosol_phase, keys.aerosol_phase_water, keys.k_reverse }; const std::vector optional_keys{ keys.name, keys.A, keys.C }; - } aqueous_equilibrium; + }; } // namespace validation } // namespace open_atmos \ No newline at end of file diff --git a/include/open_atmos/types.hpp b/include/open_atmos/types.hpp index 2d39e6e..b83b2f9 100644 --- a/include/open_atmos/types.hpp +++ b/include/open_atmos/types.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace open_atmos diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt index 6c3bcab..3ee818f 100644 --- a/packaging/CMakeLists.txt +++ b/packaging/CMakeLists.txt @@ -22,24 +22,12 @@ install( ) -if(ENABLE_JSON) - install( - TARGETS - nlohmann_json - EXPORT - mechanism_configuration_Exports - ) -endif() - -if(ENABLE_YAML) - install( - TARGETS - yaml-cpp - EXPORT - mechanism_configuration_Exports - ) -endif() - +install( + TARGETS + yaml-cpp + EXPORT + mechanism_configuration_Exports +) # install the cmake config files set(cmake_config_install_location ${INSTALL_PREFIX}/cmake) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7e6ddb7..06cb716 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,26 +18,28 @@ target_include_directories(mechanism_configuration $ ) -if(ENABLE_JSON) - target_sources(mechanism_configuration - PRIVATE - json_parser.cpp - ) - - target_link_libraries(mechanism_configuration - PUBLIC - nlohmann_json::nlohmann_json - ) -endif() - -if(ENABLE_YAML) - target_sources(mechanism_configuration - PRIVATE - yaml_parser.cpp - ) +target_sources(mechanism_configuration + PRIVATE + parser.cpp + utils.cpp + validation.cpp + condensed_phase_arrhenius_parser.cpp + troe_parser.cpp + branched_parser.cpp + tunneling_parser.cpp + surface_parser.cpp + photolysis_parser.cpp + condensed_phase_photolysis_parser.cpp + emission_parser.cpp + first_order_loss_parser.cpp + simpol_phase_transfer_parser.cpp + aqueous_equilibrium_parser.cpp + wet_deposition_parser.cpp + henrys_law_parser.cpp + arrhenius_parser.cpp +) - target_link_libraries(mechanism_configuration - PUBLIC - yaml-cpp::yaml-cpp - ) -endif() +target_link_libraries(mechanism_configuration + PUBLIC + yaml-cpp::yaml-cpp +) \ No newline at end of file diff --git a/src/aqueous_equilibrium_parser.cpp b/src/aqueous_equilibrium_parser.cpp new file mode 100644 index 0000000..d6a6f05 --- /dev/null +++ b/src/aqueous_equilibrium_parser.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus AqueousEquilibriumParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::AqueousEquilibrium aqueous_equilibrium; + + status = ValidateSchema(object, validation::aqueous_equilibrium.required_keys, validation::aqueous_equilibrium.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.A]) + { + aqueous_equilibrium.A = object[validation::keys.A].as(); + } + if (object[validation::keys.C]) + { + aqueous_equilibrium.C = object[validation::keys.C].as(); + } + + aqueous_equilibrium.k_reverse = object[validation::keys.k_reverse].as(); + + if (object[validation::keys.name]) + { + aqueous_equilibrium.name = object[validation::keys.name].as(); + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].as(); + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + requested_species.push_back(aerosol_phase_water); + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + auto phase_it = std::find_if( + existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); + + if (phase_it != existing_phases.end()) + { + std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) + { + status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; + } + } + else + { + status = ConfigParseStatus::UnknownPhase; + } + + aqueous_equilibrium.aerosol_phase = aerosol_phase; + aqueous_equilibrium.aerosol_phase_water = aerosol_phase_water; + aqueous_equilibrium.products = products; + aqueous_equilibrium.reactants = reactants; + aqueous_equilibrium.unknown_properties = + GetComments(object, validation::aqueous_equilibrium.required_keys, validation::aqueous_equilibrium.optional_keys); + reactions.aqueous_equilibrium.push_back(aqueous_equilibrium); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/arrhenius_parser.cpp b/src/arrhenius_parser.cpp new file mode 100644 index 0000000..d063139 --- /dev/null +++ b/src/arrhenius_parser.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus ArrheniusParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Arrhenius arrhenius; + + status = ValidateSchema(object, validation::arrhenius.required_keys, validation::arrhenius.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.A]) + { + arrhenius.A = object[validation::keys.A].as(); + } + if (object[validation::keys.B]) + { + arrhenius.B = object[validation::keys.B].as(); + } + if (object[validation::keys.C]) + { + arrhenius.C = object[validation::keys.C].as(); + } + if (object[validation::keys.D]) + { + arrhenius.D = object[validation::keys.D].as(); + } + if (object[validation::keys.E]) + { + arrhenius.E = object[validation::keys.E].as(); + } + if (object[validation::keys.Ea]) + { + if (arrhenius.C != 0) + { + std::cerr << "Ea is specified when C is also specified for an Arrhenius reaction. Pick one." << std::endl; + status = ConfigParseStatus::MutuallyExclusiveOption; + } + arrhenius.C = -1 * object[validation::keys.Ea].as() / constants::boltzmann; + } + + if (object[validation::keys.name]) + { + arrhenius.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + arrhenius.gas_phase = gas_phase; + arrhenius.products = products; + arrhenius.reactants = reactants; + arrhenius.unknown_properties = GetComments(object, validation::arrhenius.required_keys, validation::arrhenius.optional_keys); + reactions.arrhenius.push_back(arrhenius); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/branched_parser.cpp b/src/branched_parser.cpp new file mode 100644 index 0000000..0c28f08 --- /dev/null +++ b/src/branched_parser.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus BranchedParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Branched branched; + + status = ValidateSchema(object, validation::branched.required_keys, validation::branched.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto alkoxy_products = ParseReactantsOrProducts(validation::keys.alkoxy_products, object, status); + auto nitrate_products = ParseReactantsOrProducts(validation::keys.nitrate_products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + branched.X = object[validation::keys.X].as(); + branched.Y = object[validation::keys.Y].as(); + branched.a0 = object[validation::keys.a0].as(); + branched.n = object[validation::keys.n].as(); + + if (object[validation::keys.name]) + { + branched.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : nitrate_products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : alkoxy_products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + branched.gas_phase = gas_phase; + branched.nitrate_products = nitrate_products; + branched.alkoxy_products = alkoxy_products; + branched.reactants = reactants; + branched.unknown_properties = GetComments(object, validation::branched.required_keys, validation::branched.optional_keys); + reactions.branched.push_back(branched); + } + + return status; + + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/condensed_phase_arrhenius_parser.cpp b/src/condensed_phase_arrhenius_parser.cpp new file mode 100644 index 0000000..6364f76 --- /dev/null +++ b/src/condensed_phase_arrhenius_parser.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus CondensedPhaseArrheniusParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::CondensedPhaseArrhenius condensed_phase_arrhenius; + + status = ValidateSchema(object, validation::condensed_phase_arrhenius.required_keys, validation::condensed_phase_arrhenius.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.A]) + { + condensed_phase_arrhenius.A = object[validation::keys.A].as(); + } + if (object[validation::keys.B]) + { + condensed_phase_arrhenius.B = object[validation::keys.B].as(); + } + if (object[validation::keys.C]) + { + condensed_phase_arrhenius.C = object[validation::keys.C].as(); + } + if (object[validation::keys.D]) + { + condensed_phase_arrhenius.D = object[validation::keys.D].as(); + } + if (object[validation::keys.E]) + { + condensed_phase_arrhenius.E = object[validation::keys.E].as(); + } + if (object[validation::keys.Ea]) + { + if (condensed_phase_arrhenius.C != 0) + { + std::cerr << "Ea is specified when C is also specified for an CondensedPhasecondensed_phase_arrhenius reaction. Pick one." << std::endl; + status = ConfigParseStatus::MutuallyExclusiveOption; + } + condensed_phase_arrhenius.C = -1 * object[validation::keys.Ea].as() / constants::boltzmann; + } + + if (object[validation::keys.name]) + { + condensed_phase_arrhenius.name = object[validation::keys.name].as(); + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].as(); + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + requested_species.push_back(aerosol_phase_water); + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + auto phase_it = std::find_if( + existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); + + if (phase_it != existing_phases.end()) + { + std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) + { + status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; + } + } + else + { + status = ConfigParseStatus::UnknownPhase; + } + + condensed_phase_arrhenius.aerosol_phase = aerosol_phase; + condensed_phase_arrhenius.aerosol_phase_water = aerosol_phase_water; + condensed_phase_arrhenius.products = products; + condensed_phase_arrhenius.reactants = reactants; + condensed_phase_arrhenius.unknown_properties = + GetComments(object, validation::condensed_phase_arrhenius.required_keys, validation::condensed_phase_arrhenius.optional_keys); + reactions.condensed_phase_arrhenius.push_back(condensed_phase_arrhenius); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/condensed_phase_photolysis_parser.cpp b/src/condensed_phase_photolysis_parser.cpp new file mode 100644 index 0000000..c4b521f --- /dev/null +++ b/src/condensed_phase_photolysis_parser.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus CondensedPhasePhotolysisParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::CondensedPhasePhotolysis condensed_phase_photolysis; + + status = ValidateSchema(object, validation::condensed_phase_photolysis.required_keys, validation::photolysis.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.scaling_factor]) + { + condensed_phase_photolysis.scaling_factor_ = object[validation::keys.scaling_factor].as(); + } + + if (object[validation::keys.name]) + { + condensed_phase_photolysis.name = object[validation::keys.name].as(); + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].as(); + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + requested_species.push_back(aerosol_phase_water); + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + if (status == ConfigParseStatus::Success && reactants.size() > 1) + { + status = ConfigParseStatus::TooManyReactionComponents; + } + + auto phase_it = std::find_if( + existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); + + if (phase_it != existing_phases.end()) + { + std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) + { + status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; + } + } + else + { + status = ConfigParseStatus::UnknownPhase; + } + + condensed_phase_photolysis.aerosol_phase = aerosol_phase; + condensed_phase_photolysis.aerosol_phase_water = aerosol_phase_water; + condensed_phase_photolysis.products = products; + condensed_phase_photolysis.reactants = reactants; + condensed_phase_photolysis.unknown_properties = + GetComments(object, validation::condensed_phase_photolysis.required_keys, validation::photolysis.optional_keys); + reactions.condensed_phase_photolysis.push_back(condensed_phase_photolysis); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/emission_parser.cpp b/src/emission_parser.cpp new file mode 100644 index 0000000..fccf389 --- /dev/null +++ b/src/emission_parser.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus EmissionParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Emission emission; + + status = ValidateSchema(object, validation::emission.required_keys, validation::emission.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + + if (object[validation::keys.scaling_factor]) + { + emission.scaling_factor = object[validation::keys.scaling_factor].as(); + } + + if (object[validation::keys.name]) + { + emission.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + emission.gas_phase = gas_phase; + emission.products = products; + emission.unknown_properties = GetComments(object, validation::emission.required_keys, validation::emission.optional_keys); + reactions.emission.push_back(emission); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/first_order_loss_parser.cpp b/src/first_order_loss_parser.cpp new file mode 100644 index 0000000..f5b6010 --- /dev/null +++ b/src/first_order_loss_parser.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus FirstOrderLossParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::FirstOrderLoss first_order_loss; + + status = ValidateSchema(object, validation::first_order_loss.required_keys, validation::first_order_loss.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.scaling_factor]) + { + first_order_loss.scaling_factor = object[validation::keys.scaling_factor].as(); + } + + if (object[validation::keys.name]) + { + first_order_loss.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + if (status == ConfigParseStatus::Success && reactants.size() > 1) + { + status = ConfigParseStatus::TooManyReactionComponents; + } + + first_order_loss.gas_phase = gas_phase; + first_order_loss.reactants = reactants; + first_order_loss.unknown_properties = + GetComments(object, validation::first_order_loss.required_keys, validation::first_order_loss.optional_keys); + reactions.first_order_loss.push_back(first_order_loss); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/henrys_law_parser.cpp b/src/henrys_law_parser.cpp new file mode 100644 index 0000000..ce36f29 --- /dev/null +++ b/src/henrys_law_parser.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus HenrysLawParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::HenrysLaw henrys_law; + + status = ValidateSchema(object, validation::henrys_law.required_keys, validation::henrys_law.optional_keys); + if (status == ConfigParseStatus::Success) + { + std::string gas_phase = object[validation::keys.gas_phase].as(); + std::string gas_phase_species = object[validation::keys.gas_phase_species].as(); + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + std::string aerosol_phase_species = object[validation::keys.aerosol_phase_species].as(); + std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].as(); + + if (object[validation::keys.name]) + { + henrys_law.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + requested_species.push_back(gas_phase_species); + requested_species.push_back(aerosol_phase_species); + requested_species.push_back(aerosol_phase_water); + + std::vector requested_aerosol_species; + requested_aerosol_species.push_back(aerosol_phase_species); + requested_aerosol_species.push_back(aerosol_phase_water); + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + auto phase_it = std::find_if( + existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); + + if (phase_it != existing_phases.end()) + { + std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_aerosol_species, aerosol_phase_species)) + { + status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; + } + } + else + { + status = ConfigParseStatus::UnknownPhase; + } + + henrys_law.gas_phase = gas_phase; + henrys_law.gas_phase_species = gas_phase_species; + henrys_law.aerosol_phase = aerosol_phase; + henrys_law.aerosol_phase_species = aerosol_phase_species; + henrys_law.aerosol_phase_water = aerosol_phase_water; + henrys_law.unknown_properties = GetComments(object, validation::henrys_law.required_keys, validation::henrys_law.optional_keys); + reactions.henrys_law.push_back(henrys_law); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/json_parser.cpp b/src/json_parser.cpp deleted file mode 100644 index 90f4ee4..0000000 --- a/src/json_parser.cpp +++ /dev/null @@ -1,1504 +0,0 @@ -// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign -// -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include -#include - -using nlohmann::json; -using namespace open_atmos; -using namespace open_atmos::mechanism_configuration; - -class IReactionParser -{ - public: - /// @brief Parses a reaction - /// @param object A json object - /// @param existing_species A list of species configured in a mechanism - /// @param existing_phases A list of phases configured in a mechanism - /// @return A pair indicating parsing success and a struct of Condensed Phase Arrhenius parameters - virtual ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - types::Reactions& reactions) = 0; - virtual ~IReactionParser() = default; -}; - -/// @brief Finds all keys that start with "__" -/// @param object A json object -/// @param required_keys for a type -/// @param optional_keys for a type -/// @return a dictionary of comments w -std::unordered_map -GetComments(const json& object, const std::vector& required_keys, const std::vector& optional_keys) -{ - // standard keys are: - // those in required keys - // those in optional keys - // starting with __ - // anything else is reported as an error so that typos are caught, specifically for optional keys - - std::vector sorted_object_keys; - for (auto& [key, value] : object.items()) - sorted_object_keys.push_back(key); - - auto sorted_required_keys = required_keys; - auto sorted_optional_keys = optional_keys; - std::sort(sorted_object_keys.begin(), sorted_object_keys.end()); - std::sort(sorted_required_keys.begin(), sorted_required_keys.end()); - std::sort(sorted_optional_keys.begin(), sorted_optional_keys.end()); - - // get the difference between the object keys and those required - // what's left should be the optional keys and valid comments - std::vector difference; - std::set_difference( - sorted_object_keys.begin(), sorted_object_keys.end(), sorted_required_keys.begin(), sorted_required_keys.end(), std::back_inserter(difference)); - - std::vector remaining; - std::set_difference(difference.begin(), difference.end(), sorted_optional_keys.begin(), sorted_optional_keys.end(), std::back_inserter(remaining)); - - std::unordered_map unknown_properties; - for (const auto& key : remaining) - { - std::string val = object[key].dump(); - unknown_properties[key] = val; - } - return unknown_properties; -} - -/// @brief Search for nonstandard keys. Only nonstandard keys starting with __ are allowed. Others are considered typos -/// @param object the object whose keys need to be validated -/// @param required_keys The required keys -/// @param optional_keys The optional keys -/// @return true if only standard keys are found -ConfigParseStatus ValidateSchema(const json& object, const std::vector& required_keys, const std::vector& optional_keys) -{ - // standard keys are: - // those in required keys - // those in optional keys - // starting with __ - // anything else is reported as an error so that typos are caught, specifically for optional keys - - // debug statement - // std::cout << "ValidateSchema object " << object.dump(4) << std::endl; - - if (!object.empty() && object.begin().value().is_null()) - { - return ConfigParseStatus::Success; - } - - std::vector sorted_object_keys; - for (auto& [key, value] : object.items()) - sorted_object_keys.push_back(key); - - auto sorted_required_keys = required_keys; - auto sorted_optional_keys = optional_keys; - std::sort(sorted_object_keys.begin(), sorted_object_keys.end()); - std::sort(sorted_required_keys.begin(), sorted_required_keys.end()); - std::sort(sorted_optional_keys.begin(), sorted_optional_keys.end()); - - // get the difference between the object keys and those required - // what's left should be the optional keys and valid comments - std::vector difference; - std::set_difference( - sorted_object_keys.begin(), sorted_object_keys.end(), sorted_required_keys.begin(), sorted_required_keys.end(), std::back_inserter(difference)); - - // check that the number of keys remaining is exactly equal to the expected number of required keys - if (difference.size() != (sorted_object_keys.size() - required_keys.size())) - { - std::vector missing_keys; - std::set_difference( - sorted_required_keys.begin(), - sorted_required_keys.end(), - sorted_object_keys.begin(), - sorted_object_keys.end(), - std::back_inserter(missing_keys)); - for (auto& key : missing_keys) - std::cerr << "Missing required key '" << key << "' in object: " << object << std::endl; - - return ConfigParseStatus::RequiredKeyNotFound; - } - - std::vector remaining; - std::set_difference(difference.begin(), difference.end(), sorted_optional_keys.begin(), sorted_optional_keys.end(), std::back_inserter(remaining)); - - // now, anything left must be standard comment starting with __ - for (auto& key : remaining) - { - if (key.find("__") == std::string::npos) - { - std::cerr << "Non-standard key '" << key << "' found in object" << object << std::endl; - - return ConfigParseStatus::InvalidKey; - } - } - return ConfigParseStatus::Success; -} - -template -bool ContainsUniqueObjectsByName(const std::vector& collection) -{ - for (size_t i = 0; i < collection.size(); ++i) - { - for (size_t j = i + 1; j < collection.size(); ++j) - { - if (collection[i].name == collection[j].name) - { - return false; - } - } - } - return true; -} - -/// @brief Check if any species in required by a reaction is not in the species configured for this mechanism -/// @param requested_species a list of species needed by a reaction -/// @param existing_species all configured species in the mechanism -/// @return a boolean indicating if this reaction needs species that are not configured in the mechanism -template -bool RequiresUnknownSpecies(const std::vector& requested_species, const std::vector& existing_species) -{ - for (const auto& spec : requested_species) - { - auto it = std::find_if( - existing_species.begin(), - existing_species.end(), - [&spec](const auto& existing) - { - if constexpr (std::is_same::value) - { - return existing == spec; - } - else - { - return existing.name == spec; - } - }); - - if (it == existing_species.end()) - { - return true; - } - } - return false; -} - -/// @brief Parses species in a mechanism -/// @param objects json object of species -/// @return A pair indicating parsing success and a list of species -std::pair> ParseSpecies(const json& objects) -{ - ConfigParseStatus status = ConfigParseStatus::Success; - std::vector all_species; - - for (const auto& object : objects) - { - types::Species species; - status = ValidateSchema(object, validation::species.required_keys, validation::species.optional_keys); - if (status != ConfigParseStatus::Success) - { - break; - } - - std::string name = object[validation::keys.name].get(); - - std::map numerical_properties{}; - for (const auto& key : validation::species.optional_keys) - { - if (object.contains(key)) - { - double val = object[key].get(); - numerical_properties[key] = val; - } - } - - species.name = name; - species.optional_numerical_properties = numerical_properties; - species.unknown_properties = GetComments(object, validation::species.required_keys, validation::species.optional_keys); - - all_species.push_back(species); - } - - if (!ContainsUniqueObjectsByName(all_species)) - status = ConfigParseStatus::DuplicateSpeciesDetected; - - return { status, all_species }; -} - -/// @brief Parses phases in a mechanism -/// @param objects jsoon object of phases -/// @param existing_species a list of species configured in the mechanism -/// @return A pair indicating parsing success and a list of phases -std::pair> ParsePhases(const json& objects, const std::vector existing_species) -{ - ConfigParseStatus status = ConfigParseStatus::Success; - std::vector all_phases; - - for (const auto& object : objects) - { - types::Phase phase; - status = ValidateSchema(object, validation::phase.required_keys, validation::phase.optional_keys); - if (status != ConfigParseStatus::Success) - { - break; - } - - std::string name = object[validation::keys.name].get(); - - std::vector species{}; - for (const auto& spec : object[validation::keys.species]) - { - species.push_back(spec); - } - - phase.name = name; - phase.species = species; - phase.unknown_properties = GetComments(object, validation::phase.required_keys, validation::phase.optional_keys); - - if (RequiresUnknownSpecies(species, existing_species)) - { - status = ConfigParseStatus::PhaseRequiresUnknownSpecies; - break; - } - - all_phases.push_back(phase); - } - - if (status == ConfigParseStatus::Success && !ContainsUniqueObjectsByName(all_phases)) - status = ConfigParseStatus::DuplicatePhasesDetected; - - return { status, all_phases }; -} - -/// @brief Parses all reactions -/// @param object -/// @return A pair indicating parsing success and a struct of all reactions found in the mechanism -std::pair ParseReactionComponent(const json& object) -{ - ConfigParseStatus status = ConfigParseStatus::Success; - types::ReactionComponent component; - - status = ValidateSchema(object, validation::reaction_component.required_keys, validation::reaction_component.optional_keys); - if (status == ConfigParseStatus::Success) - { - std::string species_name = object[validation::keys.species_name].get(); - double coefficient = 1; - if (object.contains(validation::keys.coefficient)) - { - coefficient = object[validation::keys.coefficient].get(); - } - - component.species_name = species_name; - component.coefficient = coefficient; - component.unknown_properties = GetComments(object, validation::reaction_component.required_keys, validation::reaction_component.optional_keys); - } - - return { status, component }; -} - -std::vector ParseReactantsOrProducts(const std::string& key, const json& object, ConfigParseStatus& status) -{ - std::vector result{}; - for (const auto& product : object[key]) - { - auto component_parse = ParseReactionComponent(product); - status = component_parse.first; - if (status != ConfigParseStatus::Success) - { - break; - } - result.push_back(component_parse.second); - } - return result; -} - -class CondensedPhaseArrheniusParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::CondensedPhaseArrhenius condensed_phase_arrhenius; - - status = ValidateSchema(object, validation::condensed_phase_arrhenius.required_keys, validation::condensed_phase_arrhenius.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.A)) - { - condensed_phase_arrhenius.A = object[validation::keys.A].get(); - } - if (object.contains(validation::keys.B)) - { - condensed_phase_arrhenius.B = object[validation::keys.B].get(); - } - if (object.contains(validation::keys.C)) - { - condensed_phase_arrhenius.C = object[validation::keys.C].get(); - } - if (object.contains(validation::keys.D)) - { - condensed_phase_arrhenius.D = object[validation::keys.D].get(); - } - if (object.contains(validation::keys.E)) - { - condensed_phase_arrhenius.E = object[validation::keys.E].get(); - } - if (object.contains(validation::keys.Ea)) - { - if (condensed_phase_arrhenius.C != 0) - { - std::cerr << "Ea is specified when C is also specified for an CondensedPhasecondensed_phase_arrhenius reaction. Pick one." << std::endl; - status = ConfigParseStatus::MutuallyExclusiveOption; - } - // Calculate 'C' using 'Ea' - condensed_phase_arrhenius.C = -1 * object[validation::keys.Ea].get() / constants::boltzmann; - } - - if (object.contains(validation::keys.name)) - { - condensed_phase_arrhenius.name = object[validation::keys.name].get(); - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].get(); - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - requested_species.push_back(aerosol_phase_water); - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - auto phase_it = std::find_if( - existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); - - if (phase_it != existing_phases.end()) - { - // check if all of the species for this reaction are actually in the aerosol phase - std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) - { - status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; - } - } - else - { - status = ConfigParseStatus::UnknownPhase; - } - - condensed_phase_arrhenius.aerosol_phase = aerosol_phase; - condensed_phase_arrhenius.aerosol_phase_water = aerosol_phase_water; - condensed_phase_arrhenius.products = products; - condensed_phase_arrhenius.reactants = reactants; - condensed_phase_arrhenius.unknown_properties = - GetComments(object, validation::condensed_phase_arrhenius.required_keys, validation::condensed_phase_arrhenius.optional_keys); - reactions.condensed_phase_arrhenius.push_back(condensed_phase_arrhenius); - } - - return status; - } -}; - -class TroeParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Troe troe; - - status = ValidateSchema(object, validation::troe.required_keys, validation::troe.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.k0_A)) - { - troe.k0_A = object[validation::keys.k0_A].get(); - } - if (object.contains(validation::keys.k0_B)) - { - troe.k0_B = object[validation::keys.k0_B].get(); - } - if (object.contains(validation::keys.k0_C)) - { - troe.k0_C = object[validation::keys.k0_C].get(); - } - if (object.contains(validation::keys.kinf_A)) - { - troe.kinf_A = object[validation::keys.kinf_A].get(); - } - if (object.contains(validation::keys.kinf_B)) - { - troe.kinf_B = object[validation::keys.kinf_B].get(); - } - if (object.contains(validation::keys.kinf_C)) - { - troe.kinf_C = object[validation::keys.kinf_C].get(); - } - if (object.contains(validation::keys.Fc)) - { - troe.Fc = object[validation::keys.Fc].get(); - } - if (object.contains(validation::keys.N)) - { - troe.N = object[validation::keys.N].get(); - } - - if (object.contains(validation::keys.name)) - { - troe.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - troe.gas_phase = gas_phase; - troe.products = products; - troe.reactants = reactants; - troe.unknown_properties = GetComments(object, validation::troe.required_keys, validation::troe.optional_keys); - reactions.troe.push_back(troe); - } - - return status; - } -}; - -class BranchedParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Branched branched; - - status = ValidateSchema(object, validation::branched.required_keys, validation::branched.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto alkoxy_products = ParseReactantsOrProducts(validation::keys.alkoxy_products, object, status); - auto nitrate_products = ParseReactantsOrProducts(validation::keys.nitrate_products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - branched.X = object[validation::keys.X].get(); - branched.Y = object[validation::keys.Y].get(); - branched.a0 = object[validation::keys.a0].get(); - branched.n = object[validation::keys.n].get(); - - if (object.contains(validation::keys.name)) - { - branched.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : nitrate_products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : alkoxy_products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - branched.gas_phase = gas_phase; - branched.nitrate_products = nitrate_products; - branched.alkoxy_products = alkoxy_products; - branched.reactants = reactants; - branched.unknown_properties = GetComments(object, validation::branched.required_keys, validation::branched.optional_keys); - reactions.branched.push_back(branched); - } - - return status; - } -}; - -class TunnelingParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Tunneling tunneling; - - status = ValidateSchema(object, validation::tunneling.required_keys, validation::tunneling.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.A)) - { - tunneling.A = object[validation::keys.A].get(); - } - if (object.contains(validation::keys.B)) - { - tunneling.B = object[validation::keys.B].get(); - } - if (object.contains(validation::keys.C)) - { - tunneling.C = object[validation::keys.C].get(); - } - - if (object.contains(validation::keys.name)) - { - tunneling.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - tunneling.gas_phase = gas_phase; - tunneling.products = products; - tunneling.reactants = reactants; - tunneling.unknown_properties = GetComments(object, validation::tunneling.required_keys, validation::tunneling.optional_keys); - reactions.tunneling.push_back(tunneling); - } - - return status; - } -}; - -class SurfaceParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Surface surface; - - status = ValidateSchema(object, validation::surface.required_keys, validation::surface.optional_keys); - if (status == ConfigParseStatus::Success) - { - std::string gas_phase_species = object[validation::keys.gas_phase_species].get(); - - auto products = ParseReactantsOrProducts(validation::keys.gas_phase_products, object, status); - - if (object.contains(validation::keys.reaction_probability)) - { - surface.reaction_probability = object[validation::keys.reaction_probability].get(); - } - - if (object.contains(validation::keys.name)) - { - surface.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - requested_species.push_back(gas_phase_species); - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - auto it = - std::find_if(existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - surface.gas_phase = object[validation::keys.gas_phase].get(); - surface.aerosol_phase = aerosol_phase; - surface.gas_phase_products = products; - types::ReactionComponent component; - component.species_name = gas_phase_species; - surface.gas_phase_species = component; - surface.unknown_properties = GetComments(object, validation::surface.required_keys, validation::surface.optional_keys); - reactions.surface.push_back(surface); - } - - return status; - } -}; - -class PhotolysisParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Photolysis photolysis; - - status = ValidateSchema(object, validation::photolysis.required_keys, validation::photolysis.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.scaling_factor)) - { - photolysis.scaling_factor = object[validation::keys.scaling_factor].get(); - } - - if (object.contains(validation::keys.name)) - { - photolysis.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - if (status == ConfigParseStatus::Success && reactants.size() > 1) - { - status = ConfigParseStatus::TooManyReactionComponents; - } - - photolysis.gas_phase = gas_phase; - photolysis.products = products; - photolysis.reactants = reactants; - photolysis.unknown_properties = GetComments(object, validation::photolysis.required_keys, validation::photolysis.optional_keys); - reactions.photolysis.push_back(photolysis); - } - - return status; - } -}; - -class CondensedPhasePhotolysisParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::CondensedPhasePhotolysis condensed_phase_photolysis; - - status = ValidateSchema(object, validation::condensed_phase_photolysis.required_keys, validation::photolysis.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.scaling_factor)) - { - condensed_phase_photolysis.scaling_factor_ = object[validation::keys.scaling_factor].get(); - } - - if (object.contains(validation::keys.name)) - { - condensed_phase_photolysis.name = object[validation::keys.name].get(); - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].get(); - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - requested_species.push_back(aerosol_phase_water); - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - if (status == ConfigParseStatus::Success && reactants.size() > 1) - { - status = ConfigParseStatus::TooManyReactionComponents; - } - - auto phase_it = std::find_if( - existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); - - if (phase_it != existing_phases.end()) - { - // check if all of the species for this reaction are actually in the aerosol phase - std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) - { - status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; - } - } - else - { - status = ConfigParseStatus::UnknownPhase; - } - - condensed_phase_photolysis.aerosol_phase = aerosol_phase; - condensed_phase_photolysis.aerosol_phase_water = aerosol_phase_water; - condensed_phase_photolysis.products = products; - condensed_phase_photolysis.reactants = reactants; - condensed_phase_photolysis.unknown_properties = - GetComments(object, validation::condensed_phase_photolysis.required_keys, validation::photolysis.optional_keys); - reactions.condensed_phase_photolysis.push_back(condensed_phase_photolysis); - } - - return status; - } -}; - -class EmissionParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Emission emission; - - status = ValidateSchema(object, validation::emission.required_keys, validation::emission.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - - if (object.contains(validation::keys.scaling_factor)) - { - emission.scaling_factor = object[validation::keys.scaling_factor].get(); - } - - if (object.contains(validation::keys.name)) - { - emission.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - emission.gas_phase = gas_phase; - emission.products = products; - emission.unknown_properties = GetComments(object, validation::emission.required_keys, validation::emission.optional_keys); - reactions.emission.push_back(emission); - } - - return status; - } -}; - -class FirstOrderLossParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::FirstOrderLoss first_order_loss; - - status = ValidateSchema(object, validation::first_order_loss.required_keys, validation::first_order_loss.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.scaling_factor)) - { - first_order_loss.scaling_factor = object[validation::keys.scaling_factor].get(); - } - - if (object.contains(validation::keys.name)) - { - first_order_loss.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - if (status == ConfigParseStatus::Success && reactants.size() > 1) - { - status = ConfigParseStatus::TooManyReactionComponents; - } - - first_order_loss.gas_phase = gas_phase; - first_order_loss.reactants = reactants; - first_order_loss.unknown_properties = - GetComments(object, validation::first_order_loss.required_keys, validation::first_order_loss.optional_keys); - reactions.first_order_loss.push_back(first_order_loss); - } - - return status; - } -}; - -class SimpolPhaseTransferParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::SimpolPhaseTransfer simpol_phase_transfer; - - status = ValidateSchema(object, validation::simpol_phase_transfer.required_keys, validation::simpol_phase_transfer.optional_keys); - if (status == ConfigParseStatus::Success) - { - std::string gas_phase_species = object[validation::keys.gas_phase_species].get(); - std::string aerosol_phase_species = object[validation::keys.aerosol_phase_species].get(); - - if (object.contains(validation::keys.name)) - { - simpol_phase_transfer.name = object[validation::keys.name].get(); - } - - std::vector requested_species{ gas_phase_species, aerosol_phase_species }; - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - auto aerosol_it = - std::find_if(existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); - if (status == ConfigParseStatus::Success && aerosol_it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - else - { - auto phase = *aerosol_it; - auto spec_it = std::find_if( - phase.species.begin(), - phase.species.end(), - [&aerosol_phase_species](const std::string& species) { return species == aerosol_phase_species; }); - if (spec_it == phase.species.end()) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto gas_it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && gas_it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - else - { - auto phase = *gas_it; - auto spec_it = std::find_if( - phase.species.begin(), phase.species.end(), [&gas_phase_species](const std::string& species) { return species == gas_phase_species; }); - if (spec_it == phase.species.end()) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - } - - if (object.contains(validation::keys.B) && object[validation::keys.B].is_array() && object[validation::keys.B].size() == 4) - { - for (size_t i = 0; i < 4; ++i) - { - simpol_phase_transfer.B[i] = object[validation::keys.B][i]; - } - } - - simpol_phase_transfer.gas_phase = gas_phase; - types::ReactionComponent gas_component; - gas_component.species_name = gas_phase_species; - simpol_phase_transfer.gas_phase_species = gas_component; - simpol_phase_transfer.aerosol_phase = aerosol_phase; - types::ReactionComponent aerosol_component; - aerosol_component.species_name = aerosol_phase_species; - simpol_phase_transfer.aerosol_phase_species = aerosol_component; - simpol_phase_transfer.unknown_properties = - GetComments(object, validation::simpol_phase_transfer.required_keys, validation::simpol_phase_transfer.optional_keys); - reactions.simpol_phase_transfer.push_back(simpol_phase_transfer); - } - - return status; - } -}; - -class AqueousEquilibriumParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::AqueousEquilibrium aqueous_equilibrium; - - status = ValidateSchema(object, validation::aqueous_equilibrium.required_keys, validation::aqueous_equilibrium.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.A)) - { - aqueous_equilibrium.A = object[validation::keys.A].get(); - } - if (object.contains(validation::keys.C)) - { - aqueous_equilibrium.C = object[validation::keys.C].get(); - } - - aqueous_equilibrium.k_reverse = object[validation::keys.k_reverse].get(); - - if (object.contains(validation::keys.name)) - { - aqueous_equilibrium.name = object[validation::keys.name].get(); - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].get(); - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - requested_species.push_back(aerosol_phase_water); - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - auto phase_it = std::find_if( - existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); - - if (phase_it != existing_phases.end()) - { - // check if all of the species for this reaction are actually in the aerosol phase - std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, aerosol_phase_species)) - { - status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; - } - } - else - { - status = ConfigParseStatus::UnknownPhase; - } - - aqueous_equilibrium.aerosol_phase = aerosol_phase; - aqueous_equilibrium.aerosol_phase_water = aerosol_phase_water; - aqueous_equilibrium.products = products; - aqueous_equilibrium.reactants = reactants; - aqueous_equilibrium.unknown_properties = - GetComments(object, validation::aqueous_equilibrium.required_keys, validation::aqueous_equilibrium.optional_keys); - reactions.aqueous_equilibrium.push_back(aqueous_equilibrium); - } - - return status; - } -}; - -class WetDepositionParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::WetDeposition wet_deposition; - - status = ValidateSchema(object, validation::wet_deposition.required_keys, validation::wet_deposition.optional_keys); - if (status == ConfigParseStatus::Success) - { - if (object.contains(validation::keys.scaling_factor)) - { - wet_deposition.scaling_factor = object[validation::keys.scaling_factor].get(); - } - - if (object.contains(validation::keys.name)) - { - wet_deposition.name = object[validation::keys.name].get(); - } - - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - - // check if aerosol phase exists - auto it = - std::find_if(existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - wet_deposition.aerosol_phase = aerosol_phase; - wet_deposition.unknown_properties = GetComments(object, validation::wet_deposition.required_keys, validation::wet_deposition.optional_keys); - reactions.wet_deposition.push_back(wet_deposition); - } - - return status; - } -}; - -class HenrysLawParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::HenrysLaw henrys_law; - - status = ValidateSchema(object, validation::henrys_law.required_keys, validation::henrys_law.optional_keys); - if (status == ConfigParseStatus::Success) - { - std::string gas_phase = object[validation::keys.gas_phase].get(); - std::string gas_phase_species = object[validation::keys.gas_phase_species].get(); - std::string aerosol_phase = object[validation::keys.aerosol_phase].get(); - std::string aerosol_phase_species = object[validation::keys.aerosol_phase_species].get(); - std::string aerosol_phase_water = object[validation::keys.aerosol_phase_water].get(); - - if (object.contains(validation::keys.name)) - { - henrys_law.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - requested_species.push_back(gas_phase_species); - requested_species.push_back(aerosol_phase_species); - requested_species.push_back(aerosol_phase_water); - - std::vector requested_aerosol_species; - requested_aerosol_species.push_back(aerosol_phase_species); - requested_aerosol_species.push_back(aerosol_phase_water); - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - auto phase_it = std::find_if( - existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const types::Phase& phase) { return phase.name == aerosol_phase; }); - - if (phase_it != existing_phases.end()) - { - // check if all of the species for this reaction are actually in the aerosol phase - std::vector aerosol_phase_species = { (*phase_it).species.begin(), (*phase_it).species.end() }; - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_aerosol_species, aerosol_phase_species)) - { - status = ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase; - } - } - else - { - status = ConfigParseStatus::UnknownPhase; - } - - henrys_law.gas_phase = gas_phase; - henrys_law.gas_phase_species = gas_phase_species; - henrys_law.aerosol_phase = aerosol_phase; - henrys_law.aerosol_phase_species = aerosol_phase_species; - henrys_law.aerosol_phase_water = aerosol_phase_water; - henrys_law.unknown_properties = GetComments(object, validation::henrys_law.required_keys, validation::henrys_law.optional_keys); - reactions.henrys_law.push_back(henrys_law); - } - - return status; - } -}; - -class ArrheniusParser : public IReactionParser -{ - public: - ConfigParseStatus parse( - const json& object, - const std::vector& existing_species, - const std::vector& existing_phases, - open_atmos::types::Reactions& reactions) override - { - ConfigParseStatus status = ConfigParseStatus::Success; - types::Arrhenius arrhenius; - - status = ValidateSchema(object, validation::arrhenius.required_keys, validation::arrhenius.optional_keys); - if (status == ConfigParseStatus::Success) - { - auto products = ParseReactantsOrProducts(validation::keys.products, object, status); - auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); - - if (object.contains(validation::keys.A)) - { - arrhenius.A = object[validation::keys.A].get(); - } - if (object.contains(validation::keys.B)) - { - arrhenius.B = object[validation::keys.B].get(); - } - if (object.contains(validation::keys.C)) - { - arrhenius.C = object[validation::keys.C].get(); - } - if (object.contains(validation::keys.D)) - { - arrhenius.D = object[validation::keys.D].get(); - } - if (object.contains(validation::keys.E)) - { - arrhenius.E = object[validation::keys.E].get(); - } - if (object.contains(validation::keys.Ea)) - { - if (arrhenius.C != 0) - { - std::cerr << "Ea is specified when C is also specified for an Arrhenius reaction. Pick one." << std::endl; - status = ConfigParseStatus::MutuallyExclusiveOption; - } - // Calculate 'C' using 'Ea' - arrhenius.C = -1 * object[validation::keys.Ea].get() / constants::boltzmann; - } - - if (object.contains(validation::keys.name)) - { - arrhenius.name = object[validation::keys.name].get(); - } - - std::vector requested_species; - for (const auto& spec : products) - { - requested_species.push_back(spec.species_name); - } - for (const auto& spec : reactants) - { - requested_species.push_back(spec.species_name); - } - - if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) - { - status = ConfigParseStatus::ReactionRequiresUnknownSpecies; - } - - std::string gas_phase = object[validation::keys.gas_phase].get(); - auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); - if (status == ConfigParseStatus::Success && it == existing_phases.end()) - { - status = ConfigParseStatus::UnknownPhase; - } - - arrhenius.gas_phase = gas_phase; - arrhenius.products = products; - arrhenius.reactants = reactants; - arrhenius.unknown_properties = GetComments(object, validation::arrhenius.required_keys, validation::arrhenius.optional_keys); - reactions.arrhenius.push_back(arrhenius); - } - - return status; - } -}; - -/// @brief Parses all reactions -/// @param objects A json object that should contain only valid reactions -/// @param existing_species A list of spcecies configured for a mechanism -/// @param existing_phases A list of phases configured for a mechanism -/// @return A pair indicating parsing status and a Reactions struct filled with reactions configured for a mechansim -std::pair -ParseReactions(const json& objects, const std::vector& existing_species, const std::vector& existing_phases) -{ - ConfigParseStatus status = ConfigParseStatus::Success; - types::Reactions reactions; - - std::map> parsers; - parsers[validation::keys.Arrhenius_key] = std::make_unique(); - parsers[validation::keys.HenrysLaw_key] = std::make_unique(); - parsers[validation::keys.WetDeposition_key] = std::make_unique(); - parsers[validation::keys.AqueousPhaseEquilibrium_key] = std::make_unique(); - parsers[validation::keys.SimpolPhaseTransfer_key] = std::make_unique(); - parsers[validation::keys.FirstOrderLoss_key] = std::make_unique(); - parsers[validation::keys.Emission_key] = std::make_unique(); - parsers[validation::keys.CondensedPhasePhotolysis_key] = std::make_unique(); - parsers[validation::keys.Photolysis_key] = std::make_unique(); - parsers[validation::keys.Surface_key] = std::make_unique(); - parsers[validation::keys.Tunneling_key] = std::make_unique(); - parsers[validation::keys.Branched_key] = std::make_unique(); - parsers[validation::keys.Troe_key] = std::make_unique(); - parsers[validation::keys.CondensedPhaseArrhenius_key] = std::make_unique(); - - for (const auto& object : objects) - { - std::string type = object[validation::keys.type].get(); - auto it = parsers.find(type); - if (it != parsers.end()) - { - auto parse_status = it->second->parse(object, existing_species, existing_phases, reactions); - status = parse_status; - if (status != ConfigParseStatus::Success) - { - break; - } - } - else - { - const std::string& msg = "Unknown type: " + type; - throw std::runtime_error(msg); - } - } - - return { status, reactions }; -} - -namespace open_atmos -{ - namespace mechanism_configuration - { - /// @brief Parse a mechanism - /// @param file_path a location on the hard drive containing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair JsonParser::Parse(const std::string& file_path) - { - return JsonParser::Parse(std::filesystem::path(file_path)); - } - - /// @brief Parse a mechanism - /// @param file_path a location on the hard drive containing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair JsonParser::Parse(const std::filesystem::path& file_path) - { - ConfigParseStatus status; - - if (!std::filesystem::exists(file_path) || std::filesystem::is_directory(file_path)) - { - status = ConfigParseStatus::InvalidFilePath; - std::string msg = configParseStatusToString(status); - std::cerr << msg << std::endl; - return { status, types::Mechanism() }; - } - - json config = json::parse(std::ifstream(file_path)); - - return JsonParser::Parse(config); - } - - /// @brief Parse a mechanism - /// @param object A json object representing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair JsonParser::Parse(const nlohmann::json& object) - { - ConfigParseStatus status; - types::Mechanism mechanism; - - status = ValidateSchema(object, validation::mechanism.required_keys, validation::mechanism.optional_keys); - - if (status != ConfigParseStatus::Success) - { - std::string msg = configParseStatusToString(status); - std::cerr << "[" << msg << "] Invalid top level configuration." << std::endl; - return { status, mechanism }; - } - - std::string version = object[validation::keys.version].get(); - - if (version != getVersionString()) - { - status = ConfigParseStatus::InvalidVersion; - std::string msg = configParseStatusToString(status); - std::cerr << "[" << msg << "] This parser supports version " << getVersionString() << " and you requested version " << version - << ". Please download the appropriate version of the parser or switch to the supported format's version." << std::endl; - } - - std::string name = object[validation::keys.name].get(); - mechanism.name = name; - - // parse all of the species at once - auto species_parsing = ParseSpecies(object[validation::keys.species]); - - if (species_parsing.first != ConfigParseStatus::Success) - { - status = species_parsing.first; - std::string msg = configParseStatusToString(status); - std::cerr << "[" << msg << "] Failed to parse the species." << std::endl; - } - - // parse all of the phases at once - auto phases_parsing = ParsePhases(object[validation::keys.phases], species_parsing.second); - - if (phases_parsing.first != ConfigParseStatus::Success) - { - status = phases_parsing.first; - std::string msg = configParseStatusToString(status); - std::cerr << "[" << msg << "] Failed to parse the phases." << std::endl; - } - - // parse all of the reactions at once - auto reactions_parsing = ParseReactions(object[validation::keys.reactions], species_parsing.second, phases_parsing.second); - - if (reactions_parsing.first != ConfigParseStatus::Success) - { - status = reactions_parsing.first; - std::string msg = configParseStatusToString(status); - std::cerr << "[" << msg << "] Failed to parse the reactions." << std::endl; - } - - mechanism.species = species_parsing.second; - mechanism.phases = phases_parsing.second; - mechanism.reactions = reactions_parsing.second; - - return { status, mechanism }; - } - } // namespace mechanism_configuration -} // namespace open_atmos diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..c34648e --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign +// +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + + std::pair + ParseReactions(const YAML::Node& objects, const std::vector& existing_species, const std::vector& existing_phases) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Reactions reactions; + + std::map> parsers; + parsers[validation::keys.Arrhenius_key] = std::make_unique(); + parsers[validation::keys.HenrysLaw_key] = std::make_unique(); + parsers[validation::keys.WetDeposition_key] = std::make_unique(); + parsers[validation::keys.AqueousPhaseEquilibrium_key] = std::make_unique(); + parsers[validation::keys.SimpolPhaseTransfer_key] = std::make_unique(); + parsers[validation::keys.FirstOrderLoss_key] = std::make_unique(); + parsers[validation::keys.Emission_key] = std::make_unique(); + parsers[validation::keys.CondensedPhasePhotolysis_key] = std::make_unique(); + parsers[validation::keys.Photolysis_key] = std::make_unique(); + parsers[validation::keys.Surface_key] = std::make_unique(); + parsers[validation::keys.Tunneling_key] = std::make_unique(); + parsers[validation::keys.Branched_key] = std::make_unique(); + parsers[validation::keys.Troe_key] = std::make_unique(); + parsers[validation::keys.CondensedPhaseArrhenius_key] = std::make_unique(); + + for (const auto& object : objects) + { + std::string type = object[validation::keys.type].as(); + auto it = parsers.find(type); + if (it != parsers.end()) + { + auto parse_status = it->second->parse(object, existing_species, existing_phases, reactions); + status = parse_status; + if (status != ConfigParseStatus::Success) + { + break; + } + } + else + { + const std::string& msg = "Unknown type: " + type; + throw std::runtime_error(msg); + } + } + + return { status, reactions }; + } + + /// @brief Parse a mechanism + /// @param file_path a location on the hard drive containing a mechanism + /// @return A pair containing the parsing status and a mechanism + std::pair Parser::Parse(const std::string& file_path) + { + return Parser::Parse(std::filesystem::path(file_path)); + } + + /// @brief Parse a mechanism + /// @param file_path a location on the hard drive containing a mechanism + /// @return A pair containing the parsing status and a mechanism + std::pair Parser::Parse(const std::filesystem::path& file_path) + { + ConfigParseStatus status; + + if (!std::filesystem::exists(file_path) || std::filesystem::is_directory(file_path)) + { + status = ConfigParseStatus::InvalidFilePath; + std::string msg = configParseStatusToString(status); + std::cerr << msg << std::endl; + return { status, types::Mechanism() }; + } + + YAML::Node config = YAML::LoadFile(file_path.string()); + + return Parser::Parse(config); + } + + /// @brief Parse a mechanism + /// @param node A yaml object representing a mechanism + /// @return A pair containing the parsing status and a mechanism + std::pair Parser::Parse(const YAML::Node& object) + { + ConfigParseStatus status; + types::Mechanism mechanism; + + status = ValidateSchema(object, validation::mechanism.required_keys, validation::mechanism.optional_keys); + + if (status != ConfigParseStatus::Success) + { + std::string msg = configParseStatusToString(status); + std::cerr << "[" << msg << "] Invalid top level configuration." << std::endl; + return { status, mechanism }; + } + + std::string version = object[validation::keys.version].as(); + + if (version != getVersionString()) + { + status = ConfigParseStatus::InvalidVersion; + std::string msg = configParseStatusToString(status); + std::cerr << "[" << msg << "] This parser supports version " << getVersionString() << " and you requested version " << version + << ". Please download the appropriate version of the parser or switch to the supported format's version." << std::endl; + } + + std::string name = object[validation::keys.name].as(); + mechanism.name = name; + + auto species_parsing = ParseSpecies(object[validation::keys.species]); + + if (species_parsing.first != ConfigParseStatus::Success) + { + status = species_parsing.first; + std::string msg = configParseStatusToString(status); + std::cerr << "[" << msg << "] Failed to parse the species." << std::endl; + } + + auto phases_parsing = ParsePhases(object[validation::keys.phases], species_parsing.second); + + if (phases_parsing.first != ConfigParseStatus::Success) + { + status = phases_parsing.first; + std::string msg = configParseStatusToString(status); + std::cerr << "[" << msg << "] Failed to parse the phases." << std::endl; + } + + auto reactions_parsing = ParseReactions(object[validation::keys.reactions], species_parsing.second, phases_parsing.second); + + if (reactions_parsing.first != ConfigParseStatus::Success) + { + status = reactions_parsing.first; + std::string msg = configParseStatusToString(status); + std::cerr << "[" << msg << "] Failed to parse the reactions." << std::endl; + } + + mechanism.species = species_parsing.second; + mechanism.phases = phases_parsing.second; + mechanism.reactions = reactions_parsing.second; + + return { status, mechanism }; + } + } // namespace mechanism_configuration +} // namespace open_atmos \ No newline at end of file diff --git a/src/photolysis_parser.cpp b/src/photolysis_parser.cpp new file mode 100644 index 0000000..260db06 --- /dev/null +++ b/src/photolysis_parser.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus PhotolysisParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Photolysis photolysis; + + status = ValidateSchema(object, validation::photolysis.required_keys, validation::photolysis.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.scaling_factor]) + { + photolysis.scaling_factor = object[validation::keys.scaling_factor].as(); + } + + if (object[validation::keys.name]) + { + photolysis.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + if (status == ConfigParseStatus::Success && reactants.size() > 1) + { + status = ConfigParseStatus::TooManyReactionComponents; + } + + photolysis.gas_phase = gas_phase; + photolysis.products = products; + photolysis.reactants = reactants; + photolysis.unknown_properties = GetComments(object, validation::photolysis.required_keys, validation::photolysis.optional_keys); + reactions.photolysis.push_back(photolysis); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/simpol_phase_transfer_parser.cpp b/src/simpol_phase_transfer_parser.cpp new file mode 100644 index 0000000..8deb744 --- /dev/null +++ b/src/simpol_phase_transfer_parser.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus SimpolPhaseTransferParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::SimpolPhaseTransfer simpol_phase_transfer; + + status = ValidateSchema(object, validation::simpol_phase_transfer.required_keys, validation::simpol_phase_transfer.optional_keys); + if (status == ConfigParseStatus::Success) + { + std::string gas_phase_species = object[validation::keys.gas_phase_species].as(); + std::string aerosol_phase_species = object[validation::keys.aerosol_phase_species].as(); + + if (object[validation::keys.name]) + { + simpol_phase_transfer.name = object[validation::keys.name].as(); + } + + std::vector requested_species{ gas_phase_species, aerosol_phase_species }; + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + auto aerosol_it = + std::find_if(existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); + if (status == ConfigParseStatus::Success && aerosol_it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + else + { + auto phase = *aerosol_it; + auto spec_it = std::find_if( + phase.species.begin(), + phase.species.end(), + [&aerosol_phase_species](const std::string& species) { return species == aerosol_phase_species; }); + if (spec_it == phase.species.end()) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto gas_it = + std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && gas_it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + else + { + auto phase = *gas_it; + auto spec_it = std::find_if( + phase.species.begin(), phase.species.end(), [&gas_phase_species](const std::string& species) { return species == gas_phase_species; }); + if (spec_it == phase.species.end()) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + } + + if (object[validation::keys.B] && object[validation::keys.B].IsSequence() && object[validation::keys.B].size() == 4) + { + for (size_t i = 0; i < 4; ++i) + { + simpol_phase_transfer.B[i] = object[validation::keys.B][i].as(); + } + } + + simpol_phase_transfer.gas_phase = gas_phase; + types::ReactionComponent gas_component; + gas_component.species_name = gas_phase_species; + simpol_phase_transfer.gas_phase_species = gas_component; + simpol_phase_transfer.aerosol_phase = aerosol_phase; + types::ReactionComponent aerosol_component; + aerosol_component.species_name = aerosol_phase_species; + simpol_phase_transfer.aerosol_phase_species = aerosol_component; + simpol_phase_transfer.unknown_properties = + GetComments(object, validation::simpol_phase_transfer.required_keys, validation::simpol_phase_transfer.optional_keys); + reactions.simpol_phase_transfer.push_back(simpol_phase_transfer); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/surface_parser.cpp b/src/surface_parser.cpp new file mode 100644 index 0000000..8195c75 --- /dev/null +++ b/src/surface_parser.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus SurfaceParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Surface surface; + + status = ValidateSchema(object, validation::surface.required_keys, validation::surface.optional_keys); + if (status == ConfigParseStatus::Success) + { + std::string gas_phase_species = object[validation::keys.gas_phase_species].as(); + + auto products = ParseReactantsOrProducts(validation::keys.gas_phase_products, object, status); + + if (object[validation::keys.reaction_probability]) + { + surface.reaction_probability = object[validation::keys.reaction_probability].as(); + } + + if (object[validation::keys.name]) + { + surface.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + requested_species.push_back(gas_phase_species); + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + auto it = + std::find_if(existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + surface.gas_phase = object[validation::keys.gas_phase].as(); + surface.aerosol_phase = aerosol_phase; + surface.gas_phase_products = products; + types::ReactionComponent component; + component.species_name = gas_phase_species; + surface.gas_phase_species = component; + surface.unknown_properties = GetComments(object, validation::surface.required_keys, validation::surface.optional_keys); + reactions.surface.push_back(surface); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/troe_parser.cpp b/src/troe_parser.cpp new file mode 100644 index 0000000..6a36aae --- /dev/null +++ b/src/troe_parser.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus TroeParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Troe troe; + + status = ValidateSchema(object, validation::troe.required_keys, validation::troe.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.k0_A]) + { + troe.k0_A = object[validation::keys.k0_A].as(); + } + if (object[validation::keys.k0_B]) + { + troe.k0_B = object[validation::keys.k0_B].as(); + } + if (object[validation::keys.k0_C]) + { + troe.k0_C = object[validation::keys.k0_C].as(); + } + if (object[validation::keys.kinf_A]) + { + troe.kinf_A = object[validation::keys.kinf_A].as(); + } + if (object[validation::keys.kinf_B]) + { + troe.kinf_B = object[validation::keys.kinf_B].as(); + } + if (object[validation::keys.kinf_C]) + { + troe.kinf_C = object[validation::keys.kinf_C].as(); + } + if (object[validation::keys.Fc]) + { + troe.Fc = object[validation::keys.Fc].as(); + } + if (object[validation::keys.N]) + { + troe.N = object[validation::keys.N].as(); + } + + if (object[validation::keys.name]) + { + troe.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + troe.gas_phase = gas_phase; + troe.products = products; + troe.reactants = reactants; + troe.unknown_properties = GetComments(object, validation::troe.required_keys, validation::troe.optional_keys); + reactions.troe.push_back(troe); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/tunneling_parser.cpp b/src/tunneling_parser.cpp new file mode 100644 index 0000000..14dc92b --- /dev/null +++ b/src/tunneling_parser.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus TunnelingParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::Tunneling tunneling; + + status = ValidateSchema(object, validation::tunneling.required_keys, validation::tunneling.optional_keys); + if (status == ConfigParseStatus::Success) + { + auto products = ParseReactantsOrProducts(validation::keys.products, object, status); + auto reactants = ParseReactantsOrProducts(validation::keys.reactants, object, status); + + if (object[validation::keys.A]) + { + tunneling.A = object[validation::keys.A].as(); + } + if (object[validation::keys.B]) + { + tunneling.B = object[validation::keys.B].as(); + } + if (object[validation::keys.C]) + { + tunneling.C = object[validation::keys.C].as(); + } + + if (object[validation::keys.name]) + { + tunneling.name = object[validation::keys.name].as(); + } + + std::vector requested_species; + for (const auto& spec : products) + { + requested_species.push_back(spec.species_name); + } + for (const auto& spec : reactants) + { + requested_species.push_back(spec.species_name); + } + + if (status == ConfigParseStatus::Success && RequiresUnknownSpecies(requested_species, existing_species)) + { + status = ConfigParseStatus::ReactionRequiresUnknownSpecies; + } + + std::string gas_phase = object[validation::keys.gas_phase].as(); + auto it = std::find_if(existing_phases.begin(), existing_phases.end(), [&gas_phase](const auto& phase) { return phase.name == gas_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + tunneling.gas_phase = gas_phase; + tunneling.products = products; + tunneling.reactants = reactants; + tunneling.unknown_properties = GetComments(object, validation::tunneling.required_keys, validation::tunneling.optional_keys); + reactions.tunneling.push_back(tunneling); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..e0b247d --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,207 @@ +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + + std::unordered_map + GetComments(const YAML::Node& object, const std::vector& required_keys, const std::vector& optional_keys) + { + std::unordered_map unknown_properties; + const std::string comment_start = "__"; + for (const auto& key : object) + { + std::string key_str = key.first.as(); + if (key_str.compare(0, comment_start.size(), comment_start) == 0) + { + YAML::Emitter emitter; + emitter << YAML::DoubleQuoted << YAML::Flow // json style output + << key.second; + unknown_properties[key_str] = emitter.c_str(); + } + } + return unknown_properties; + } + + ConfigParseStatus + ValidateSchema(const YAML::Node& object, const std::vector& required_keys, const std::vector& optional_keys) + { + if (!object || object.IsNull()) + { + return ConfigParseStatus::Success; + } + + std::vector sorted_object_keys; + for (const auto& key : object) + { + sorted_object_keys.push_back(key.first.as()); + } + + auto sorted_required_keys = required_keys; + auto sorted_optional_keys = optional_keys; + std::sort(sorted_object_keys.begin(), sorted_object_keys.end()); + std::sort(sorted_required_keys.begin(), sorted_required_keys.end()); + std::sort(sorted_optional_keys.begin(), sorted_optional_keys.end()); + + std::vector difference; + std::set_difference( + sorted_object_keys.begin(), + sorted_object_keys.end(), + sorted_required_keys.begin(), + sorted_required_keys.end(), + std::back_inserter(difference)); + + if (difference.size() != (sorted_object_keys.size() - required_keys.size())) + { + std::vector missing_keys; + std::set_difference( + sorted_required_keys.begin(), + sorted_required_keys.end(), + sorted_object_keys.begin(), + sorted_object_keys.end(), + std::back_inserter(missing_keys)); + for (auto& key : missing_keys) + std::cerr << "Missing required key '" << key << "' in object: " << object << std::endl; + + return ConfigParseStatus::RequiredKeyNotFound; + } + + std::vector remaining; + std::set_difference( + difference.begin(), difference.end(), sorted_optional_keys.begin(), sorted_optional_keys.end(), std::back_inserter(remaining)); + + for (auto& key : remaining) + { + if (key.find("__") == std::string::npos) + { + std::cerr << "Non-standard key '" << key << "' found in object" << object << std::endl; + + return ConfigParseStatus::InvalidKey; + } + } + return ConfigParseStatus::Success; + } + + std::pair> ParseSpecies(const YAML::Node& objects) + { + ConfigParseStatus status = ConfigParseStatus::Success; + std::vector all_species; + + for (const auto& object : objects) + { + types::Species species; + status = ValidateSchema(object, validation::species.required_keys, validation::species.optional_keys); + if (status != ConfigParseStatus::Success) + { + break; + } + + std::string name = object[validation::keys.name].as(); + + std::map numerical_properties{}; + for (const auto& key : validation::species.optional_keys) + { + if (object[key]) + { + double val = object[key].as(); + numerical_properties[key] = val; + } + } + + species.name = name; + species.optional_numerical_properties = numerical_properties; + species.unknown_properties = GetComments(object, validation::species.required_keys, validation::species.optional_keys); + + all_species.push_back(species); + } + + if (!ContainsUniqueObjectsByName(all_species)) + status = ConfigParseStatus::DuplicateSpeciesDetected; + + return { status, all_species }; + } + + std::pair> ParsePhases(const YAML::Node& objects, const std::vector existing_species) + { + ConfigParseStatus status = ConfigParseStatus::Success; + std::vector all_phases; + + for (const auto& object : objects) + { + types::Phase phase; + status = ValidateSchema(object, validation::phase.required_keys, validation::phase.optional_keys); + if (status != ConfigParseStatus::Success) + { + break; + } + + std::string name = object[validation::keys.name].as(); + + std::vector species{}; + for (const auto& spec : object[validation::keys.species]) + { + species.push_back(spec.as()); + } + + phase.name = name; + phase.species = species; + phase.unknown_properties = GetComments(object, validation::phase.required_keys, validation::phase.optional_keys); + + if (RequiresUnknownSpecies(species, existing_species)) + { + status = ConfigParseStatus::PhaseRequiresUnknownSpecies; + break; + } + + all_phases.push_back(phase); + } + + if (status == ConfigParseStatus::Success && !ContainsUniqueObjectsByName(all_phases)) + status = ConfigParseStatus::DuplicatePhasesDetected; + + return { status, all_phases }; + } + + std::pair ParseReactionComponent(const YAML::Node& object) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::ReactionComponent component; + + status = ValidateSchema(object, validation::reaction_component.required_keys, validation::reaction_component.optional_keys); + if (status == ConfigParseStatus::Success) + { + std::string species_name = object[validation::keys.species_name].as(); + double coefficient = 1; + if (object[validation::keys.coefficient]) + { + coefficient = object[validation::keys.coefficient].as(); + } + + component.species_name = species_name; + component.coefficient = coefficient; + component.unknown_properties = + GetComments(object, validation::reaction_component.required_keys, validation::reaction_component.optional_keys); + } + + return { status, component }; + } + + std::vector ParseReactantsOrProducts(const std::string& key, const YAML::Node& object, ConfigParseStatus& status) + { + std::vector result{}; + for (const auto& product : object[key]) + { + auto component_parse = ParseReactionComponent(product); + status = component_parse.first; + if (status != ConfigParseStatus::Success) + { + break; + } + result.push_back(component_parse.second); + } + return result; + } + + } // namespace mechanism_configuration +} // namespace open_atmos \ No newline at end of file diff --git a/src/validation.cpp b/src/validation.cpp new file mode 100644 index 0000000..c6e5db1 --- /dev/null +++ b/src/validation.cpp @@ -0,0 +1,27 @@ +#include + +namespace open_atmos +{ + namespace validation + { + struct Keys keys; + struct Mechanism mechanism; + struct Species species; + struct Phase phase; + struct ReactionComponent reaction_component; + struct Arrhenius arrhenius; + struct CondensedPhaseArrhenius condensed_phase_arrhenius; + struct Troe troe; + struct Branched branched; + struct Tunneling tunneling; + struct Surface surface; + struct Photolysis photolysis; + struct CondensedPhasePhotolysis condensed_phase_photolysis; + struct Emission emission; + struct FirstOrderLoss first_order_loss; + struct SimpolPhaseTransfer simpol_phase_transfer; + struct WetDeposition wet_deposition; + struct HenrysLaw henrys_law; + struct AqueousEquilibrium aqueous_equilibrium; + } // namespace validation +} // namespace open_atmos diff --git a/src/wet_deposition_parser.cpp b/src/wet_deposition_parser.cpp new file mode 100644 index 0000000..6dd7ea7 --- /dev/null +++ b/src/wet_deposition_parser.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +namespace open_atmos +{ + namespace mechanism_configuration + { + ConfigParseStatus WetDepositionParser::parse( + const YAML::Node& object, + const std::vector& existing_species, + const std::vector& existing_phases, + open_atmos::types::Reactions& reactions) + { + ConfigParseStatus status = ConfigParseStatus::Success; + types::WetDeposition wet_deposition; + + status = ValidateSchema(object, validation::wet_deposition.required_keys, validation::wet_deposition.optional_keys); + if (status == ConfigParseStatus::Success) + { + if (object[validation::keys.scaling_factor]) + { + wet_deposition.scaling_factor = object[validation::keys.scaling_factor].as(); + } + + if (object[validation::keys.name]) + { + wet_deposition.name = object[validation::keys.name].as(); + } + + std::string aerosol_phase = object[validation::keys.aerosol_phase].as(); + + auto it = std::find_if( + existing_phases.begin(), existing_phases.end(), [&aerosol_phase](const auto& phase) { return phase.name == aerosol_phase; }); + if (status == ConfigParseStatus::Success && it == existing_phases.end()) + { + status = ConfigParseStatus::UnknownPhase; + } + + wet_deposition.aerosol_phase = aerosol_phase; + wet_deposition.unknown_properties = GetComments(object, validation::wet_deposition.required_keys, validation::wet_deposition.optional_keys); + reactions.wet_deposition.push_back(wet_deposition); + } + + return status; + } + } // namespace mechanism_configuration +} // namespace open_atmos diff --git a/src/yaml_parser.cpp b/src/yaml_parser.cpp deleted file mode 100644 index 39abf3b..0000000 --- a/src/yaml_parser.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2023-2024 National Center for Atmospheric Research, University of Illinois at Urbana-Champaign -// -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include - -namespace open_atmos -{ - namespace mechanism_configuration - { - /// @brief Parse a mechanism - /// @param file_path a location on the hard drive containing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair YamlParser::Parse(const std::string& file_path) - { - throw std::runtime_error("Not implemented"); - } - - /// @brief Parse a mechanism - /// @param file_path a location on the hard drive containing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair YamlParser::Parse(const std::filesystem::path& file_path) - { - throw std::runtime_error("Not implemented"); - } - - /// @brief Parse a mechanism - /// @param node A yaml object representing a mechanism - /// @return A pair containing the parsing status and a mechanism - std::pair YamlParser::Parse(const YAML::Node& node) - { - throw std::runtime_error("Not implemented"); - } - } // namespace mechanism_configuration -} // namespace open_atmos diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index c1eac75..fc5779b 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -5,10 +5,4 @@ include(test_util) ################################################################################ # Tests -if(ENABLE_JSON) - create_standard_test(NAME json_parser SOURCES test_json_parser.cpp) -endif() - -if(ENABLE_YAML) - create_standard_test(NAME yaml_parser SOURCES test_yaml_parser.cpp) -endif() \ No newline at end of file +create_standard_test(NAME parser SOURCES test_parser.cpp) \ No newline at end of file diff --git a/test/integration/test_json_parser.cpp b/test/integration/test_json_parser.cpp deleted file mode 100644 index c7e4195..0000000 --- a/test/integration/test_json_parser.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, ParsesFullConfiguration) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("examples/full_configuration.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - EXPECT_EQ(mechanism.name, "Full Configuration"); - EXPECT_EQ(mechanism.species.size(), 11); - EXPECT_EQ(mechanism.phases.size(), 4); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius.size(), 2); - EXPECT_EQ(mechanism.reactions.branched.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius.size(), 2); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis.size(), 1); - EXPECT_EQ(mechanism.reactions.emission.size(), 1); - EXPECT_EQ(mechanism.reactions.first_order_loss.size(), 1); - EXPECT_EQ(mechanism.reactions.henrys_law.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis.size(), 1); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer.size(), 1); - EXPECT_EQ(mechanism.reactions.surface.size(), 1); - EXPECT_EQ(mechanism.reactions.surface.size(), 1); - EXPECT_EQ(mechanism.reactions.troe.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling.size(), 1); -} - -TEST(JsonParser, ParserReportsBadFiles) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("examples/_missing_configuration.json")); - EXPECT_EQ(status, ConfigParseStatus::InvalidFilePath); -} \ No newline at end of file diff --git a/test/integration/test_parser.cpp b/test/integration/test_parser.cpp new file mode 100644 index 0000000..da0a577 --- /dev/null +++ b/test/integration/test_parser.cpp @@ -0,0 +1,48 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, ParsesFullConfiguration) +{ + Parser parser; + std::vector extensions = { ".yaml", ".json" }; + for (auto& extension : extensions) + { + std::string path = "examples/full_configuration" + extension; + auto [status, mechanism] = parser.Parse(path); + EXPECT_EQ(status, ConfigParseStatus::Success); + EXPECT_EQ(mechanism.name, "Full Configuration"); + EXPECT_EQ(mechanism.species.size(), 11); + EXPECT_EQ(mechanism.phases.size(), 4); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius.size(), 2); + EXPECT_EQ(mechanism.reactions.branched.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius.size(), 2); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis.size(), 1); + EXPECT_EQ(mechanism.reactions.emission.size(), 1); + EXPECT_EQ(mechanism.reactions.first_order_loss.size(), 1); + EXPECT_EQ(mechanism.reactions.henrys_law.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis.size(), 1); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer.size(), 1); + EXPECT_EQ(mechanism.reactions.surface.size(), 1); + EXPECT_EQ(mechanism.reactions.surface.size(), 1); + EXPECT_EQ(mechanism.reactions.troe.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling.size(), 1); + } +} + +TEST(Parser, ParserReportsBadFiles) +{ + Parser parser; + std::vector extensions = { ".yaml", ".json" }; + for (auto& extension : extensions) + { + std::string path = "examples/_missing_configuration" + extension; + auto [status, mechanism] = parser.Parse(path); + EXPECT_EQ(status, ConfigParseStatus::InvalidFilePath); + } +} \ No newline at end of file diff --git a/test/integration/test_yaml_parser.cpp b/test/integration/test_yaml_parser.cpp deleted file mode 100644 index 6bc339a..0000000 --- a/test/integration/test_yaml_parser.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(YamlParser, ParsesFullConfiguration) -{ - YamlParser parser; - EXPECT_ANY_THROW(parser.Parse(std::string("examples/full_configuration.yaml"))); -} - -TEST(YamlParser, ParserReportsBadFiles) -{ - YamlParser parser; - EXPECT_ANY_THROW(parser.Parse(std::string("examples/_missing_configuration.yaml"))); -} \ No newline at end of file diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b1ab6ab..7e4ce65 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,7 +1,30 @@ -if(ENABLE_JSON) - add_subdirectory(json) -endif() +################################################################################ +# Test utilities -if(ENABLE_YAML) - add_subdirectory(yaml) -endif() \ No newline at end of file +include(test_util) + +################################################################################ +# Tests + +create_standard_test(NAME parse_arrhenius SOURCES test_parse_arrhenius.cpp) +create_standard_test(NAME parse_branched SOURCES test_parse_branched.cpp) +create_standard_test(NAME parse_condensed_phase_arrhenius SOURCES test_parse_condensed_phase_arrhenius.cpp) +create_standard_test(NAME parse_condensed_phase_photolysis SOURCES test_parse_condensed_phase_photolysis.cpp) +create_standard_test(NAME parse_emission SOURCES test_parse_emission.cpp) +create_standard_test(NAME parse_first_order_loss SOURCES test_parse_first_order_loss.cpp) +create_standard_test(NAME parse_henrys_law SOURCES test_parse_henrys_law.cpp) +create_standard_test(NAME parse_phases SOURCES test_parse_phases.cpp) +create_standard_test(NAME parse_photolysis SOURCES test_parse_photolysis.cpp) +create_standard_test(NAME parse_species SOURCES test_parse_species.cpp) +create_standard_test(NAME parse_surface SOURCES test_parse_surface.cpp) +create_standard_test(NAME parse_troe SOURCES test_parse_troe.cpp) +create_standard_test(NAME parse_tunneling SOURCES test_parse_tunneling.cpp) +create_standard_test(NAME parse_simpol_phase_transfer SOURCES test_parse_simpol_phase_transfer.cpp) +create_standard_test(NAME parse_aqueous_equilibrium SOURCES test_parse_aqueous_equilibrium.cpp) +create_standard_test(NAME parse_wet_deposition SOURCES test_parse_wet_deposition.cpp) + +################################################################################ +# Copy test data + +add_custom_target(copy_unit_test_configs ALL ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/unit_configs ${CMAKE_BINARY_DIR}/unit_configs) \ No newline at end of file diff --git a/test/unit/json/CMakeLists.txt b/test/unit/json/CMakeLists.txt deleted file mode 100644 index 7e4ce65..0000000 --- a/test/unit/json/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -################################################################################ -# Test utilities - -include(test_util) - -################################################################################ -# Tests - -create_standard_test(NAME parse_arrhenius SOURCES test_parse_arrhenius.cpp) -create_standard_test(NAME parse_branched SOURCES test_parse_branched.cpp) -create_standard_test(NAME parse_condensed_phase_arrhenius SOURCES test_parse_condensed_phase_arrhenius.cpp) -create_standard_test(NAME parse_condensed_phase_photolysis SOURCES test_parse_condensed_phase_photolysis.cpp) -create_standard_test(NAME parse_emission SOURCES test_parse_emission.cpp) -create_standard_test(NAME parse_first_order_loss SOURCES test_parse_first_order_loss.cpp) -create_standard_test(NAME parse_henrys_law SOURCES test_parse_henrys_law.cpp) -create_standard_test(NAME parse_phases SOURCES test_parse_phases.cpp) -create_standard_test(NAME parse_photolysis SOURCES test_parse_photolysis.cpp) -create_standard_test(NAME parse_species SOURCES test_parse_species.cpp) -create_standard_test(NAME parse_surface SOURCES test_parse_surface.cpp) -create_standard_test(NAME parse_troe SOURCES test_parse_troe.cpp) -create_standard_test(NAME parse_tunneling SOURCES test_parse_tunneling.cpp) -create_standard_test(NAME parse_simpol_phase_transfer SOURCES test_parse_simpol_phase_transfer.cpp) -create_standard_test(NAME parse_aqueous_equilibrium SOURCES test_parse_aqueous_equilibrium.cpp) -create_standard_test(NAME parse_wet_deposition SOURCES test_parse_wet_deposition.cpp) - -################################################################################ -# Copy test data - -add_custom_target(copy_unit_test_configs ALL ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/unit_configs ${CMAKE_BINARY_DIR}/unit_configs) \ No newline at end of file diff --git a/test/unit/json/test_parse_aqueous_equilibrium.cpp b/test/unit/json/test_parse_aqueous_equilibrium.cpp deleted file mode 100644 index 9fd9c97..0000000 --- a/test/unit/json/test_parse_aqueous_equilibrium.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidAqueousEquilibriumReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium.size(), 2); - - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].name, "my aqueous eq"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].aerosol_phase, "aerosol"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].A, 1.14e-2); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].C, 2300.0); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].k_reverse, 0.32); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants[0].coefficient, 2); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products.size(), 2); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[1].coefficient, 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].unknown_properties["__comment"], "\"GIF is pronounced with a hard g\""); - - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].aerosol_phase, "aerosol"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].A, 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].C, 0); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].k_reverse, 0.32); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants[0].coefficient, 2); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products.size(), 2); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[1].coefficient, 1); -} - -TEST(JsonParser, AqueousEquilibriumDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, AqueousEquilibriumDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, AqueousEquilibriumDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_arrhenius.cpp b/test/unit/json/test_parse_arrhenius.cpp deleted file mode 100644 index 863fa06..0000000 --- a/test/unit/json/test_parse_arrhenius.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidArrheniusReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.arrhenius.size(), 3); - - EXPECT_EQ(mechanism.reactions.arrhenius[0].name, "my arrhenius"); - EXPECT_EQ(mechanism.reactions.arrhenius[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.arrhenius[0].A, 32.1); - EXPECT_EQ(mechanism.reactions.arrhenius[0].B, -2.3); - EXPECT_EQ(mechanism.reactions.arrhenius[0].C, 102.3); - EXPECT_EQ(mechanism.reactions.arrhenius[0].D, 63.4); - EXPECT_EQ(mechanism.reactions.arrhenius[0].E, -1.3); - EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.arrhenius[0].products.size(), 2); - EXPECT_EQ(mechanism.reactions.arrhenius[0].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.arrhenius[0].products[0].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.arrhenius[0].products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.arrhenius[0].products[1].coefficient, 0.3); - EXPECT_EQ(mechanism.reactions.arrhenius[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[0].unknown_properties["__solver_param"], "0.1"); - - EXPECT_EQ(mechanism.reactions.arrhenius[1].name, "my arrhenius2"); - EXPECT_EQ(mechanism.reactions.arrhenius[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.arrhenius[1].A, 3.1); - EXPECT_EQ(mechanism.reactions.arrhenius[1].B, -0.3); - EXPECT_EQ(mechanism.reactions.arrhenius[1].C, 12.3); - EXPECT_EQ(mechanism.reactions.arrhenius[1].D, 6.4); - EXPECT_EQ(mechanism.reactions.arrhenius[1].E, -0.3); - EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants.size(), 2); - EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[0].coefficient, 2); - EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[1].species_name, "B"); - EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[1].coefficient, 0.1); - EXPECT_EQ(mechanism.reactions.arrhenius[1].products.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].coefficient, 0.5); - EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].unknown_properties["__optional thing"], "\"hello\""); - - EXPECT_EQ(mechanism.reactions.arrhenius[2].name, ""); - EXPECT_EQ(mechanism.reactions.arrhenius[2].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.arrhenius[2].A, 1); - EXPECT_EQ(mechanism.reactions.arrhenius[2].B, 0); - EXPECT_EQ(mechanism.reactions.arrhenius[2].C, 0); - EXPECT_EQ(mechanism.reactions.arrhenius[2].D, 300); - EXPECT_EQ(mechanism.reactions.arrhenius[2].E, 0); - EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.arrhenius[2].products.size(), 1); - EXPECT_EQ(mechanism.reactions.arrhenius[2].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.arrhenius[2].products[0].coefficient, 1); -} - -TEST(JsonParser, ArrheniusDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, ArrheniusDetectsMutuallyExclusiveOptions) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/mutually_exclusive.json")); - EXPECT_EQ(status, ConfigParseStatus::MutuallyExclusiveOption); -} - -TEST(JsonParser, ArrheniusDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, ArrheniusDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_branched.cpp b/test/unit/json/test_parse_branched.cpp deleted file mode 100644 index dfd4069..0000000 --- a/test/unit/json/test_parse_branched.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidBranchedReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.branched.size(), 1); - - EXPECT_EQ(mechanism.reactions.branched[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.branched[0].name, "my branched"); - EXPECT_EQ(mechanism.reactions.branched[0].X, 1.2e-4); - EXPECT_EQ(mechanism.reactions.branched[0].Y, 167); - EXPECT_EQ(mechanism.reactions.branched[0].a0, 0.15); - EXPECT_EQ(mechanism.reactions.branched[0].n, 9); - EXPECT_EQ(mechanism.reactions.branched[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.branched[0].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.branched[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products.size(), 1); - EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].unknown_properties["__thing"], "\"hi\""); - EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products.size(), 2); - EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[0].coefficient, 0.2); - EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[1].species_name, "A"); - EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[1].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.branched[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.branched[0].unknown_properties["__comment"], "\"thing\""); -} - -TEST(JsonParser, BranchedDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, BranchedDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, BranchedDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_condensed_phase_arrhenius.cpp b/test/unit/json/test_parse_condensed_phase_arrhenius.cpp deleted file mode 100644 index 7515a11..0000000 --- a/test/unit/json/test_parse_condensed_phase_arrhenius.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidCondensedPhaseArrheniusReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius.size(), 3); - - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].name, "my arrhenius"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].A, 32.1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].B, -2.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].C, 102.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].D, 63.4); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].E, -1.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products.size(), 2); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[0].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[1].coefficient, 0.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].unknown_properties["__solver_param"], "0.1"); - - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].name, "my arrhenius2"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].A, 3.1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].B, -0.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].C, 12.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].D, 6.4); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].E, -0.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants.size(), 2); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[0].coefficient, 2); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[1].species_name, "B"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[1].coefficient, 0.1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].coefficient, 0.5); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].unknown_properties["__optional thing"], "\"hello\""); - - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].name, ""); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].A, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].B, 0); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].C, 0); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].D, 300); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].E, 0); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products[0].coefficient, 1); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsMutuallyExclusiveOptions) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.json")); - EXPECT_EQ(status, ConfigParseStatus::MutuallyExclusiveOption); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsUnknownAerosolPhaseWater) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsWhenRequestedSpeciesAreNotInAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsMissingPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_condensed_phase_photolysis.cpp b/test/unit/json/test_parse_condensed_phase_photolysis.cpp deleted file mode 100644 index cbe151c..0000000 --- a/test/unit/json/test_parse_condensed_phase_photolysis.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidCondensedPhasePhotolysisReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis.size(), 2); - - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].name, "my condensed phase photolysis"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].scaling_factor_, 12.3); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].unknown_properties["__comment"], "\"hi\""); - - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].scaling_factor_, 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants[0].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products.size(), 1); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products[0].coefficient, 0.2); -} - -TEST(JsonParser, CondensedPhasePhotolysisDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, CondensedPhasePhotolysisDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::InvalidKey); -} - -TEST(JsonParser, CondensedPhasePhotolysisDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, CondensedPhasePhotolysisDoesNotAcceptMoreThanOneReactant) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.json")); - EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); -} - -TEST(JsonParser, CondensedPhasePhotolysisDetectsWhenRequestedSpeciesAreNotInAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); -} - -TEST(JsonParser, CondensedPhaseArrheniusDetectsUnknownAerosolPhaseWater) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_emission.cpp b/test/unit/json/test_parse_emission.cpp deleted file mode 100644 index aaad23f..0000000 --- a/test/unit/json/test_parse_emission.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidEmissionReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.emission.size(), 2); - - EXPECT_EQ(mechanism.reactions.emission[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.emission[0].name, "my emission"); - EXPECT_EQ(mechanism.reactions.emission[0].scaling_factor, 12.3); - EXPECT_EQ(mechanism.reactions.emission[0].products.size(), 1); - EXPECT_EQ(mechanism.reactions.emission[0].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.emission[0].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.emission[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.emission[0].unknown_properties["__comment"], "\"Dr. Pepper outranks any other soda\""); - - EXPECT_EQ(mechanism.reactions.emission[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.emission[1].scaling_factor, 1); - EXPECT_EQ(mechanism.reactions.emission[1].products.size(), 1); - EXPECT_EQ(mechanism.reactions.emission[1].products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.emission[1].products[0].coefficient, 1); -} - -TEST(JsonParser, EmissionDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, EmissionDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, EmissionDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_first_order_loss.cpp b/test/unit/json/test_parse_first_order_loss.cpp deleted file mode 100644 index 7de616f..0000000 --- a/test/unit/json/test_parse_first_order_loss.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidFirstOrderLossReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.first_order_loss.size(), 2); - - EXPECT_EQ(mechanism.reactions.first_order_loss[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].name, "my first order loss"); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].scaling_factor, 12.3); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.first_order_loss[0].unknown_properties["__comment"], "\"Strawberries are the superior fruit\""); - - EXPECT_EQ(mechanism.reactions.first_order_loss[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.first_order_loss[1].scaling_factor, 1); - EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants[0].coefficient, 1); -} - -TEST(JsonParser, FirstOrderLossDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, FirstOrderLossDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, FirstOrderLossDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, FirstOrderLossDetectsMoreThanOneSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/too_many_reactants.json")); - EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_henrys_law.cpp b/test/unit/json/test_parse_henrys_law.cpp deleted file mode 100644 index e0d4dea..0000000 --- a/test/unit/json/test_parse_henrys_law.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidHenrysLawReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.henrys_law.size(), 2); - - EXPECT_EQ(mechanism.reactions.henrys_law[0].name, "my henry's law"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].gas_phase_species, "A"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase_species, "B"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.henrys_law[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.henrys_law[0].unknown_properties["__comment"], "\"hi\""); - - EXPECT_EQ(mechanism.reactions.henrys_law[1].name, ""); - EXPECT_EQ(mechanism.reactions.henrys_law[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.henrys_law[1].gas_phase_species, "A"); - EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase, "aqueous aerosol"); - EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase_species, "B"); - EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase_water, "H2O_aq"); - EXPECT_EQ(mechanism.reactions.henrys_law[1].unknown_properties.size(), 0); -} - -TEST(JsonParser, HenrysLawDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, HenrysLawDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, HenrysLawDetectsUnknownAerosolPhaseWater) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, HenrysLawDetectsWhenRequestedSpeciesAreNotInAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_phases.cpp b/test/unit/json/test_parse_phases.cpp deleted file mode 100644 index dab9805..0000000 --- a/test/unit/json/test_parse_phases.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidPhases) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/valid_phases.json")); - - EXPECT_EQ(status, ConfigParseStatus::Success); - EXPECT_EQ(mechanism.species.size(), 3); - EXPECT_EQ(mechanism.phases.size(), 2); - - EXPECT_EQ(mechanism.phases[0].name, "gas"); - EXPECT_EQ(mechanism.phases[0].species.size(), 2); - EXPECT_EQ(mechanism.phases[0].species[0], "A"); - EXPECT_EQ(mechanism.phases[0].species[1], "B"); - EXPECT_EQ(mechanism.phases[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.phases[0].unknown_properties["__other"], "\"key\""); - - EXPECT_EQ(mechanism.phases[1].name, "aerosols"); - EXPECT_EQ(mechanism.phases[1].species.size(), 1); - EXPECT_EQ(mechanism.phases[1].species[0], "C"); - EXPECT_EQ(mechanism.phases[1].unknown_properties.size(), 2); - EXPECT_EQ(mechanism.phases[1].unknown_properties["__other1"], "\"key1\""); - EXPECT_EQ(mechanism.phases[1].unknown_properties["__other2"], "\"key2\""); -} - -TEST(JsonParser, DetectsDuplicatePhases) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/duplicate_phases.json")); - - EXPECT_EQ(status, ConfigParseStatus::DuplicatePhasesDetected); -} - -TEST(JsonParser, DetectsMissingRequiredKeys) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/missing_required_key.json")); - - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, DetectsInvalidKeys) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/invalid_key.json")); - - EXPECT_EQ(status, ConfigParseStatus::InvalidKey); -} - -TEST(JsonParser, DetectsPhaseRequestingUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/unknown_species.json")); - - EXPECT_EQ(status, ConfigParseStatus::PhaseRequiresUnknownSpecies); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_photolysis.cpp b/test/unit/json/test_parse_photolysis.cpp deleted file mode 100644 index 977fc48..0000000 --- a/test/unit/json/test_parse_photolysis.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidPhotolysisReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.photolysis.size(), 2); - - EXPECT_EQ(mechanism.reactions.photolysis[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.photolysis[0].name, "my photolysis"); - EXPECT_EQ(mechanism.reactions.photolysis[0].scaling_factor, 12.3); - EXPECT_EQ(mechanism.reactions.photolysis[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis[0].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.photolysis[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.photolysis[0].products.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis[0].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.photolysis[0].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.photolysis[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis[0].unknown_properties["__comment"], "\"hi\""); - - EXPECT_EQ(mechanism.reactions.photolysis[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.photolysis[1].scaling_factor, 1); - EXPECT_EQ(mechanism.reactions.photolysis[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis[1].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.photolysis[1].reactants[0].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.photolysis[1].products.size(), 1); - EXPECT_EQ(mechanism.reactions.photolysis[1].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.photolysis[1].products[0].coefficient, 0.2); -} - -TEST(JsonParser, PhotolysisDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, PhotolysisDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::InvalidKey); -} - -TEST(JsonParser, PhotolysisDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, PhotolysisDoesNotAcceptMoreThanOneReactant) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/more_than_one_reactant.json")); - EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_simpol_phase_transfer.cpp b/test/unit/json/test_parse_simpol_phase_transfer.cpp deleted file mode 100644 index 00f8517..0000000 --- a/test/unit/json/test_parse_simpol_phase_transfer.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidSimpolPhaseTransferReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer.size(), 2); - - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].name, "my simpol"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].gas_phase_species.species_name, "A"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].aerosol_phase, "aerosol"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].aerosol_phase_species.species_name, "B"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[0], -1.97e3); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[1], 2.91e0); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[2], 1.96e-3); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[3], -4.96e-1); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].unknown_properties["__comment"], "\"cereal is also soup\""); - - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].name, ""); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].gas_phase_species.species_name, "A"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].aerosol_phase, "aerosol"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].aerosol_phase_species.species_name, "B"); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[0], -1.97e3); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[1], 2.91e0); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[2], 1.96e-3); - EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[3], -4.96e-1); -} - -TEST(JsonParser, SimpolPhaseTransferDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, SimpolPhaseTransferDetectsUnknownAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, SimpolPhaseTransferDetectsUnknownGasPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, SimpolPhaseTransferDetectsUnknownGasPhaseSpeciesNotInGasPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, SimpolPhaseTransferDetectsUnknownAerosolPhaseSpeciesNotInAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = - parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_species.cpp b/test/unit/json/test_parse_species.cpp deleted file mode 100644 index 23c59ff..0000000 --- a/test/unit/json/test_parse_species.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/valid_species.json")); - - EXPECT_EQ(status, ConfigParseStatus::Success); - EXPECT_EQ(mechanism.species.size(), 3); - - EXPECT_EQ(mechanism.species[0].name, "A"); - EXPECT_EQ(mechanism.species[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.species[0].unknown_properties["__absolute tolerance"], "1e-30"); - - EXPECT_EQ(mechanism.species[1].name, "H2O2"); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties.size(), 6); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["HLC(298K) [mol m-3 Pa-1]"], 1.011596348); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["HLC exponential factor [K]"], 6340); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["diffusion coefficient [m2 s-1]"], 1.46e-05); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["N star"], 1.74); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["molecular weight [kg mol-1]"], 0.0340147); - EXPECT_EQ(mechanism.species[1].optional_numerical_properties["density [kg m-3]"], 1000.0); - EXPECT_EQ(mechanism.species[1].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.species[1].unknown_properties["__absolute tolerance"], "1e-10"); - - EXPECT_EQ(mechanism.species[2].name, "aerosol stuff"); - EXPECT_EQ(mechanism.species[2].optional_numerical_properties.size(), 2); - EXPECT_EQ(mechanism.species[2].optional_numerical_properties["molecular weight [kg mol-1]"], 0.5); - EXPECT_EQ(mechanism.species[2].optional_numerical_properties["density [kg m-3]"], 1000.0); - EXPECT_EQ(mechanism.species[2].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.species[2].unknown_properties["__absolute tolerance"], "1e-20"); -} - -TEST(JsonParser, DetectsDuplicateSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/duplicate_species.json")); - - EXPECT_EQ(status, ConfigParseStatus::DuplicateSpeciesDetected); -} - -TEST(JsonParser, DetectsMissingRequiredKeys) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/missing_required_key.json")); - - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, DetectsInvalidKeys) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/invalid_key.json")); - - EXPECT_EQ(status, ConfigParseStatus::InvalidKey); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_surface.cpp b/test/unit/json/test_parse_surface.cpp deleted file mode 100644 index 1481cd0..0000000 --- a/test/unit/json/test_parse_surface.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidSurfaceReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.surface.size(), 2); - - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.surface[0].name, "my surface"); - EXPECT_EQ(mechanism.reactions.surface[0].aerosol_phase, "surface reacting phase"); - EXPECT_EQ(mechanism.reactions.surface[0].reaction_probability, 2.0e-2); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_species.species_name, "A"); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_species.coefficient, 1); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products.size(), 2); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[1].coefficient, 1); - EXPECT_EQ(mechanism.reactions.surface[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.surface[0].unknown_properties["__comment"], "\"key lime pie is superior to all other pies\""); - - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.surface[1].aerosol_phase, "surface reacting phase"); - EXPECT_EQ(mechanism.reactions.surface[1].reaction_probability, 1.0); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_species.species_name, "A"); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_species.coefficient, 1); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products.size(), 2); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].unknown_properties["__optional thing"], "\"hello\""); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[1].species_name, "C"); - EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[1].coefficient, 1); -} - -TEST(JsonParser, SurfaceDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, SurfaceDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, SurfaceDetectsUnknownAerosolPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/missing_aerosol_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} - -TEST(JsonParser, SurfaceDetectsUnknownGasPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/missing_gas_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_troe.cpp b/test/unit/json/test_parse_troe.cpp deleted file mode 100644 index d9e39e9..0000000 --- a/test/unit/json/test_parse_troe.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidTroeReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.troe.size(), 2); - - EXPECT_EQ(mechanism.reactions.troe[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.troe[0].k0_A, 1.0); - EXPECT_EQ(mechanism.reactions.troe[0].k0_B, 0.0); - EXPECT_EQ(mechanism.reactions.troe[0].k0_C, 0.0); - EXPECT_EQ(mechanism.reactions.troe[0].kinf_A, 1.0); - EXPECT_EQ(mechanism.reactions.troe[0].kinf_B, 0.0); - EXPECT_EQ(mechanism.reactions.troe[0].kinf_C, 0.0); - EXPECT_EQ(mechanism.reactions.troe[0].Fc, 0.6); - EXPECT_EQ(mechanism.reactions.troe[0].N, 1.0); - EXPECT_EQ(mechanism.reactions.troe[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.troe[0].reactants[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.troe[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.troe[0].products.size(), 1); - EXPECT_EQ(mechanism.reactions.troe[0].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.troe[0].products[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.troe[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.troe[0].unknown_properties["__my object"], "{\"a\":1.0}"); - - EXPECT_EQ(mechanism.reactions.troe[1].name, "my troe"); - EXPECT_EQ(mechanism.reactions.troe[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.troe[1].k0_A, 32.1); - EXPECT_EQ(mechanism.reactions.troe[1].k0_B, -2.3); - EXPECT_EQ(mechanism.reactions.troe[1].k0_C, 102.3); - EXPECT_EQ(mechanism.reactions.troe[1].kinf_A, 63.4); - EXPECT_EQ(mechanism.reactions.troe[1].kinf_B, -1.3); - EXPECT_EQ(mechanism.reactions.troe[1].kinf_C, 908.5); - EXPECT_EQ(mechanism.reactions.troe[1].Fc, 1.3); - EXPECT_EQ(mechanism.reactions.troe[1].N, 32.1); - EXPECT_EQ(mechanism.reactions.troe[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.troe[1].reactants[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.troe[1].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.troe[1].products.size(), 2); - EXPECT_EQ(mechanism.reactions.troe[1].products[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.troe[1].products[0].coefficient, 0.2); - EXPECT_EQ(mechanism.reactions.troe[1].products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.troe[1].products[0].unknown_properties["__optional thing"], "\"hello\""); - EXPECT_EQ(mechanism.reactions.troe[1].products[1].species_name, "B"); - EXPECT_EQ(mechanism.reactions.troe[1].products[1].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.troe[1].products[1].unknown_properties.size(), 0); -} - -TEST(JsonParser, TroeDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, TroeDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, TroeDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_tunneling.cpp b/test/unit/json/test_parse_tunneling.cpp deleted file mode 100644 index 07560fd..0000000 --- a/test/unit/json/test_parse_tunneling.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidTunnelingReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.tunneling.size(), 2); - - EXPECT_EQ(mechanism.reactions.tunneling[0].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.tunneling[0].A, 123.45); - EXPECT_EQ(mechanism.reactions.tunneling[0].B, 1200.0); - EXPECT_EQ(mechanism.reactions.tunneling[0].C, 1.0e8); - EXPECT_EQ(mechanism.reactions.tunneling[0].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling[0].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.tunneling[0].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.tunneling[0].products.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling[0].products[0].species_name, "C"); - EXPECT_EQ(mechanism.reactions.tunneling[0].products[0].coefficient, 1); - - EXPECT_EQ(mechanism.reactions.tunneling[1].name, "my tunneling"); - EXPECT_EQ(mechanism.reactions.tunneling[1].gas_phase, "gas"); - EXPECT_EQ(mechanism.reactions.tunneling[1].A, 1.0); - EXPECT_EQ(mechanism.reactions.tunneling[1].B, 0); - EXPECT_EQ(mechanism.reactions.tunneling[1].C, 0); - EXPECT_EQ(mechanism.reactions.tunneling[1].reactants.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling[1].reactants[0].species_name, "B"); - EXPECT_EQ(mechanism.reactions.tunneling[1].reactants[0].coefficient, 1); - EXPECT_EQ(mechanism.reactions.tunneling[1].products.size(), 2); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].species_name, "A"); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].coefficient, 0.2); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].unknown_properties["__optional thing"], "\"hello\""); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].species_name, "B"); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].coefficient, 1.2); - EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].unknown_properties.size(), 0); -} - -TEST(JsonParser, TunnelingDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} - -TEST(JsonParser, TunnelingDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); -} - -TEST(JsonParser, TunnelingDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/test_parse_wet_deposition.cpp b/test/unit/json/test_parse_wet_deposition.cpp deleted file mode 100644 index 610d99c..0000000 --- a/test/unit/json/test_parse_wet_deposition.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include - -using namespace open_atmos::mechanism_configuration; - -TEST(JsonParser, CanParseValidWetDepositionReaction) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/valid.json")); - EXPECT_EQ(status, ConfigParseStatus::Success); - - EXPECT_EQ(mechanism.reactions.wet_deposition.size(), 2); - - EXPECT_EQ(mechanism.reactions.wet_deposition[0].name, "rxn cloud"); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].aerosol_phase, "cloud"); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].scaling_factor, 12.3); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].unknown_properties.size(), 1); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].unknown_properties["__comment"], "\"Tuxedo cats are the best\""); - - EXPECT_EQ(mechanism.reactions.wet_deposition[1].name, "rxn cloud2"); - EXPECT_EQ(mechanism.reactions.wet_deposition[1].aerosol_phase, "cloud"); - EXPECT_EQ(mechanism.reactions.wet_deposition[1].scaling_factor, 1); -} - -TEST(JsonParser, WetDepositionDetectsUnknownPhase) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/missing_phase.json")); - EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); -} \ No newline at end of file diff --git a/test/unit/json/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json b/test/unit/json/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json deleted file mode 100644 index b7a8795..0000000 --- a/test/unit/json/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "version": "1.0.0", - "name": "Condensed phase arrhenius using species not in its requested aerosol phase", - "species": [ - { - "name": "A" - }, - { - "name": "B" - }, - { - "name": "C" - }, - { - "name": "H2O_aq" - } - ], - "phases": [ - { - "name": "aqueous aerosol", - "species": [ - "A", - "C", - "H2O_aq" - ] - } - ], - "reactions": [ - { - "type": "CONDENSED_PHASE_ARRHENIUS", - "aerosol phase": "aqueous aerosol", - "aerosol-phase water": "H2O_aq", - "reactants": [ - { - "species name": "A", - "coefficient": 1 - } - ], - "products": [ - { - "species name": "B", - "coefficient": 1.2 - }, - { - "species name": "C", - "coefficient": 0.3 - } - ], - "A": 32.1, - "B": -2.3, - "C": 102.3, - "D": 63.4, - "E": -1.3, - "name": "my arrhenius", - "__solver_param": 0.1 - }, - { - "type": "CONDENSED_PHASE_ARRHENIUS", - "aerosol phase": "aqueous aerosol", - "aerosol-phase water": "H2O_aq", - "reactants": [ - { - "species name": "A", - "coefficient": 2 - }, - { - "species name": "B", - "coefficient": 0.1 - } - ], - "products": [ - { - "species name": "C", - "coefficient": 0.5, - "__optional thing": "hello" - } - ], - "A": 3.1, - "B": -0.3, - "C": 12.3, - "D": 6.4, - "E": -0.3, - "name": "my arrhenius2" - }, - { - "type": "CONDENSED_PHASE_ARRHENIUS", - "aerosol phase": "aqueous aerosol", - "aerosol-phase water": "H2O_aq", - "reactants": [ - { - "species name": "A" - } - ], - "products": [ - { - "species name": "C" - } - ] - } - ] -} \ No newline at end of file diff --git a/test/unit/test_parse_aqueous_equilibrium.cpp b/test/unit/test_parse_aqueous_equilibrium.cpp new file mode 100644 index 0000000..19ca00f --- /dev/null +++ b/test/unit/test_parse_aqueous_equilibrium.cpp @@ -0,0 +1,82 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidAqueousEquilibriumReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium.size(), 2); + + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].name, "my aqueous eq"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].aerosol_phase, "aerosol"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].A, 1.14e-2); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].C, 2300.0); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].k_reverse, 0.32); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].reactants[0].coefficient, 2); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products.size(), 2); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].products[1].coefficient, 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[0].unknown_properties["__comment"], "\"GIF is pronounced with a hard g\""); + + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].aerosol_phase, "aerosol"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].A, 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].C, 0); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].k_reverse, 0.32); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].reactants[0].coefficient, 2); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products.size(), 2); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.aqueous_equilibrium[1].products[1].coefficient, 1); + } +} + +TEST(Parser, AqueousEquilibriumDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, AqueousEquilibriumDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, AqueousEquilibriumDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/aqueous_equilibrium/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_arrhenius.cpp b/test/unit/test_parse_arrhenius.cpp new file mode 100644 index 0000000..503abd3 --- /dev/null +++ b/test/unit/test_parse_arrhenius.cpp @@ -0,0 +1,112 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidArrheniusReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.arrhenius.size(), 3); + + EXPECT_EQ(mechanism.reactions.arrhenius[0].name, "my arrhenius"); + EXPECT_EQ(mechanism.reactions.arrhenius[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.arrhenius[0].A, 32.1); + EXPECT_EQ(mechanism.reactions.arrhenius[0].B, -2.3); + EXPECT_EQ(mechanism.reactions.arrhenius[0].C, 102.3); + EXPECT_EQ(mechanism.reactions.arrhenius[0].D, 63.4); + EXPECT_EQ(mechanism.reactions.arrhenius[0].E, -1.3); + EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.arrhenius[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.arrhenius[0].products.size(), 2); + EXPECT_EQ(mechanism.reactions.arrhenius[0].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.arrhenius[0].products[0].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.arrhenius[0].products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.arrhenius[0].products[1].coefficient, 0.3); + EXPECT_EQ(mechanism.reactions.arrhenius[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[0].unknown_properties["__solver_param"], "\"0.1\""); + + EXPECT_EQ(mechanism.reactions.arrhenius[1].name, "my arrhenius2"); + EXPECT_EQ(mechanism.reactions.arrhenius[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.arrhenius[1].A, 3.1); + EXPECT_EQ(mechanism.reactions.arrhenius[1].B, -0.3); + EXPECT_EQ(mechanism.reactions.arrhenius[1].C, 12.3); + EXPECT_EQ(mechanism.reactions.arrhenius[1].D, 6.4); + EXPECT_EQ(mechanism.reactions.arrhenius[1].E, -0.3); + EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants.size(), 2); + EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[0].coefficient, 2); + EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[1].species_name, "B"); + EXPECT_EQ(mechanism.reactions.arrhenius[1].reactants[1].coefficient, 0.1); + EXPECT_EQ(mechanism.reactions.arrhenius[1].products.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].coefficient, 0.5); + EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[1].products[0].unknown_properties["__optional thing"], "\"hello\""); + + EXPECT_EQ(mechanism.reactions.arrhenius[2].name, ""); + EXPECT_EQ(mechanism.reactions.arrhenius[2].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.arrhenius[2].A, 1); + EXPECT_EQ(mechanism.reactions.arrhenius[2].B, 0); + EXPECT_EQ(mechanism.reactions.arrhenius[2].C, 0); + EXPECT_EQ(mechanism.reactions.arrhenius[2].D, 300); + EXPECT_EQ(mechanism.reactions.arrhenius[2].E, 0); + EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.arrhenius[2].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.arrhenius[2].products.size(), 1); + EXPECT_EQ(mechanism.reactions.arrhenius[2].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.arrhenius[2].products[0].coefficient, 1); + } +} + +TEST(Parser, ArrheniusDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, ArrheniusDetectsMutuallyExclusiveOptions) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/mutually_exclusive") + extension); + EXPECT_EQ(status, ConfigParseStatus::MutuallyExclusiveOption); + } +} + +TEST(Parser, ArrheniusDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, ArrheniusDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/arrhenius/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_branched.cpp b/test/unit/test_parse_branched.cpp new file mode 100644 index 0000000..1a07f8a --- /dev/null +++ b/test/unit/test_parse_branched.cpp @@ -0,0 +1,73 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidBranchedReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.branched.size(), 1); + + EXPECT_EQ(mechanism.reactions.branched[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.branched[0].name, "my branched"); + EXPECT_EQ(mechanism.reactions.branched[0].X, 1.2e-4); + EXPECT_EQ(mechanism.reactions.branched[0].Y, 167); + EXPECT_EQ(mechanism.reactions.branched[0].a0, 0.15); + EXPECT_EQ(mechanism.reactions.branched[0].n, 9); + EXPECT_EQ(mechanism.reactions.branched[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.branched[0].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.branched[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products.size(), 1); + EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.branched[0].nitrate_products[0].unknown_properties["__thing"], "\"hi\""); + EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products.size(), 2); + EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[0].coefficient, 0.2); + EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[1].species_name, "A"); + EXPECT_EQ(mechanism.reactions.branched[0].alkoxy_products[1].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.branched[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.branched[0].unknown_properties["__comment"], "\"thing\""); + } +} + +TEST(Parser, BranchedDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, BranchedDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, BranchedDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/branched/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_condensed_phase_arrhenius.cpp b/test/unit/test_parse_condensed_phase_arrhenius.cpp new file mode 100644 index 0000000..4329d23 --- /dev/null +++ b/test/unit/test_parse_condensed_phase_arrhenius.cpp @@ -0,0 +1,137 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidCondensedPhaseArrheniusReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius.size(), 3); + + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].name, "my arrhenius"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].A, 32.1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].B, -2.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].C, 102.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].D, 63.4); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].E, -1.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products.size(), 2); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[0].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].products[1].coefficient, 0.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[0].unknown_properties["__solver_param"], "\"0.1\""); + + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].name, "my arrhenius2"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].A, 3.1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].B, -0.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].C, 12.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].D, 6.4); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].E, -0.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants.size(), 2); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[0].coefficient, 2); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[1].species_name, "B"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].reactants[1].coefficient, 0.1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].coefficient, 0.5); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[1].products[0].unknown_properties["__optional thing"], "\"hello\""); + + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].name, ""); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].A, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].B, 0); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].C, 0); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].D, 300); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].E, 0); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.condensed_phase_arrhenius[2].products[0].coefficient, 1); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsMutuallyExclusiveOptions) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive") + extension); + EXPECT_EQ(status, ConfigParseStatus::MutuallyExclusiveOption); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsUnknownAerosolPhaseWater) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsWhenRequestedSpeciesAreNotInAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsMissingPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_arrhenius/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_condensed_phase_photolysis.cpp b/test/unit/test_parse_condensed_phase_photolysis.cpp new file mode 100644 index 0000000..4fc118c --- /dev/null +++ b/test/unit/test_parse_condensed_phase_photolysis.cpp @@ -0,0 +1,107 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidCondensedPhasePhotolysisReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis.size(), 2); + + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].name, "my condensed phase photolysis"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].scaling_factor_, 12.3); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[0].unknown_properties["__comment"], "\"hi\""); + + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].scaling_factor_, 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].reactants[0].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products.size(), 1); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.condensed_phase_photolysis[1].products[0].coefficient, 0.2); + } +} + +TEST(Parser, CondensedPhasePhotolysisDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, CondensedPhasePhotolysisDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::InvalidKey); + } +} + +TEST(Parser, CondensedPhasePhotolysisDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, CondensedPhasePhotolysisDoesNotAcceptMoreThanOneReactant) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant") + extension); + EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); + } +} + +TEST(Parser, CondensedPhasePhotolysisDetectsWhenRequestedSpeciesAreNotInAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); + } +} + +TEST(Parser, CondensedPhaseArrheniusDetectsUnknownAerosolPhaseWater) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_emission.cpp b/test/unit/test_parse_emission.cpp new file mode 100644 index 0000000..57e50fb --- /dev/null +++ b/test/unit/test_parse_emission.cpp @@ -0,0 +1,66 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidEmissionReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.emission.size(), 2); + + EXPECT_EQ(mechanism.reactions.emission[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.emission[0].name, "my emission"); + EXPECT_EQ(mechanism.reactions.emission[0].scaling_factor, 12.3); + EXPECT_EQ(mechanism.reactions.emission[0].products.size(), 1); + EXPECT_EQ(mechanism.reactions.emission[0].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.emission[0].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.emission[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.emission[0].unknown_properties["__comment"], "\"Dr. Pepper outranks any other soda\""); + + EXPECT_EQ(mechanism.reactions.emission[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.emission[1].scaling_factor, 1); + EXPECT_EQ(mechanism.reactions.emission[1].products.size(), 1); + EXPECT_EQ(mechanism.reactions.emission[1].products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.emission[1].products[0].coefficient, 1); + } +} + +TEST(Parser, EmissionDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, EmissionDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, EmissionDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/emission/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_first_order_loss.cpp b/test/unit/test_parse_first_order_loss.cpp new file mode 100644 index 0000000..ba806da --- /dev/null +++ b/test/unit/test_parse_first_order_loss.cpp @@ -0,0 +1,77 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidFirstOrderLossReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.first_order_loss.size(), 2); + + EXPECT_EQ(mechanism.reactions.first_order_loss[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].name, "my first order loss"); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].scaling_factor, 12.3); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.first_order_loss[0].unknown_properties["__comment"], "\"Strawberries are the superior fruit\""); + + EXPECT_EQ(mechanism.reactions.first_order_loss[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.first_order_loss[1].scaling_factor, 1); + EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.first_order_loss[1].reactants[0].coefficient, 1); + } +} + +TEST(Parser, FirstOrderLossDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, FirstOrderLossDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, FirstOrderLossDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, FirstOrderLossDetectsMoreThanOneSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/first_order_loss/too_many_reactants") + extension); + EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_henrys_law.cpp b/test/unit/test_parse_henrys_law.cpp new file mode 100644 index 0000000..3ab0b8c --- /dev/null +++ b/test/unit/test_parse_henrys_law.cpp @@ -0,0 +1,79 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidHenrysLawReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.henrys_law.size(), 2); + + EXPECT_EQ(mechanism.reactions.henrys_law[0].name, "my henry's law"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].gas_phase_species, "A"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase_species, "B"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.henrys_law[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.henrys_law[0].unknown_properties["__comment"], "\"hi\""); + + EXPECT_EQ(mechanism.reactions.henrys_law[1].name, ""); + EXPECT_EQ(mechanism.reactions.henrys_law[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.henrys_law[1].gas_phase_species, "A"); + EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase, "aqueous aerosol"); + EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase_species, "B"); + EXPECT_EQ(mechanism.reactions.henrys_law[1].aerosol_phase_water, "H2O_aq"); + EXPECT_EQ(mechanism.reactions.henrys_law[1].unknown_properties.size(), 0); + } +} + +TEST(Parser, HenrysLawDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, HenrysLawDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, HenrysLawDetectsUnknownAerosolPhaseWater) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/missing_aerosol_phase_water") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, HenrysLawDetectsWhenRequestedSpeciesAreNotInAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/henrys_law/species_not_in_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequestedAerosolSpeciesNotIncludedInAerosolPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_phases.cpp b/test/unit/test_parse_phases.cpp new file mode 100644 index 0000000..7df80fb --- /dev/null +++ b/test/unit/test_parse_phases.cpp @@ -0,0 +1,81 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidPhases) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/valid_phases") + extension); + + EXPECT_EQ(status, ConfigParseStatus::Success); + EXPECT_EQ(mechanism.species.size(), 3); + EXPECT_EQ(mechanism.phases.size(), 2); + + EXPECT_EQ(mechanism.phases[0].name, "gas"); + EXPECT_EQ(mechanism.phases[0].species.size(), 2); + EXPECT_EQ(mechanism.phases[0].species[0], "A"); + EXPECT_EQ(mechanism.phases[0].species[1], "B"); + EXPECT_EQ(mechanism.phases[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.phases[0].unknown_properties["__other"], "\"key\""); + + EXPECT_EQ(mechanism.phases[1].name, "aerosols"); + EXPECT_EQ(mechanism.phases[1].species.size(), 1); + EXPECT_EQ(mechanism.phases[1].species[0], "C"); + EXPECT_EQ(mechanism.phases[1].unknown_properties.size(), 2); + EXPECT_EQ(mechanism.phases[1].unknown_properties["__other1"], "\"key1\""); + EXPECT_EQ(mechanism.phases[1].unknown_properties["__other2"], "\"key2\""); + } +} + +TEST(Parser, DetectsDuplicatePhases) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/duplicate_phases") + extension); + + EXPECT_EQ(status, ConfigParseStatus::DuplicatePhasesDetected); + } +} + +TEST(Parser, DetectsMissingRequiredKeys) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/missing_required_key") + extension); + + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, DetectsInvalidKeys) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/invalid_key") + extension); + + EXPECT_EQ(status, ConfigParseStatus::InvalidKey); + } +} + +TEST(Parser, DetectsPhaseRequestingUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/phases/unknown_species") + extension); + + EXPECT_EQ(status, ConfigParseStatus::PhaseRequiresUnknownSpecies); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_photolysis.cpp b/test/unit/test_parse_photolysis.cpp new file mode 100644 index 0000000..6bfadd2 --- /dev/null +++ b/test/unit/test_parse_photolysis.cpp @@ -0,0 +1,83 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidPhotolysisReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.photolysis.size(), 2); + + EXPECT_EQ(mechanism.reactions.photolysis[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.photolysis[0].name, "my photolysis"); + EXPECT_EQ(mechanism.reactions.photolysis[0].scaling_factor, 12.3); + EXPECT_EQ(mechanism.reactions.photolysis[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis[0].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.photolysis[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.photolysis[0].products.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis[0].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.photolysis[0].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.photolysis[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis[0].unknown_properties["__comment"], "\"hi\""); + + EXPECT_EQ(mechanism.reactions.photolysis[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.photolysis[1].scaling_factor, 1); + EXPECT_EQ(mechanism.reactions.photolysis[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis[1].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.photolysis[1].reactants[0].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.photolysis[1].products.size(), 1); + EXPECT_EQ(mechanism.reactions.photolysis[1].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.photolysis[1].products[0].coefficient, 0.2); + } +} + +TEST(Parser, PhotolysisDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, PhotolysisDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::InvalidKey); + } +} + +TEST(Parser, PhotolysisDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, PhotolysisDoesNotAcceptMoreThanOneReactant) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/photolysis/more_than_one_reactant") + extension); + EXPECT_EQ(status, ConfigParseStatus::TooManyReactionComponents); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_simpol_phase_transfer.cpp b/test/unit/test_parse_simpol_phase_transfer.cpp new file mode 100644 index 0000000..63d27f6 --- /dev/null +++ b/test/unit/test_parse_simpol_phase_transfer.cpp @@ -0,0 +1,96 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidSimpolPhaseTransferReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer.size(), 2); + + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].name, "my simpol"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].gas_phase_species.species_name, "A"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].aerosol_phase, "aerosol"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].aerosol_phase_species.species_name, "B"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[0], -1.97e3); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[1], 2.91e0); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[2], 1.96e-3); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].B[3], -4.96e-1); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[0].unknown_properties["__comment"], "\"cereal is also soup\""); + + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].name, ""); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].gas_phase_species.species_name, "A"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].aerosol_phase, "aerosol"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].aerosol_phase_species.species_name, "B"); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[0], -1.97e3); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[1], 2.91e0); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[2], 1.96e-3); + EXPECT_EQ(mechanism.reactions.simpol_phase_transfer[1].B[3], -4.96e-1); + } +} + +TEST(Parser, SimpolPhaseTransferDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, SimpolPhaseTransferDetectsUnknownAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, SimpolPhaseTransferDetectsUnknownGasPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_gas_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, SimpolPhaseTransferDetectsUnknownGasPhaseSpeciesNotInGasPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, SimpolPhaseTransferDetectsUnknownAerosolPhaseSpeciesNotInAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = + parser.Parse(std::string("unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_species.cpp b/test/unit/test_parse_species.cpp new file mode 100644 index 0000000..cc6e2b4 --- /dev/null +++ b/test/unit/test_parse_species.cpp @@ -0,0 +1,76 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/valid_species") + extension); + + EXPECT_EQ(status, ConfigParseStatus::Success); + EXPECT_EQ(mechanism.species.size(), 3); + + EXPECT_EQ(mechanism.species[0].name, "A"); + EXPECT_EQ(mechanism.species[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.species[0].unknown_properties["__absolute tolerance"], "\"1.0e-30\""); + + EXPECT_EQ(mechanism.species[1].name, "H2O2"); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties.size(), 6); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["HLC(298K) [mol m-3 Pa-1]"], 1.011596348); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["HLC exponential factor [K]"], 6340); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["diffusion coefficient [m2 s-1]"], 1.46e-05); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["N star"], 1.74); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["molecular weight [kg mol-1]"], 0.0340147); + EXPECT_EQ(mechanism.species[1].optional_numerical_properties["density [kg m-3]"], 1000.0); + EXPECT_EQ(mechanism.species[1].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.species[1].unknown_properties["__absolute tolerance"], "\"1.0e-10\""); + + EXPECT_EQ(mechanism.species[2].name, "aerosol stuff"); + EXPECT_EQ(mechanism.species[2].optional_numerical_properties.size(), 2); + EXPECT_EQ(mechanism.species[2].optional_numerical_properties["molecular weight [kg mol-1]"], 0.5); + EXPECT_EQ(mechanism.species[2].optional_numerical_properties["density [kg m-3]"], 1000.0); + EXPECT_EQ(mechanism.species[2].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.species[2].unknown_properties["__absolute tolerance"], "\"1.0e-20\""); + } +} + +TEST(Parser, DetectsDuplicateSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/duplicate_species") + extension); + + EXPECT_EQ(status, ConfigParseStatus::DuplicateSpeciesDetected); + } +} + +TEST(Parser, DetectsMissingRequiredKeys) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/missing_required_key") + extension); + + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, DetectsInvalidKeys) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/species/invalid_key") + extension); + + EXPECT_EQ(status, ConfigParseStatus::InvalidKey); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_surface.cpp b/test/unit/test_parse_surface.cpp new file mode 100644 index 0000000..1b7a594 --- /dev/null +++ b/test/unit/test_parse_surface.cpp @@ -0,0 +1,89 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidSurfaceReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.surface.size(), 2); + + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.surface[0].name, "my surface"); + EXPECT_EQ(mechanism.reactions.surface[0].aerosol_phase, "surface reacting phase"); + EXPECT_EQ(mechanism.reactions.surface[0].reaction_probability, 2.0e-2); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_species.species_name, "A"); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_species.coefficient, 1); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products.size(), 2); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.surface[0].gas_phase_products[1].coefficient, 1); + EXPECT_EQ(mechanism.reactions.surface[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.surface[0].unknown_properties["__comment"], "\"key lime pie is superior to all other pies\""); + + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.surface[1].aerosol_phase, "surface reacting phase"); + EXPECT_EQ(mechanism.reactions.surface[1].reaction_probability, 1.0); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_species.species_name, "A"); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_species.coefficient, 1); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products.size(), 2); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[0].unknown_properties["__optional thing"], "\"hello\""); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[1].species_name, "C"); + EXPECT_EQ(mechanism.reactions.surface[1].gas_phase_products[1].coefficient, 1); + } +} + +TEST(Parser, SurfaceDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, SurfaceDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, SurfaceDetectsUnknownAerosolPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/missing_aerosol_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} + +TEST(Parser, SurfaceDetectsUnknownGasPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/surface/missing_gas_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_troe.cpp b/test/unit/test_parse_troe.cpp new file mode 100644 index 0000000..e5b9c01 --- /dev/null +++ b/test/unit/test_parse_troe.cpp @@ -0,0 +1,98 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidTroeReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.troe.size(), 2); + + EXPECT_EQ(mechanism.reactions.troe[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.troe[0].k0_A, 1.0); + EXPECT_EQ(mechanism.reactions.troe[0].k0_B, 0.0); + EXPECT_EQ(mechanism.reactions.troe[0].k0_C, 0.0); + EXPECT_EQ(mechanism.reactions.troe[0].kinf_A, 1.0); + EXPECT_EQ(mechanism.reactions.troe[0].kinf_B, 0.0); + EXPECT_EQ(mechanism.reactions.troe[0].kinf_C, 0.0); + EXPECT_EQ(mechanism.reactions.troe[0].Fc, 0.6); + EXPECT_EQ(mechanism.reactions.troe[0].N, 1.0); + EXPECT_EQ(mechanism.reactions.troe[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.troe[0].reactants[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.troe[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.troe[0].products.size(), 1); + EXPECT_EQ(mechanism.reactions.troe[0].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.troe[0].products[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.troe[0].unknown_properties.size(), 1); + if (extension == ".json") + { + EXPECT_EQ(mechanism.reactions.troe[0].unknown_properties["__my object"], "{\"a\": \"1.0\"}"); + } + else + { + EXPECT_EQ(mechanism.reactions.troe[0].unknown_properties["__my object"], "\"a\": \"1.0\""); + } + + EXPECT_EQ(mechanism.reactions.troe[1].name, "my troe"); + EXPECT_EQ(mechanism.reactions.troe[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.troe[1].k0_A, 32.1); + EXPECT_EQ(mechanism.reactions.troe[1].k0_B, -2.3); + EXPECT_EQ(mechanism.reactions.troe[1].k0_C, 102.3); + EXPECT_EQ(mechanism.reactions.troe[1].kinf_A, 63.4); + EXPECT_EQ(mechanism.reactions.troe[1].kinf_B, -1.3); + EXPECT_EQ(mechanism.reactions.troe[1].kinf_C, 908.5); + EXPECT_EQ(mechanism.reactions.troe[1].Fc, 1.3); + EXPECT_EQ(mechanism.reactions.troe[1].N, 32.1); + EXPECT_EQ(mechanism.reactions.troe[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.troe[1].reactants[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.troe[1].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.troe[1].products.size(), 2); + EXPECT_EQ(mechanism.reactions.troe[1].products[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.troe[1].products[0].coefficient, 0.2); + EXPECT_EQ(mechanism.reactions.troe[1].products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.troe[1].products[0].unknown_properties["__optional thing"], "\"hello\""); + EXPECT_EQ(mechanism.reactions.troe[1].products[1].species_name, "B"); + EXPECT_EQ(mechanism.reactions.troe[1].products[1].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.troe[1].products[1].unknown_properties.size(), 0); + } +} + +TEST(Parser, TroeDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, TroeDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, TroeDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/troe/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_tunneling.cpp b/test/unit/test_parse_tunneling.cpp new file mode 100644 index 0000000..09926d4 --- /dev/null +++ b/test/unit/test_parse_tunneling.cpp @@ -0,0 +1,79 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidTunnelingReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.tunneling.size(), 2); + + EXPECT_EQ(mechanism.reactions.tunneling[0].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.tunneling[0].A, 123.45); + EXPECT_EQ(mechanism.reactions.tunneling[0].B, 1200.0); + EXPECT_EQ(mechanism.reactions.tunneling[0].C, 1.0e8); + EXPECT_EQ(mechanism.reactions.tunneling[0].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling[0].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.tunneling[0].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.tunneling[0].products.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling[0].products[0].species_name, "C"); + EXPECT_EQ(mechanism.reactions.tunneling[0].products[0].coefficient, 1); + + EXPECT_EQ(mechanism.reactions.tunneling[1].name, "my tunneling"); + EXPECT_EQ(mechanism.reactions.tunneling[1].gas_phase, "gas"); + EXPECT_EQ(mechanism.reactions.tunneling[1].A, 1.0); + EXPECT_EQ(mechanism.reactions.tunneling[1].B, 0); + EXPECT_EQ(mechanism.reactions.tunneling[1].C, 0); + EXPECT_EQ(mechanism.reactions.tunneling[1].reactants.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling[1].reactants[0].species_name, "B"); + EXPECT_EQ(mechanism.reactions.tunneling[1].reactants[0].coefficient, 1); + EXPECT_EQ(mechanism.reactions.tunneling[1].products.size(), 2); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].species_name, "A"); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].coefficient, 0.2); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[0].unknown_properties["__optional thing"], "\"hello\""); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].species_name, "B"); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].coefficient, 1.2); + EXPECT_EQ(mechanism.reactions.tunneling[1].products[1].unknown_properties.size(), 0); + } +} + +TEST(Parser, TunnelingDetectsUnknownSpecies) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/unknown_species") + extension); + EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); + } +} + +TEST(Parser, TunnelingDetectsBadReactionComponent) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/bad_reaction_component") + extension); + EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + } +} + +TEST(Parser, TunnelingDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/tunneling/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/test_parse_wet_deposition.cpp b/test/unit/test_parse_wet_deposition.cpp new file mode 100644 index 0000000..7b106d1 --- /dev/null +++ b/test/unit/test_parse_wet_deposition.cpp @@ -0,0 +1,39 @@ +#include + +#include + +using namespace open_atmos::mechanism_configuration; + +TEST(Parser, CanParseValidWetDepositionReaction) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/valid") + extension); + EXPECT_EQ(status, ConfigParseStatus::Success); + + EXPECT_EQ(mechanism.reactions.wet_deposition.size(), 2); + + EXPECT_EQ(mechanism.reactions.wet_deposition[0].name, "rxn cloud"); + EXPECT_EQ(mechanism.reactions.wet_deposition[0].aerosol_phase, "cloud"); + EXPECT_EQ(mechanism.reactions.wet_deposition[0].scaling_factor, 12.3); + EXPECT_EQ(mechanism.reactions.wet_deposition[0].unknown_properties.size(), 1); + EXPECT_EQ(mechanism.reactions.wet_deposition[0].unknown_properties["__comment"], "\"Tuxedo cats are the best\""); + + EXPECT_EQ(mechanism.reactions.wet_deposition[1].name, "rxn cloud2"); + EXPECT_EQ(mechanism.reactions.wet_deposition[1].aerosol_phase, "cloud"); + EXPECT_EQ(mechanism.reactions.wet_deposition[1].scaling_factor, 1); + } +} + +TEST(Parser, WetDepositionDetectsUnknownPhase) +{ + Parser parser; + std::vector extensions = { ".json", ".yaml" }; + for (auto& extension : extensions) + { + auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/missing_phase") + extension); + EXPECT_EQ(status, ConfigParseStatus::UnknownPhase); + } +} \ No newline at end of file diff --git a/test/unit/json/unit_configs/phases/duplicate_phases.json b/test/unit/unit_configs/phases/duplicate_phases.json similarity index 100% rename from test/unit/json/unit_configs/phases/duplicate_phases.json rename to test/unit/unit_configs/phases/duplicate_phases.json diff --git a/test/unit/unit_configs/phases/duplicate_phases.yaml b/test/unit/unit_configs/phases/duplicate_phases.yaml new file mode 100644 index 0000000..8254886 --- /dev/null +++ b/test/unit/unit_configs/phases/duplicate_phases.yaml @@ -0,0 +1,16 @@ +name: Duplicate phases configuration +phases: +- name: gas + species: + - A + - B +- name: gas + species: + - A + - B +reactions: [] +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/phases/invalid_key.json b/test/unit/unit_configs/phases/invalid_key.json similarity index 100% rename from test/unit/json/unit_configs/phases/invalid_key.json rename to test/unit/unit_configs/phases/invalid_key.json diff --git a/test/unit/unit_configs/phases/invalid_key.yaml b/test/unit/unit_configs/phases/invalid_key.yaml new file mode 100644 index 0000000..5be0e96 --- /dev/null +++ b/test/unit/unit_configs/phases/invalid_key.yaml @@ -0,0 +1,13 @@ +name: Invalid key configuration +phases: +- name: gas + other: key + species: + - A + - B +reactions: [] +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/phases/missing_required_key.json b/test/unit/unit_configs/phases/missing_required_key.json similarity index 100% rename from test/unit/json/unit_configs/phases/missing_required_key.json rename to test/unit/unit_configs/phases/missing_required_key.json diff --git a/test/unit/unit_configs/phases/missing_required_key.yaml b/test/unit/unit_configs/phases/missing_required_key.yaml new file mode 100644 index 0000000..e11189c --- /dev/null +++ b/test/unit/unit_configs/phases/missing_required_key.yaml @@ -0,0 +1,6 @@ +name: Missing required phases key configuration +phases: +- name: gas +reactions: [] +species: [] +version: 1.0.0 diff --git a/test/unit/json/unit_configs/phases/unknown_species.json b/test/unit/unit_configs/phases/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/phases/unknown_species.json rename to test/unit/unit_configs/phases/unknown_species.json diff --git a/test/unit/unit_configs/phases/unknown_species.yaml b/test/unit/unit_configs/phases/unknown_species.yaml new file mode 100644 index 0000000..8f45ec6 --- /dev/null +++ b/test/unit/unit_configs/phases/unknown_species.yaml @@ -0,0 +1,13 @@ +name: Unknown species configuration +phases: +- __other: key + name: gas + species: + - A + - D +reactions: [] +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/phases/valid_phases.json b/test/unit/unit_configs/phases/valid_phases.json similarity index 100% rename from test/unit/json/unit_configs/phases/valid_phases.json rename to test/unit/unit_configs/phases/valid_phases.json diff --git a/test/unit/unit_configs/phases/valid_phases.yaml b/test/unit/unit_configs/phases/valid_phases.yaml new file mode 100644 index 0000000..e91c986 --- /dev/null +++ b/test/unit/unit_configs/phases/valid_phases.yaml @@ -0,0 +1,18 @@ +name: Valid phases configuration +phases: +- __other: key + name: gas + species: + - A + - B +- __other1: key1 + __other2: key2 + name: aerosols + species: + - C +reactions: [] +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.json b/test/unit/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.json rename to test/unit/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.yaml new file mode 100644 index 0000000..dfb323f --- /dev/null +++ b/test/unit/unit_configs/reactions/aqueous_equilibrium/bad_reaction_component.yaml @@ -0,0 +1,27 @@ +name: Bad reaction component +phases: +- name: aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aerosol + aerosol-phase water: H2O_aq + k_reverse: 0.32 + products: + - Species name: B + coefficient: 1 + - Species name: C + coefficient: 1 + reactants: + - Species name: A + coefficient: 2 + type: AQUEOUS_EQUILIBRIUM +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/aqueous_equilibrium/missing_phase.json b/test/unit/unit_configs/reactions/aqueous_equilibrium/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/aqueous_equilibrium/missing_phase.json rename to test/unit/unit_configs/reactions/aqueous_equilibrium/missing_phase.json diff --git a/test/unit/unit_configs/reactions/aqueous_equilibrium/missing_phase.yaml b/test/unit/unit_configs/reactions/aqueous_equilibrium/missing_phase.yaml new file mode 100644 index 0000000..216f8b6 --- /dev/null +++ b/test/unit/unit_configs/reactions/aqueous_equilibrium/missing_phase.yaml @@ -0,0 +1,21 @@ +name: Missing phase +phases: [] +reactions: +- aerosol phase: aerosol + aerosol-phase water: H2O_aq + k_reverse: 0.32 + products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + reactants: + - coefficient: 2 + species name: A + type: AQUEOUS_EQUILIBRIUM +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/aqueous_equilibrium/unknown_species.json b/test/unit/unit_configs/reactions/aqueous_equilibrium/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/aqueous_equilibrium/unknown_species.json rename to test/unit/unit_configs/reactions/aqueous_equilibrium/unknown_species.json diff --git a/test/unit/unit_configs/reactions/aqueous_equilibrium/unknown_species.yaml b/test/unit/unit_configs/reactions/aqueous_equilibrium/unknown_species.yaml new file mode 100644 index 0000000..0e58c76 --- /dev/null +++ b/test/unit/unit_configs/reactions/aqueous_equilibrium/unknown_species.yaml @@ -0,0 +1,23 @@ +name: Unknown species +phases: +- name: aerosol + species: + - A + - B +reactions: +- aerosol phase: aerosol + aerosol-phase water: H2O_aq + k_reverse: 0.32 + products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + reactants: + - coefficient: 2 + species name: A + type: AQUEOUS_EQUILIBRIUM +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/aqueous_equilibrium/valid.json b/test/unit/unit_configs/reactions/aqueous_equilibrium/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/aqueous_equilibrium/valid.json rename to test/unit/unit_configs/reactions/aqueous_equilibrium/valid.json diff --git a/test/unit/unit_configs/reactions/aqueous_equilibrium/valid.yaml b/test/unit/unit_configs/reactions/aqueous_equilibrium/valid.yaml new file mode 100644 index 0000000..d0a748b --- /dev/null +++ b/test/unit/unit_configs/reactions/aqueous_equilibrium/valid.yaml @@ -0,0 +1,43 @@ +name: Valid aqueous equilibrium +phases: +- name: aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- A: 0.0114 + C: 2300.0 + __comment: GIF is pronounced with a hard g + aerosol phase: aerosol + aerosol-phase water: H2O_aq + k_reverse: 0.32 + name: my aqueous eq + products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + reactants: + - coefficient: 2 + species name: A + type: AQUEOUS_EQUILIBRIUM +- aerosol phase: aerosol + aerosol-phase water: H2O_aq + k_reverse: 0.32 + products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + reactants: + - coefficient: 2 + species name: A + type: AQUEOUS_EQUILIBRIUM +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/arrhenius/bad_reaction_component.json b/test/unit/unit_configs/reactions/arrhenius/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/arrhenius/bad_reaction_component.json rename to test/unit/unit_configs/reactions/arrhenius/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/arrhenius/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/arrhenius/bad_reaction_component.yaml new file mode 100644 index 0000000..bf58a66 --- /dev/null +++ b/test/unit/unit_configs/reactions/arrhenius/bad_reaction_component.yaml @@ -0,0 +1,17 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - species name: B + reactants: + - Species name: A + type: ARRHENIUS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/arrhenius/missing_phase.json b/test/unit/unit_configs/reactions/arrhenius/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/arrhenius/missing_phase.json rename to test/unit/unit_configs/reactions/arrhenius/missing_phase.json diff --git a/test/unit/unit_configs/reactions/arrhenius/missing_phase.yaml b/test/unit/unit_configs/reactions/arrhenius/missing_phase.yaml new file mode 100644 index 0000000..ae5a8c0 --- /dev/null +++ b/test/unit/unit_configs/reactions/arrhenius/missing_phase.yaml @@ -0,0 +1,14 @@ +name: Missing phase +phases: [] +reactions: +- gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: ARRHENIUS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/arrhenius/mutually_exclusive.json b/test/unit/unit_configs/reactions/arrhenius/mutually_exclusive.json similarity index 100% rename from test/unit/json/unit_configs/reactions/arrhenius/mutually_exclusive.json rename to test/unit/unit_configs/reactions/arrhenius/mutually_exclusive.json diff --git a/test/unit/unit_configs/reactions/arrhenius/mutually_exclusive.yaml b/test/unit/unit_configs/reactions/arrhenius/mutually_exclusive.yaml new file mode 100644 index 0000000..cad06e6 --- /dev/null +++ b/test/unit/unit_configs/reactions/arrhenius/mutually_exclusive.yaml @@ -0,0 +1,19 @@ +name: Mutually Exclusive +phases: +- name: gas + species: + - A + - B +reactions: +- C: 10 + Ea: 0.5 + gas phase: gas + products: + - species name: B + reactants: + - species name: A + type: ARRHENIUS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/arrhenius/unknown_species.json b/test/unit/unit_configs/reactions/arrhenius/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/arrhenius/unknown_species.json rename to test/unit/unit_configs/reactions/arrhenius/unknown_species.json diff --git a/test/unit/unit_configs/reactions/arrhenius/unknown_species.yaml b/test/unit/unit_configs/reactions/arrhenius/unknown_species.yaml new file mode 100644 index 0000000..6cbe3b5 --- /dev/null +++ b/test/unit/unit_configs/reactions/arrhenius/unknown_species.yaml @@ -0,0 +1,17 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: ARRHENIUS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/arrhenius/valid.json b/test/unit/unit_configs/reactions/arrhenius/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/arrhenius/valid.json rename to test/unit/unit_configs/reactions/arrhenius/valid.json diff --git a/test/unit/unit_configs/reactions/arrhenius/valid.yaml b/test/unit/unit_configs/reactions/arrhenius/valid.yaml new file mode 100644 index 0000000..fe64673 --- /dev/null +++ b/test/unit/unit_configs/reactions/arrhenius/valid.yaml @@ -0,0 +1,53 @@ +name: Valid arrhenius +phases: +- name: gas + species: + - A + - B + - C +reactions: +- A: 32.1 + B: -2.3 + C: 102.3 + D: 63.4 + E: -1.3 + __solver_param: 0.1 + gas phase: gas + name: my arrhenius + products: + - coefficient: 1.2 + species name: B + - coefficient: 0.3 + species name: C + reactants: + - coefficient: 1 + species name: A + type: ARRHENIUS +- A: 3.1 + B: -0.3 + C: 12.3 + D: 6.4 + E: -0.3 + gas phase: gas + name: my arrhenius2 + products: + - __optional thing: hello + coefficient: 0.5 + species name: C + reactants: + - coefficient: 2 + species name: A + - coefficient: 0.1 + species name: B + type: ARRHENIUS +- gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: ARRHENIUS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/branched/bad_reaction_component.json b/test/unit/unit_configs/reactions/branched/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/branched/bad_reaction_component.json rename to test/unit/unit_configs/reactions/branched/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/branched/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/branched/bad_reaction_component.yaml new file mode 100644 index 0000000..19c29e6 --- /dev/null +++ b/test/unit/unit_configs/reactions/branched/bad_reaction_component.yaml @@ -0,0 +1,30 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- X: 0.00012 + Y: 167 + __comment: thing + a0: 0.15 + alkoxy products: + - coefficient: 0.2 + species name: B + - coefficient: 1.2 + species name: A + gas phase: gas + n: 9 + name: my branched + nitrate products: + - __thing: hi + coefficient: 1.2 + species name: C + reactants: + - Species name: A + type: BRANCHED_NO_RO2 +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/branched/missing_phase.json b/test/unit/unit_configs/reactions/branched/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/branched/missing_phase.json rename to test/unit/unit_configs/reactions/branched/missing_phase.json diff --git a/test/unit/unit_configs/reactions/branched/missing_phase.yaml b/test/unit/unit_configs/reactions/branched/missing_phase.yaml new file mode 100644 index 0000000..d82daa4 --- /dev/null +++ b/test/unit/unit_configs/reactions/branched/missing_phase.yaml @@ -0,0 +1,27 @@ +name: Missing phase +phases: [] +reactions: +- X: 0.00012 + Y: 167 + __comment: thing + a0: 0.15 + alkoxy products: + - coefficient: 0.2 + species name: B + - coefficient: 1.2 + species name: A + gas phase: gas + n: 9 + name: my branched + nitrate products: + - __thing: hi + coefficient: 1.2 + species name: C + reactants: + - species name: A + type: BRANCHED_NO_RO2 +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/branched/unknown_species.json b/test/unit/unit_configs/reactions/branched/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/branched/unknown_species.json rename to test/unit/unit_configs/reactions/branched/unknown_species.json diff --git a/test/unit/unit_configs/reactions/branched/unknown_species.yaml b/test/unit/unit_configs/reactions/branched/unknown_species.yaml new file mode 100644 index 0000000..1b41041 --- /dev/null +++ b/test/unit/unit_configs/reactions/branched/unknown_species.yaml @@ -0,0 +1,30 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- X: 0.00012 + Y: 167 + __comment: thing + a0: 0.15 + alkoxy products: + - coefficient: 0.2 + species name: B + - coefficient: 1.2 + species name: A + gas phase: gas + n: 9 + name: my branched + nitrate products: + - __thing: hi + coefficient: 1.2 + species name: C + reactants: + - species name: A + type: BRANCHED_NO_RO2 +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/branched/valid.json b/test/unit/unit_configs/reactions/branched/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/branched/valid.json rename to test/unit/unit_configs/reactions/branched/valid.json diff --git a/test/unit/unit_configs/reactions/branched/valid.yaml b/test/unit/unit_configs/reactions/branched/valid.yaml new file mode 100644 index 0000000..b3a1297 --- /dev/null +++ b/test/unit/unit_configs/reactions/branched/valid.yaml @@ -0,0 +1,32 @@ +name: Valid branched +phases: +- name: gas + species: + - A + - B + - C +reactions: +- X: 0.00012 + Y: 167 + __comment: thing + a0: 0.15 + alkoxy products: + - coefficient: 0.2 + species name: B + - coefficient: 1.2 + species name: A + gas phase: gas + n: 9 + name: my branched + nitrate products: + - __thing: hi + coefficient: 1.2 + species name: C + reactants: + - species name: A + type: BRANCHED_NO_RO2 +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.yaml new file mode 100644 index 0000000..34b8834 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/bad_reaction_component.yaml @@ -0,0 +1,20 @@ +name: Bad reaction component +phases: +- name: aqueous aerosol + species: + - A + - B + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_a + products: + - species name: B + reactants: + - Species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.yaml new file mode 100644 index 0000000..d9003e8 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_aerosol_phase_water.yaml @@ -0,0 +1,22 @@ +name: Missing condensed phase arrhenius aerosol phase water +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_a + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.yaml new file mode 100644 index 0000000..f68d4b8 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/missing_phase.yaml @@ -0,0 +1,16 @@ +name: Missing phase +phases: [] +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.yaml new file mode 100644 index 0000000..c69db38 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/mutually_exclusive.yaml @@ -0,0 +1,22 @@ +name: Mutually Exclusive +phases: +- name: aqueous aerosol + species: + - A + - B + - H2O_aq +reactions: +- C: 10 + Ea: 0.5 + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - species name: B + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.yaml new file mode 100644 index 0000000..54d9def --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/species_not_in_aerosol_phase.yaml @@ -0,0 +1,57 @@ +name: Condensed phase arrhenius using species not in its requested aerosol phase +phases: +- name: aqueous aerosol + species: + - A + - C + - H2O_aq +reactions: +- A: 32.1 + B: -2.3 + C: 102.3 + D: 63.4 + E: -1.3 + __solver_param: 0.1 + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + name: my arrhenius + products: + - coefficient: 1.2 + species name: B + - coefficient: 0.3 + species name: C + reactants: + - coefficient: 1 + species name: A + type: CONDENSED_PHASE_ARRHENIUS +- A: 3.1 + B: -0.3 + C: 12.3 + D: 6.4 + E: -0.3 + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + name: my arrhenius2 + products: + - __optional thing: hello + coefficient: 0.5 + species name: C + reactants: + - coefficient: 2 + species name: A + - coefficient: 0.1 + species name: B + type: CONDENSED_PHASE_ARRHENIUS +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.yaml new file mode 100644 index 0000000..7c54ff9 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/unknown_species.yaml @@ -0,0 +1,20 @@ +name: Unknown species +phases: +- name: aqueous aerosol + species: + - A + - B + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/valid.json b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_arrhenius/valid.json rename to test/unit/unit_configs/reactions/condensed_phase_arrhenius/valid.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_arrhenius/valid.yaml b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/valid.yaml new file mode 100644 index 0000000..465ccee --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_arrhenius/valid.yaml @@ -0,0 +1,58 @@ +name: Valid condensed phase arrhenius +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- A: 32.1 + B: -2.3 + C: 102.3 + D: 63.4 + E: -1.3 + __solver_param: 0.1 + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + name: my arrhenius + products: + - coefficient: 1.2 + species name: B + - coefficient: 0.3 + species name: C + reactants: + - coefficient: 1 + species name: A + type: CONDENSED_PHASE_ARRHENIUS +- A: 3.1 + B: -0.3 + C: 12.3 + D: 6.4 + E: -0.3 + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + name: my arrhenius2 + products: + - __optional thing: hello + coefficient: 0.5 + species name: C + reactants: + - coefficient: 2 + species name: A + - coefficient: 0.1 + species name: B + type: CONDENSED_PHASE_ARRHENIUS +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.yaml new file mode 100644 index 0000000..7c82bff --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/bad_reaction_component.yaml @@ -0,0 +1,24 @@ +name: Bad reaction component +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 0.2 + species name: B + reactants: + - Coefficient: 1.2 + species name: A + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.yaml new file mode 100644 index 0000000..c3ca250 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_aerosol_phase_water.yaml @@ -0,0 +1,24 @@ +name: Missing condensed phase arrhenius aerosol phase water +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_a + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/missing_phase.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/missing_phase.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_phase.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_phase.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_phase.yaml new file mode 100644 index 0000000..9070225 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/missing_phase.yaml @@ -0,0 +1,18 @@ +name: Missing phase +phases: [] +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.yaml new file mode 100644 index 0000000..bbb1f4f --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/more_than_one_reactant.yaml @@ -0,0 +1,24 @@ +name: more than one reactant +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 0.2 + species name: C + reactants: + - species name: A + - species name: B + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.yaml new file mode 100644 index 0000000..2162712 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/species_not_in_aerosol_phase.yaml @@ -0,0 +1,25 @@ +name: Condensed phase photolysis using species not in its requested aerosol phase +phases: +- name: aqueous aerosol + species: + - A + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 1.2 + species name: B + - coefficient: 0.3 + species name: C + reactants: + - coefficient: 1 + species name: A + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/unknown_species.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/unknown_species.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/unknown_species.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/unknown_species.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/unknown_species.yaml new file mode 100644 index 0000000..fdc6744 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/unknown_species.yaml @@ -0,0 +1,20 @@ +name: Unknown species +phases: +- name: aqueous aerosol + species: + - A + - B +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 0.2 + species name: B + reactants: + - coefficient: 1.2 + species name: A + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/condensed_phase_photolysis/valid.json b/test/unit/unit_configs/reactions/condensed_phase_photolysis/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/condensed_phase_photolysis/valid.json rename to test/unit/unit_configs/reactions/condensed_phase_photolysis/valid.json diff --git a/test/unit/unit_configs/reactions/condensed_phase_photolysis/valid.yaml b/test/unit/unit_configs/reactions/condensed_phase_photolysis/valid.yaml new file mode 100644 index 0000000..32471d3 --- /dev/null +++ b/test/unit/unit_configs/reactions/condensed_phase_photolysis/valid.yaml @@ -0,0 +1,36 @@ +name: Valid surface +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- __comment: hi + aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + name: my condensed phase photolysis + products: + - coefficient: 1 + species name: C + reactants: + - coefficient: 1 + species name: B + scaling factor: 12.3 + type: CONDENSED_PHASE_PHOTOLYSIS +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_aq + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: CONDENSED_PHASE_PHOTOLYSIS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/emission/bad_reaction_component.json b/test/unit/unit_configs/reactions/emission/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/emission/bad_reaction_component.json rename to test/unit/unit_configs/reactions/emission/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/emission/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/emission/bad_reaction_component.yaml new file mode 100644 index 0000000..f7f2248 --- /dev/null +++ b/test/unit/unit_configs/reactions/emission/bad_reaction_component.yaml @@ -0,0 +1,15 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - Species name: C + type: EMISSION +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/emission/missing_phase.json b/test/unit/unit_configs/reactions/emission/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/emission/missing_phase.json rename to test/unit/unit_configs/reactions/emission/missing_phase.json diff --git a/test/unit/unit_configs/reactions/emission/missing_phase.yaml b/test/unit/unit_configs/reactions/emission/missing_phase.yaml new file mode 100644 index 0000000..4e25e75 --- /dev/null +++ b/test/unit/unit_configs/reactions/emission/missing_phase.yaml @@ -0,0 +1,12 @@ +name: Missing phase +phases: [] +reactions: +- gas phase: gas + products: + - species name: C + type: EMISSION +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/emission/unknown_species.json b/test/unit/unit_configs/reactions/emission/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/emission/unknown_species.json rename to test/unit/unit_configs/reactions/emission/unknown_species.json diff --git a/test/unit/unit_configs/reactions/emission/unknown_species.yaml b/test/unit/unit_configs/reactions/emission/unknown_species.yaml new file mode 100644 index 0000000..26a0735 --- /dev/null +++ b/test/unit/unit_configs/reactions/emission/unknown_species.yaml @@ -0,0 +1,15 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - species name: C + type: EMISSION +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/emission/valid.json b/test/unit/unit_configs/reactions/emission/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/emission/valid.json rename to test/unit/unit_configs/reactions/emission/valid.json diff --git a/test/unit/unit_configs/reactions/emission/valid.yaml b/test/unit/unit_configs/reactions/emission/valid.yaml new file mode 100644 index 0000000..024a735 --- /dev/null +++ b/test/unit/unit_configs/reactions/emission/valid.yaml @@ -0,0 +1,30 @@ +name: Valid surface +phases: +- name: gas + species: + - A + - B + - C +- name: surface reacting phase + species: + - A + - B + - C +reactions: +- __comment: Dr. Pepper outranks any other soda + gas phase: gas + name: my emission + products: + - coefficient: 1 + species name: B + scaling factor: 12.3 + type: EMISSION +- gas phase: gas + products: + - species name: B + type: EMISSION +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/first_order_loss/bad_reaction_component.json b/test/unit/unit_configs/reactions/first_order_loss/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/first_order_loss/bad_reaction_component.json rename to test/unit/unit_configs/reactions/first_order_loss/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/first_order_loss/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/first_order_loss/bad_reaction_component.yaml new file mode 100644 index 0000000..c3ffe42 --- /dev/null +++ b/test/unit/unit_configs/reactions/first_order_loss/bad_reaction_component.yaml @@ -0,0 +1,15 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + reactants: + - Species name: C + type: FIRST_ORDER_LOSS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/first_order_loss/missing_phase.json b/test/unit/unit_configs/reactions/first_order_loss/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/first_order_loss/missing_phase.json rename to test/unit/unit_configs/reactions/first_order_loss/missing_phase.json diff --git a/test/unit/unit_configs/reactions/first_order_loss/missing_phase.yaml b/test/unit/unit_configs/reactions/first_order_loss/missing_phase.yaml new file mode 100644 index 0000000..0fdd78c --- /dev/null +++ b/test/unit/unit_configs/reactions/first_order_loss/missing_phase.yaml @@ -0,0 +1,12 @@ +name: Missing phase +phases: [] +reactions: +- gas phase: gas + reactants: + - species name: C + type: FIRST_ORDER_LOSS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/first_order_loss/too_many_reactants.json b/test/unit/unit_configs/reactions/first_order_loss/too_many_reactants.json similarity index 100% rename from test/unit/json/unit_configs/reactions/first_order_loss/too_many_reactants.json rename to test/unit/unit_configs/reactions/first_order_loss/too_many_reactants.json diff --git a/test/unit/unit_configs/reactions/first_order_loss/too_many_reactants.yaml b/test/unit/unit_configs/reactions/first_order_loss/too_many_reactants.yaml new file mode 100644 index 0000000..edf0ff2 --- /dev/null +++ b/test/unit/unit_configs/reactions/first_order_loss/too_many_reactants.yaml @@ -0,0 +1,20 @@ +name: Too many reactants +phases: +- name: gas + species: + - A + - B + - C +reactions: +- gas phase: gas + reactants: + - coefficient: 1 + species name: C + - coefficient: 1 + species name: B + type: FIRST_ORDER_LOSS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/first_order_loss/unknown_species.json b/test/unit/unit_configs/reactions/first_order_loss/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/first_order_loss/unknown_species.json rename to test/unit/unit_configs/reactions/first_order_loss/unknown_species.json diff --git a/test/unit/unit_configs/reactions/first_order_loss/unknown_species.yaml b/test/unit/unit_configs/reactions/first_order_loss/unknown_species.yaml new file mode 100644 index 0000000..33a44e9 --- /dev/null +++ b/test/unit/unit_configs/reactions/first_order_loss/unknown_species.yaml @@ -0,0 +1,15 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + reactants: + - species name: C + type: FIRST_ORDER_LOSS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/first_order_loss/valid.json b/test/unit/unit_configs/reactions/first_order_loss/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/first_order_loss/valid.json rename to test/unit/unit_configs/reactions/first_order_loss/valid.json diff --git a/test/unit/unit_configs/reactions/first_order_loss/valid.yaml b/test/unit/unit_configs/reactions/first_order_loss/valid.yaml new file mode 100644 index 0000000..570b83d --- /dev/null +++ b/test/unit/unit_configs/reactions/first_order_loss/valid.yaml @@ -0,0 +1,26 @@ +name: Valid surface +phases: +- name: gas + species: + - A + - B + - C +reactions: +- __comment: Strawberries are the superior fruit + gas phase: gas + name: my first order loss + reactants: + - coefficient: 1 + species name: C + scaling factor: 12.3 + type: FIRST_ORDER_LOSS +- gas phase: gas + reactants: + - coefficient: 1 + species name: C + type: FIRST_ORDER_LOSS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.json b/test/unit/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.json similarity index 100% rename from test/unit/json/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.json rename to test/unit/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.json diff --git a/test/unit/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.yaml b/test/unit/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.yaml new file mode 100644 index 0000000..d9003e8 --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/missing_aerosol_phase_water.yaml @@ -0,0 +1,22 @@ +name: Missing condensed phase arrhenius aerosol phase water +phases: +- name: aqueous aerosol + species: + - A + - B + - C + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase water: H2O_a + products: + - species name: C + reactants: + - species name: A + type: CONDENSED_PHASE_ARRHENIUS +species: +- name: A +- name: B +- name: C +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/henrys_law/missing_phase.json b/test/unit/unit_configs/reactions/henrys_law/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/henrys_law/missing_phase.json rename to test/unit/unit_configs/reactions/henrys_law/missing_phase.json diff --git a/test/unit/unit_configs/reactions/henrys_law/missing_phase.yaml b/test/unit/unit_configs/reactions/henrys_law/missing_phase.yaml new file mode 100644 index 0000000..9153677 --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/missing_phase.yaml @@ -0,0 +1,15 @@ +name: Missing phase +phases: [] +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase species: H2O2_aq + aerosol-phase water: H2O_aq + gas phase: gas + gas-phase species: H2O2 + name: my henry's law + type: HL_PHASE_TRANSFER +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json b/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json new file mode 100644 index 0000000..0fae96a --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.json @@ -0,0 +1,42 @@ +{ + "version": "1.0.0", + "name": "Condensed phase arrhenius using species not in its requested aerosol phase", + "species": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "H2O_aq" + } + ], + "phases": [ + { + "name": "gas", + "species": [ + "A", + "B" + ] + }, + { + "name": "aqueous aerosol", + "species": [ + "H2O_aq" + ] + } + ], + "reactions": [ + { + "type": "HL_PHASE_TRANSFER", + "gas phase": "gas", + "gas-phase species": "A", + "aerosol phase": "aqueous aerosol", + "aerosol-phase species": "B", + "aerosol-phase water": "H2O_aq", + "name": "my henry's law", + "__comment": "hi" + } + ] +} \ No newline at end of file diff --git a/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.yaml b/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.yaml new file mode 100644 index 0000000..3a13343 --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/species_not_in_aerosol_phase.yaml @@ -0,0 +1,23 @@ +version: 1.0.0 +name: Condensed phase arrhenius using species not in its requested aerosol phase +species: +- name: A +- name: B +- name: H2O_aq +phases: +- name: gas + species: + - A + - B +- name: aqueous aerosol + species: + - H2O_aq +reactions: +- type: HL_PHASE_TRANSFER + gas phase: gas + gas-phase species: A + aerosol phase: aqueous aerosol + aerosol-phase species: B + aerosol-phase water: H2O_aq + name: my henry's law + __comment: hi diff --git a/test/unit/json/unit_configs/reactions/henrys_law/unknown_species.json b/test/unit/unit_configs/reactions/henrys_law/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/henrys_law/unknown_species.json rename to test/unit/unit_configs/reactions/henrys_law/unknown_species.json diff --git a/test/unit/unit_configs/reactions/henrys_law/unknown_species.yaml b/test/unit/unit_configs/reactions/henrys_law/unknown_species.yaml new file mode 100644 index 0000000..b04547e --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/unknown_species.yaml @@ -0,0 +1,21 @@ +name: Unknown species +phases: +- name: gas + species: + - A +- name: aqueous aerosol + species: + - B + - H2O_aq +reactions: +- aerosol phase: aqueous aerosol + aerosol-phase species: B + aerosol-phase water: H2O_aq + gas phase: gas + gas-phase species: C + type: HL_PHASE_TRANSFER +species: +- name: A +- name: B +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/henrys_law/valid.json b/test/unit/unit_configs/reactions/henrys_law/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/henrys_law/valid.json rename to test/unit/unit_configs/reactions/henrys_law/valid.json diff --git a/test/unit/unit_configs/reactions/henrys_law/valid.yaml b/test/unit/unit_configs/reactions/henrys_law/valid.yaml new file mode 100644 index 0000000..0133fec --- /dev/null +++ b/test/unit/unit_configs/reactions/henrys_law/valid.yaml @@ -0,0 +1,29 @@ +name: Valid surface +phases: +- name: gas + species: + - A +- name: aqueous aerosol + species: + - B + - H2O_aq +reactions: +- __comment: hi + aerosol phase: aqueous aerosol + aerosol-phase species: B + aerosol-phase water: H2O_aq + gas phase: gas + gas-phase species: A + name: my henry's law + type: HL_PHASE_TRANSFER +- aerosol phase: aqueous aerosol + aerosol-phase species: B + aerosol-phase water: H2O_aq + gas phase: gas + gas-phase species: A + type: HL_PHASE_TRANSFER +species: +- name: A +- name: B +- name: H2O_aq +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/photolysis/bad_reaction_component.json b/test/unit/unit_configs/reactions/photolysis/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/photolysis/bad_reaction_component.json rename to test/unit/unit_configs/reactions/photolysis/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/photolysis/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/photolysis/bad_reaction_component.yaml new file mode 100644 index 0000000..a275fdb --- /dev/null +++ b/test/unit/unit_configs/reactions/photolysis/bad_reaction_component.yaml @@ -0,0 +1,19 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - coefficient: 0.2 + species name: B + reactants: + - Coefficient: 1.2 + species name: A + type: PHOTOLYSIS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/photolysis/missing_phase.json b/test/unit/unit_configs/reactions/photolysis/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/photolysis/missing_phase.json rename to test/unit/unit_configs/reactions/photolysis/missing_phase.json diff --git a/test/unit/unit_configs/reactions/photolysis/missing_phase.yaml b/test/unit/unit_configs/reactions/photolysis/missing_phase.yaml new file mode 100644 index 0000000..25c60d2 --- /dev/null +++ b/test/unit/unit_configs/reactions/photolysis/missing_phase.yaml @@ -0,0 +1,16 @@ +name: Missing phase +phases: [] +reactions: +- gas phase: gas + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: PHOTOLYSIS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/photolysis/more_than_one_reactant.json b/test/unit/unit_configs/reactions/photolysis/more_than_one_reactant.json similarity index 100% rename from test/unit/json/unit_configs/reactions/photolysis/more_than_one_reactant.json rename to test/unit/unit_configs/reactions/photolysis/more_than_one_reactant.json diff --git a/test/unit/unit_configs/reactions/photolysis/more_than_one_reactant.yaml b/test/unit/unit_configs/reactions/photolysis/more_than_one_reactant.yaml new file mode 100644 index 0000000..3b63cfb --- /dev/null +++ b/test/unit/unit_configs/reactions/photolysis/more_than_one_reactant.yaml @@ -0,0 +1,37 @@ +name: more than one reactant +phases: +- name: gas + species: + - A + - B + - C +- name: surface reacting phase + species: + - A + - B + - C +reactions: +- __comment: hi + gas phase: gas + name: my photolysis + products: + - coefficient: 1 + species name: C + reactants: + - species name: B + - species name: A + scaling factor: 12.3 + type: PHOTOLYSIS +- gas phase: gas + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: PHOTOLYSIS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/photolysis/unknown_species.json b/test/unit/unit_configs/reactions/photolysis/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/photolysis/unknown_species.json rename to test/unit/unit_configs/reactions/photolysis/unknown_species.json diff --git a/test/unit/unit_configs/reactions/photolysis/unknown_species.yaml b/test/unit/unit_configs/reactions/photolysis/unknown_species.yaml new file mode 100644 index 0000000..73a8691 --- /dev/null +++ b/test/unit/unit_configs/reactions/photolysis/unknown_species.yaml @@ -0,0 +1,19 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: PHOTOLYSIS +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/photolysis/valid.json b/test/unit/unit_configs/reactions/photolysis/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/photolysis/valid.json rename to test/unit/unit_configs/reactions/photolysis/valid.json diff --git a/test/unit/unit_configs/reactions/photolysis/valid.yaml b/test/unit/unit_configs/reactions/photolysis/valid.yaml new file mode 100644 index 0000000..b68cc75 --- /dev/null +++ b/test/unit/unit_configs/reactions/photolysis/valid.yaml @@ -0,0 +1,37 @@ +name: Valid photolysis +phases: +- name: gas + species: + - A + - B + - C +- name: surface reacting phase + species: + - A + - B + - C +reactions: +- __comment: hi + gas phase: gas + name: my photolysis + products: + - coefficient: 1 + species name: C + reactants: + - coefficient: 1 + species name: B + scaling factor: 12.3 + type: PHOTOLYSIS +- gas phase: gas + products: + - coefficient: 0.2 + species name: C + reactants: + - coefficient: 1.2 + species name: B + type: PHOTOLYSIS +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.yaml new file mode 100644 index 0000000..a2a0d9d --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase.yaml @@ -0,0 +1,21 @@ +name: Valid surface +phases: +- name: gas + species: + - A +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + name: my simpol + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.yaml new file mode 100644 index 0000000..915eecf --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_aerosol_phase_species_in_aerosol_phase.yaml @@ -0,0 +1,24 @@ +name: Missing gas phase +phases: +- name: gas + species: + - A +- name: aerosol + species: + - A +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + name: my simpol + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.yaml new file mode 100644 index 0000000..1ca88e0 --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase.yaml @@ -0,0 +1,21 @@ +name: Missing gas phase +phases: +- name: aerosol + species: + - B +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + name: my simpol + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.yaml new file mode 100644 index 0000000..2557037 --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/missing_gas_phase_species_in_gas_phase.yaml @@ -0,0 +1,24 @@ +name: Missing gas phase +phases: +- name: gas + species: + - B +- name: aerosol + species: + - B +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + name: my simpol + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/unknown_species.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/unknown_species.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/unknown_species.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/unknown_species.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/unknown_species.yaml new file mode 100644 index 0000000..a1625e4 --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/unknown_species.yaml @@ -0,0 +1,24 @@ +name: Unknown species +phases: +- name: gas + species: + - A +- name: aerosol + species: + - B +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: C + name: my simpol + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/simpol_phase_transfer/valid.json b/test/unit/unit_configs/reactions/simpol_phase_transfer/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/simpol_phase_transfer/valid.json rename to test/unit/unit_configs/reactions/simpol_phase_transfer/valid.json diff --git a/test/unit/unit_configs/reactions/simpol_phase_transfer/valid.yaml b/test/unit/unit_configs/reactions/simpol_phase_transfer/valid.yaml new file mode 100644 index 0000000..7dd4cf1 --- /dev/null +++ b/test/unit/unit_configs/reactions/simpol_phase_transfer/valid.yaml @@ -0,0 +1,35 @@ +name: Valid surface +phases: +- name: gas + species: + - A +- name: aerosol + species: + - B +reactions: +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + __comment: cereal is also soup + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + name: my simpol + type: SIMPOL_PHASE_TRANSFER +- B: + - -1970.0 + - 2.91 + - 0.00196 + - -0.496 + aerosol phase: aerosol + aerosol-phase species: B + gas phase: gas + gas-phase species: A + type: SIMPOL_PHASE_TRANSFER +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/surface/bad_reaction_component.json b/test/unit/unit_configs/reactions/surface/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/surface/bad_reaction_component.json rename to test/unit/unit_configs/reactions/surface/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/surface/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/surface/bad_reaction_component.yaml new file mode 100644 index 0000000..0c0e8ad --- /dev/null +++ b/test/unit/unit_configs/reactions/surface/bad_reaction_component.yaml @@ -0,0 +1,23 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- __coment: key lime pie is superior to all other pies + aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - Species name: B + coefficient: 1 + - coefficient: 1 + species name: C + gas-phase species: A + name: my surface + reaction probability: 0.02 + type: SURFACE +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/surface/missing_aerosol_phase.json b/test/unit/unit_configs/reactions/surface/missing_aerosol_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/surface/missing_aerosol_phase.json rename to test/unit/unit_configs/reactions/surface/missing_aerosol_phase.json diff --git a/test/unit/unit_configs/reactions/surface/missing_aerosol_phase.yaml b/test/unit/unit_configs/reactions/surface/missing_aerosol_phase.yaml new file mode 100644 index 0000000..f3d9c3a --- /dev/null +++ b/test/unit/unit_configs/reactions/surface/missing_aerosol_phase.yaml @@ -0,0 +1,21 @@ +name: Missing aerosol phase +phases: +- name: gas + species: + - A + - B + - C +reactions: +- aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - __optional thing: hello + species name: B + - species name: C + gas-phase species: A + type: SURFACE +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/surface/missing_gas_phase.json b/test/unit/unit_configs/reactions/surface/missing_gas_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/surface/missing_gas_phase.json rename to test/unit/unit_configs/reactions/surface/missing_gas_phase.json diff --git a/test/unit/unit_configs/reactions/surface/missing_gas_phase.yaml b/test/unit/unit_configs/reactions/surface/missing_gas_phase.yaml new file mode 100644 index 0000000..c8dc603 --- /dev/null +++ b/test/unit/unit_configs/reactions/surface/missing_gas_phase.yaml @@ -0,0 +1,16 @@ +name: Missing aerosol phase +phases: [] +reactions: +- aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - __optional thing: hello + species name: B + - species name: C + gas-phase species: A + type: SURFACE +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/surface/unknown_species.json b/test/unit/unit_configs/reactions/surface/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/surface/unknown_species.json rename to test/unit/unit_configs/reactions/surface/unknown_species.json diff --git a/test/unit/unit_configs/reactions/surface/unknown_species.yaml b/test/unit/unit_configs/reactions/surface/unknown_species.yaml new file mode 100644 index 0000000..fd00b09 --- /dev/null +++ b/test/unit/unit_configs/reactions/surface/unknown_species.yaml @@ -0,0 +1,21 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + gas-phase species: A + reaction probability: 0.02 + type: SURFACE +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/surface/valid.json b/test/unit/unit_configs/reactions/surface/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/surface/valid.json rename to test/unit/unit_configs/reactions/surface/valid.json diff --git a/test/unit/unit_configs/reactions/surface/valid.yaml b/test/unit/unit_configs/reactions/surface/valid.yaml new file mode 100644 index 0000000..7ffecac --- /dev/null +++ b/test/unit/unit_configs/reactions/surface/valid.yaml @@ -0,0 +1,38 @@ +name: Valid surface +phases: +- name: gas + species: + - A + - B + - C +- name: surface reacting phase + species: + - A + - B + - C +reactions: +- __comment: key lime pie is superior to all other pies + aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - coefficient: 1 + species name: B + - coefficient: 1 + species name: C + gas-phase species: A + name: my surface + reaction probability: 0.02 + type: SURFACE +- aerosol phase: surface reacting phase + gas phase: gas + gas-phase products: + - __optional thing: hello + species name: B + - species name: C + gas-phase species: A + type: SURFACE +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/troe/bad_reaction_component.json b/test/unit/unit_configs/reactions/troe/bad_reaction_component.json similarity index 100% rename from test/unit/json/unit_configs/reactions/troe/bad_reaction_component.json rename to test/unit/unit_configs/reactions/troe/bad_reaction_component.json diff --git a/test/unit/unit_configs/reactions/troe/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/troe/bad_reaction_component.yaml new file mode 100644 index 0000000..375f205 --- /dev/null +++ b/test/unit/unit_configs/reactions/troe/bad_reaction_component.yaml @@ -0,0 +1,17 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - species name: B + reactants: + - Species name: A + type: TROE +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/troe/missing_phase.json b/test/unit/unit_configs/reactions/troe/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/troe/missing_phase.json rename to test/unit/unit_configs/reactions/troe/missing_phase.json diff --git a/test/unit/unit_configs/reactions/troe/missing_phase.yaml b/test/unit/unit_configs/reactions/troe/missing_phase.yaml new file mode 100644 index 0000000..8b548db --- /dev/null +++ b/test/unit/unit_configs/reactions/troe/missing_phase.yaml @@ -0,0 +1,14 @@ +name: Missing phase +phases: [] +reactions: +- gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: TROE +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/troe/unknown_species.json b/test/unit/unit_configs/reactions/troe/unknown_species.json similarity index 100% rename from test/unit/json/unit_configs/reactions/troe/unknown_species.json rename to test/unit/unit_configs/reactions/troe/unknown_species.json diff --git a/test/unit/unit_configs/reactions/troe/unknown_species.yaml b/test/unit/unit_configs/reactions/troe/unknown_species.yaml new file mode 100644 index 0000000..f3eb67e --- /dev/null +++ b/test/unit/unit_configs/reactions/troe/unknown_species.yaml @@ -0,0 +1,18 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- __my comment: {} + gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: TROE +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/troe/valid.json b/test/unit/unit_configs/reactions/troe/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/troe/valid.json rename to test/unit/unit_configs/reactions/troe/valid.json diff --git a/test/unit/unit_configs/reactions/troe/valid.yaml b/test/unit/unit_configs/reactions/troe/valid.yaml new file mode 100644 index 0000000..b84d35a --- /dev/null +++ b/test/unit/unit_configs/reactions/troe/valid.yaml @@ -0,0 +1,40 @@ +name: Valid troe +phases: +- name: gas + species: + - A + - B + - C +reactions: +- __my object: + a: 1.0 + gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: TROE +- Fc: 1.3 + N: 32.1 + gas phase: gas + k0_A: 32.1 + k0_B: -2.3 + k0_C: 102.3 + kinf_A: 63.4 + kinf_B: -1.3 + kinf_C: 908.5 + name: my troe + products: + - __optional thing: hello + coefficient: 0.2 + species name: A + - coefficient: 1.2 + species name: B + reactants: + - species name: C + type: TROE +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/tunneling/bad_reaction_component.json b/test/unit/unit_configs/reactions/tunneling/bad_reaction_component.json similarity index 94% rename from test/unit/json/unit_configs/reactions/tunneling/bad_reaction_component.json rename to test/unit/unit_configs/reactions/tunneling/bad_reaction_component.json index 89830d2..d19835b 100644 --- a/test/unit/json/unit_configs/reactions/tunneling/bad_reaction_component.json +++ b/test/unit/unit_configs/reactions/tunneling/bad_reaction_component.json @@ -20,7 +20,7 @@ ], "reactions": [ { - "type": "TROE", + "type": "TUNNELING", "gas phase": "gas", "reactants": [ { diff --git a/test/unit/unit_configs/reactions/tunneling/bad_reaction_component.yaml b/test/unit/unit_configs/reactions/tunneling/bad_reaction_component.yaml new file mode 100644 index 0000000..25ed0ab --- /dev/null +++ b/test/unit/unit_configs/reactions/tunneling/bad_reaction_component.yaml @@ -0,0 +1,17 @@ +name: Bad reaction component +phases: +- name: gas + species: + - A + - B +reactions: +- gas phase: gas + products: + - species name: B + reactants: + - Species name: A + type: TUNNELING +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/tunneling/missing_phase.json b/test/unit/unit_configs/reactions/tunneling/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/tunneling/missing_phase.json rename to test/unit/unit_configs/reactions/tunneling/missing_phase.json diff --git a/test/unit/unit_configs/reactions/tunneling/missing_phase.yaml b/test/unit/unit_configs/reactions/tunneling/missing_phase.yaml new file mode 100644 index 0000000..0ee642a --- /dev/null +++ b/test/unit/unit_configs/reactions/tunneling/missing_phase.yaml @@ -0,0 +1,18 @@ +name: Missing phase +phases: [] +reactions: +- A: 123.45 + B: 1200.0 + C: 100000000.0 + gas phase: gas + products: + - species name: C + reactants: + - coefficient: 1 + species name: B + type: TUNNELING +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/tunneling/unknown_species.json b/test/unit/unit_configs/reactions/tunneling/unknown_species.json similarity index 94% rename from test/unit/json/unit_configs/reactions/tunneling/unknown_species.json rename to test/unit/unit_configs/reactions/tunneling/unknown_species.json index ac09162..06d3ed2 100644 --- a/test/unit/json/unit_configs/reactions/tunneling/unknown_species.json +++ b/test/unit/unit_configs/reactions/tunneling/unknown_species.json @@ -21,7 +21,7 @@ "reactions": [ { "__my comment": {}, - "type": "TROE", + "type": "TUNNELING", "gas phase": "gas", "reactants": [ { diff --git a/test/unit/unit_configs/reactions/tunneling/unknown_species.yaml b/test/unit/unit_configs/reactions/tunneling/unknown_species.yaml new file mode 100644 index 0000000..0b8faa0 --- /dev/null +++ b/test/unit/unit_configs/reactions/tunneling/unknown_species.yaml @@ -0,0 +1,18 @@ +name: Unknown species +phases: +- name: gas + species: + - A + - B +reactions: +- __my comment: {} + gas phase: gas + products: + - species name: C + reactants: + - species name: A + type: TUNNELING +species: +- name: A +- name: B +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/tunneling/valid.json b/test/unit/unit_configs/reactions/tunneling/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/tunneling/valid.json rename to test/unit/unit_configs/reactions/tunneling/valid.json diff --git a/test/unit/unit_configs/reactions/tunneling/valid.yaml b/test/unit/unit_configs/reactions/tunneling/valid.yaml new file mode 100644 index 0000000..e88c977 --- /dev/null +++ b/test/unit/unit_configs/reactions/tunneling/valid.yaml @@ -0,0 +1,35 @@ +name: Valid tunneling +phases: +- name: gas + species: + - A + - B + - C +reactions: +- A: 123.45 + B: 1200.0 + C: 100000000.0 + gas phase: gas + products: + - species name: C + reactants: + - coefficient: 1 + species name: B + type: TUNNELING +- gas phase: gas + name: my tunneling + products: + - __optional thing: hello + coefficient: 0.2 + species name: A + - coefficient: 1.2 + species name: B + reactants: + - coefficient: 1 + species name: B + type: TUNNELING +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/wet_deposition/missing_phase.json b/test/unit/unit_configs/reactions/wet_deposition/missing_phase.json similarity index 100% rename from test/unit/json/unit_configs/reactions/wet_deposition/missing_phase.json rename to test/unit/unit_configs/reactions/wet_deposition/missing_phase.json diff --git a/test/unit/unit_configs/reactions/wet_deposition/missing_phase.yaml b/test/unit/unit_configs/reactions/wet_deposition/missing_phase.yaml new file mode 100644 index 0000000..c1a9fe0 --- /dev/null +++ b/test/unit/unit_configs/reactions/wet_deposition/missing_phase.yaml @@ -0,0 +1,11 @@ +name: Missing phase +phases: [] +reactions: +- aerosol phase: cloud + name: rxn cloud + type: WET_DEPOSITION +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/reactions/wet_deposition/valid.json b/test/unit/unit_configs/reactions/wet_deposition/valid.json similarity index 100% rename from test/unit/json/unit_configs/reactions/wet_deposition/valid.json rename to test/unit/unit_configs/reactions/wet_deposition/valid.json diff --git a/test/unit/unit_configs/reactions/wet_deposition/valid.yaml b/test/unit/unit_configs/reactions/wet_deposition/valid.yaml new file mode 100644 index 0000000..77df4e9 --- /dev/null +++ b/test/unit/unit_configs/reactions/wet_deposition/valid.yaml @@ -0,0 +1,21 @@ +name: Valid wet deposition +phases: +- name: cloud + species: + - A + - B + - C +reactions: +- __comment: Tuxedo cats are the best + aerosol phase: cloud + name: rxn cloud + scaling factor: 12.3 + type: WET_DEPOSITION +- aerosol phase: cloud + name: rxn cloud2 + type: WET_DEPOSITION +species: +- name: A +- name: B +- name: C +version: 1.0.0 diff --git a/test/unit/json/unit_configs/species/duplicate_species.json b/test/unit/unit_configs/species/duplicate_species.json similarity index 100% rename from test/unit/json/unit_configs/species/duplicate_species.json rename to test/unit/unit_configs/species/duplicate_species.json diff --git a/test/unit/unit_configs/species/duplicate_species.yaml b/test/unit/unit_configs/species/duplicate_species.yaml new file mode 100644 index 0000000..ffe295e --- /dev/null +++ b/test/unit/unit_configs/species/duplicate_species.yaml @@ -0,0 +1,7 @@ +name: Duplicate Species +phases: [] +reactions: [] +species: +- name: A +- name: A +version: 1.0.0 diff --git a/test/unit/json/unit_configs/species/invalid_key.json b/test/unit/unit_configs/species/invalid_key.json similarity index 100% rename from test/unit/json/unit_configs/species/invalid_key.json rename to test/unit/unit_configs/species/invalid_key.json diff --git a/test/unit/unit_configs/species/invalid_key.yaml b/test/unit/unit_configs/species/invalid_key.yaml new file mode 100644 index 0000000..550d1ae --- /dev/null +++ b/test/unit/unit_configs/species/invalid_key.yaml @@ -0,0 +1,7 @@ +name: Invalid key +phases: [] +reactions: [] +species: +- _absolute tolerance: 1.0e-30 + name: A +version: 1.0.0 diff --git a/test/unit/json/unit_configs/species/missing_required_key.json b/test/unit/unit_configs/species/missing_required_key.json similarity index 100% rename from test/unit/json/unit_configs/species/missing_required_key.json rename to test/unit/unit_configs/species/missing_required_key.json diff --git a/test/unit/unit_configs/species/missing_required_key.yaml b/test/unit/unit_configs/species/missing_required_key.yaml new file mode 100644 index 0000000..78a1a43 --- /dev/null +++ b/test/unit/unit_configs/species/missing_required_key.yaml @@ -0,0 +1,6 @@ +name: Invalid key +phases: [] +reactions: [] +species: +- Name: A +version: 1.0.0 diff --git a/test/unit/json/unit_configs/species/valid_species.json b/test/unit/unit_configs/species/valid_species.json similarity index 100% rename from test/unit/json/unit_configs/species/valid_species.json rename to test/unit/unit_configs/species/valid_species.json diff --git a/test/unit/unit_configs/species/valid_species.yaml b/test/unit/unit_configs/species/valid_species.yaml new file mode 100644 index 0000000..0b8f1fe --- /dev/null +++ b/test/unit/unit_configs/species/valid_species.yaml @@ -0,0 +1,19 @@ +name: Valid species configuration +phases: [] +reactions: [] +species: +- __absolute tolerance: 1.0e-30 + name: A +- HLC exponential factor [K]: 6340 + HLC(298K) [mol m-3 Pa-1]: 1.011596348 + N star: 1.74 + __absolute tolerance: 1.0e-10 + density [kg m-3]: 1000.0 + diffusion coefficient [m2 s-1]: 1.46e-05 + molecular weight [kg mol-1]: 0.0340147 + name: H2O2 +- __absolute tolerance: 1.0e-20 + density [kg m-3]: 1000.0 + molecular weight [kg mol-1]: 0.5 + name: aerosol stuff +version: 1.0.0 diff --git a/test/unit/yaml/CMakeLists.txt b/test/unit/yaml/CMakeLists.txt deleted file mode 100644 index e69de29..0000000