From bd362e65e8fdd2511b405a2af5a83f71c46532eb Mon Sep 17 00:00:00 2001 From: Kyle Shores Date: Mon, 22 Jan 2024 08:55:05 -0600 Subject: [PATCH] parsing wet deposition --- examples/full_configuration.json | 1 - .../mechanism_configuration/validation.hpp | 3 +- include/open_atmos/types.hpp | 10 ++-- src/parser.cpp | 55 ++++++++++++++++++- test/unit/test_parse_emission.cpp | 4 +- test/unit/test_parse_first_order_loss.cpp | 4 +- test/unit/test_parse_photolysis.cpp | 4 +- test/unit/test_parse_wet_deposition.cpp | 32 +++-------- .../wet_deposition/missing_phase.json | 24 ++++++++ .../reactions/wet_deposition/valid.json | 39 +++++++++++++ 10 files changed, 134 insertions(+), 42 deletions(-) create mode 100644 test/unit/unit_configs/reactions/wet_deposition/missing_phase.json create mode 100644 test/unit/unit_configs/reactions/wet_deposition/valid.json diff --git a/examples/full_configuration.json b/examples/full_configuration.json index 7c94eaf..04b69f8 100644 --- a/examples/full_configuration.json +++ b/examples/full_configuration.json @@ -362,7 +362,6 @@ }, { "type": "WET_DEPOSITION", - "gas phase": "gas", "aerosol phase": "cloud", "name": "rxn cloud", "scaling factor": 12.3 diff --git a/include/open_atmos/mechanism_configuration/validation.hpp b/include/open_atmos/mechanism_configuration/validation.hpp index e14369d..12bb7c8 100644 --- a/include/open_atmos/mechanism_configuration/validation.hpp +++ b/include/open_atmos/mechanism_configuration/validation.hpp @@ -114,7 +114,6 @@ namespace open_atmos // also // scaling factor // aerosol phase - // gas phase } keys; @@ -206,7 +205,7 @@ namespace open_atmos struct WetDeposition { - const std::vector required_keys{ keys.gas_phase, keys.aerosol_phase, keys.type }; + const std::vector required_keys{ keys.aerosol_phase, keys.type }; const std::vector optional_keys{ keys.name, keys.scaling_factor }; } wet_deposition; diff --git a/include/open_atmos/types.hpp b/include/open_atmos/types.hpp index bb6fd0b..fbfda1e 100644 --- a/include/open_atmos/types.hpp +++ b/include/open_atmos/types.hpp @@ -182,7 +182,7 @@ namespace open_atmos struct Photolysis { /// @brief Scaling factor to apply to user-provided rate constants - double scaling_factor_{ 1.0 }; + double scaling_factor{ 1.0 }; /// @brief A list of reactants std::vector reactants; /// @brief A list of products @@ -198,7 +198,7 @@ namespace open_atmos struct Emission { /// @brief Scaling factor to apply to user-provided rate constants - double scaling_factor_{ 1.0 }; + double scaling_factor{ 1.0 }; /// @brief A list of products std::vector products; /// @brief An identifier, optional, uniqueness not enforced @@ -212,7 +212,7 @@ namespace open_atmos struct FirstOrderLoss { /// @brief Scaling factor to apply to user-provided rate constants - double scaling_factor_{ 1.0 }; + double scaling_factor{ 1.0 }; /// @brief A list of reactants std::vector reactants; /// @brief An identifier, optional, uniqueness not enforced @@ -226,11 +226,9 @@ namespace open_atmos struct WetDeposition { /// @brief Scaling factor to apply to user-provided rate constants - double scaling_factor_{ 1.0 }; + double scaling_factor{ 1.0 }; /// @brief An identifier, optional, uniqueness not enforced std::string name; - /// @brief An identifier indicating which gas phase this reaction takes place in - std::string gas_phase; /// @brief An identifier indicating which aerosol phase this reaction takes place in std::string aerosol_phase; /// @brief Unknown properties, prefixed with two underscores (__) diff --git a/src/parser.cpp b/src/parser.cpp index 96c7763..0c378ca 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1024,7 +1024,7 @@ namespace open_atmos if (object.contains(validation::keys.scaling_factor)) { - photolysis.scaling_factor_ = object[validation::keys.scaling_factor].get(); + photolysis.scaling_factor = object[validation::keys.scaling_factor].get(); } if (object.contains(validation::keys.name)) @@ -1105,7 +1105,7 @@ namespace open_atmos if (object.contains(validation::keys.scaling_factor)) { - emission.scaling_factor_ = object[validation::keys.scaling_factor].get(); + emission.scaling_factor = object[validation::keys.scaling_factor].get(); } if (object.contains(validation::keys.name)) @@ -1176,7 +1176,7 @@ namespace open_atmos if (object.contains(validation::keys.scaling_factor)) { - first_order_loss.scaling_factor_ = object[validation::keys.scaling_factor].get(); + first_order_loss.scaling_factor = object[validation::keys.scaling_factor].get(); } if (object.contains(validation::keys.name)) @@ -1224,6 +1224,55 @@ namespace open_atmos return { status, first_order_loss }; } + /// @brief Parses a wet deposition reaction + /// @param object A json object that should have information containing arrhenius parameters + /// @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 First Order Loss parameters + std::pair + ParseWetDeposition(const json& object, const std::vector existing_species, const std::vector existing_phases) + { + 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(); + } + + auto comments = GetComments(object, validation::wet_deposition.required_keys, validation::wet_deposition.optional_keys); + + std::unordered_map unknown_properties; + for (const auto& key : comments) + { + std::string val = object[key].dump(); + unknown_properties[key] = val; + } + + 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 = unknown_properties; + } + + return { status, wet_deposition }; + } + /// @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 diff --git a/test/unit/test_parse_emission.cpp b/test/unit/test_parse_emission.cpp index fbe6424..0ce87ab 100644 --- a/test/unit/test_parse_emission.cpp +++ b/test/unit/test_parse_emission.cpp @@ -14,7 +14,7 @@ TEST(JsonParser, CanParseValidEmissionReaction) 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].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); @@ -22,7 +22,7 @@ TEST(JsonParser, CanParseValidEmissionReaction) 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].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); diff --git a/test/unit/test_parse_first_order_loss.cpp b/test/unit/test_parse_first_order_loss.cpp index 30de586..f6226f6 100644 --- a/test/unit/test_parse_first_order_loss.cpp +++ b/test/unit/test_parse_first_order_loss.cpp @@ -14,7 +14,7 @@ TEST(JsonParser, CanParseValidFirstOrderLossReaction) 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].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); @@ -22,7 +22,7 @@ TEST(JsonParser, CanParseValidFirstOrderLossReaction) 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].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); diff --git a/test/unit/test_parse_photolysis.cpp b/test/unit/test_parse_photolysis.cpp index eff3e9d..1089126 100644 --- a/test/unit/test_parse_photolysis.cpp +++ b/test/unit/test_parse_photolysis.cpp @@ -14,7 +14,7 @@ TEST(JsonParser, CanParseValidPhotolysisReaction) 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].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); @@ -25,7 +25,7 @@ TEST(JsonParser, CanParseValidPhotolysisReaction) 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].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); diff --git a/test/unit/test_parse_wet_deposition.cpp b/test/unit/test_parse_wet_deposition.cpp index a5b18b6..3b1bd1e 100644 --- a/test/unit/test_parse_wet_deposition.cpp +++ b/test/unit/test_parse_wet_deposition.cpp @@ -10,33 +10,17 @@ TEST(JsonParser, CanParseValidWetDepositionReaction) 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(), 1); + EXPECT_EQ(mechanism.reactions.wet_deposition.size(), 2); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].name, "my arrhenius"); - EXPECT_EQ(mechanism.reactions.wet_deposition[0].gas_phase, "gas"); + 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["__solver_param"], "0.1"); -} - -TEST(JsonParser, WetDepositionDetectsUnknownSpecies) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/unknown_species.json")); - EXPECT_EQ(status, ConfigParseStatus::ReactionRequiresUnknownSpecies); -} + EXPECT_EQ(mechanism.reactions.wet_deposition[0].unknown_properties["__comment"], "\"Tuxedo cats are the best\""); -TEST(JsonParser, WetDepositionDetectsMutuallyExclusiveOptions) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/mutually_exclusive.json")); - EXPECT_EQ(status, ConfigParseStatus::MutuallyExclusiveOption); -} - -TEST(JsonParser, WetDepositionDetectsBadReactionComponent) -{ - JsonParser parser; - auto [status, mechanism] = parser.Parse(std::string("unit_configs/reactions/wet_deposition/bad_reaction_component.json")); - EXPECT_EQ(status, ConfigParseStatus::RequiredKeyNotFound); + 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) diff --git a/test/unit/unit_configs/reactions/wet_deposition/missing_phase.json b/test/unit/unit_configs/reactions/wet_deposition/missing_phase.json new file mode 100644 index 0000000..bc25732 --- /dev/null +++ b/test/unit/unit_configs/reactions/wet_deposition/missing_phase.json @@ -0,0 +1,24 @@ +{ + "version": "1.0.0", + "name": "Missing phase", + "species": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "C" + } + ], + "phases": [ + ], + "reactions": [ + { + "type": "WET_DEPOSITION", + "aerosol phase": "cloud", + "name": "rxn cloud" + } + ] +} \ No newline at end of file diff --git a/test/unit/unit_configs/reactions/wet_deposition/valid.json b/test/unit/unit_configs/reactions/wet_deposition/valid.json new file mode 100644 index 0000000..0ad861c --- /dev/null +++ b/test/unit/unit_configs/reactions/wet_deposition/valid.json @@ -0,0 +1,39 @@ +{ + "version": "1.0.0", + "name": "Valid wet deposition", + "species": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "C" + } + ], + "phases": [ + { + "name": "cloud", + "species": [ + "A", + "B", + "C" + ] + } + ], + "reactions": [ + { + "type": "WET_DEPOSITION", + "aerosol phase": "cloud", + "name": "rxn cloud", + "scaling factor": 12.3, + "__comment": "Tuxedo cats are the best" + }, + { + "type": "WET_DEPOSITION", + "aerosol phase": "cloud", + "name": "rxn cloud2" + } + ] +} \ No newline at end of file