Skip to content

Commit

Permalink
Merge pull request #17 from open-atmos/parse_troe
Browse files Browse the repository at this point in the history
Parse troe
  • Loading branch information
K20shores authored Jan 18, 2024
2 parents 0fa9e88 + 238a02c commit 3e768bf
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 5 deletions.
3 changes: 3 additions & 0 deletions examples/full_configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
{
"name": "C"
},
{
"name": "M"
},
{
"name": "H2O2",
"HLC(298K) [mol m-3 Pa-1]": 1.011596348,
Expand Down
17 changes: 17 additions & 0 deletions include/open_atmos/mechanism_configuration/validation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ namespace open_atmos
const std::string E = "E";
const std::string Ea = "Ea";

// Troe
const std::string Troe_key = "TROE";
const std::string k0_A = "k0_A";
const std::string k0_B = "k0_B";
const std::string k0_C = "k0_C";
const std::string kinf_A = "kinf_A";
const std::string kinf_B = "kinf_B";
const std::string kinf_C = "kinf_C";
const std::string Fc = "Fc";
const std::string N = "N";

} keys;

struct Configuration
Expand Down Expand Up @@ -89,6 +100,12 @@ namespace open_atmos
const std::vector<std::string> optional_keys{ keys.A, keys.B, keys.C, keys.D, keys.E, keys.Ea, keys.name };
} arrhenius;

struct Troe
{
const std::vector<std::string> required_keys{ keys.products, keys.reactants, keys.type, keys.gas_phase };
const std::vector<std::string> 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 Mechanism
{
const std::vector<std::string> required_keys{};
Expand Down
37 changes: 34 additions & 3 deletions include/open_atmos/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@ namespace open_atmos
struct Species
{
std::string name;

std::map<std::string, double> optional_numerical_properties;

/// @brief Unknown properties, prefixed with two underscores (__)
std::unordered_map<std::string, std::string> unknown_properties;
};

struct Phase
{
std::string name;
std::vector<std::string> species;
/// @brief Unknown properties, prefixed with two underscores (__)
std::unordered_map<std::string, std::string> unknown_properties;
};

struct ReactionComponent
{
std::string species_name;
double coefficient;
/// @brief Unknown properties, prefixed with two underscores (__)
std::unordered_map<std::string, std::string> unknown_properties;
};

Expand All @@ -47,7 +48,6 @@ namespace open_atmos
double D{ 300 };
/// @brief A factor that determines pressure dependence [Pa-1]
double E{ 0 };

/// @brief A list of reactants
std::vector<ReactionComponent> reactants;
/// @brief A list of products
Expand All @@ -56,13 +56,44 @@ namespace open_atmos
std::string name;
/// @brief An identifier indicating which gas phase this reaction takes place in
std::string gas_phase;
/// @brief Unknown properties, prefixed with two underscores (__)
std::unordered_map<std::string, std::string> unknown_properties;
};

struct Troe
{
/// @brief low-pressure pre-exponential factor
double k0_A = 1.0;
/// @brief low-pressure temperature-scaling parameter
double k0_B = 0.0;
/// @brief low-pressure exponential factor
double k0_C = 0.0;
/// @brief high-pressure pre-exponential factor
double kinf_A = 1.0;
/// @brief high-pressure temperature-scaling parameter
double kinf_B = 0.0;
/// @brief high-pressure exponential factor
double kinf_C = 0.0;
/// @brief Troe F_c parameter
double Fc = 0.6;
/// @brief Troe N parameter
double N = 1.0;
/// @brief A list of reactants
std::vector<ReactionComponent> reactants;
/// @brief A list of products
std::vector<ReactionComponent> products;
/// @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 Unknown properties, prefixed with two underscores (__)
std::unordered_map<std::string, std::string> unknown_properties;
};

struct Reactions
{
std::vector<types::Arrhenius> arrhenius;
std::vector<types::Troe> troe;
};

struct Mechanism
Expand Down
113 changes: 113 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,109 @@ namespace open_atmos
return { status, arrhenius };
}

std::pair<ConfigParseStatus, types::Troe> ParseTroe(const json& object, const std::vector<types::Species> existing_species)
{
ConfigParseStatus status = ConfigParseStatus::Success;
types::Troe troe;

status = ValidateSchema(object, validation::troe.required_keys, validation::troe.optional_keys);
if (status == ConfigParseStatus::Success)
{
std::vector<types::ReactionComponent> products{};
for (const auto& product : object[validation::keys.products])
{
auto product_parse = ParseReactionComponent(product);
status = product_parse.first;
if (status != ConfigParseStatus::Success)
{
break;
}
products.push_back(product_parse.second);
}

std::vector<types::ReactionComponent> reactants{};
for (const auto& reactant : object[validation::keys.reactants])
{
auto reactant_parse = ParseReactionComponent(reactant);
status = reactant_parse.first;
if (status != ConfigParseStatus::Success)
{
break;
}
reactants.push_back(reactant_parse.second);
}

if (object.contains(validation::keys.k0_A))
{
troe.k0_A = object[validation::keys.k0_A].get<double>();
}
if (object.contains(validation::keys.k0_B))
{
troe.k0_B = object[validation::keys.k0_B].get<double>();
}
if (object.contains(validation::keys.k0_C))
{
troe.k0_C = object[validation::keys.k0_C].get<double>();
}
if (object.contains(validation::keys.kinf_A))
{
troe.kinf_A = object[validation::keys.kinf_A].get<double>();
}
if (object.contains(validation::keys.kinf_B))
{
troe.kinf_B = object[validation::keys.kinf_B].get<double>();
}
if (object.contains(validation::keys.kinf_C))
{
troe.kinf_C = object[validation::keys.kinf_C].get<double>();
}
if (object.contains(validation::keys.Fc))
{
troe.Fc = object[validation::keys.Fc].get<double>();
}
if (object.contains(validation::keys.N))
{
troe.N = object[validation::keys.N].get<double>();
}

if (object.contains(validation::keys.name))
{
troe.name = object[validation::keys.name].get<std::string>();
}

auto comments = GetComments(object, validation::troe.required_keys, validation::troe.optional_keys);

std::unordered_map<std::string, std::string> unknown_properties;
for (const auto& key : comments)
{
std::string val = object[key].dump();
unknown_properties[key] = val;
}

std::vector<std::string> 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;
}

troe.gas_phase = object[validation::keys.gas_phase].get<std::string>();
troe.products = products;
troe.reactants = reactants;
troe.unknown_properties = unknown_properties;
}

return { status, troe };
}

std::pair<ConfigParseStatus, types::Reactions> ParseReactions(const json& objects, const std::vector<types::Species> existing_species)
{
ConfigParseStatus status = ConfigParseStatus::Success;
Expand All @@ -424,6 +527,16 @@ namespace open_atmos
}
reactions.arrhenius.push_back(arrhenius_parse.second);
}
else if (type == validation::keys.Troe_key)
{
auto troe_parse = ParseTroe(object, existing_species);
status = troe_parse.first;
if (status != ConfigParseStatus::Success)
{
break;
}
reactions.troe.push_back(troe_parse.second);
}
}

return { status, reactions };
Expand Down
3 changes: 2 additions & 1 deletion test/integration/test_json_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ TEST(JsonParser, ParsesFullConfiguration)
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(), 10);
EXPECT_EQ(mechanism.species.size(), 11);
EXPECT_EQ(mechanism.reactions.arrhenius.size(), 1);
EXPECT_EQ(mechanism.reactions.troe.size(), 1);
}

TEST(JsonParser, ParserReportsBadFiles)
Expand Down
1 change: 1 addition & 0 deletions test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ include(test_util)
create_standard_test(NAME parse_species SOURCES test_parse_species.cpp)
create_standard_test(NAME parse_phases SOURCES test_parse_phases.cpp)
create_standard_test(NAME parse_arrhenius SOURCES test_parse_arrhenius.cpp)
create_standard_test(NAME parse_troe SOURCES test_parse_troe.cpp)

################################################################################
# Copy test data
Expand Down
68 changes: 68 additions & 0 deletions test/unit/test_parse_troe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <gtest/gtest.h>

#include <open_atmos/mechanism_configuration/parser.hpp>

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);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.0.0",
"name": "Mutually Exclusive",
"name": "Bad reaction component",
"species": [
{
"name": "A"
Expand Down
37 changes: 37 additions & 0 deletions test/unit/unit_configs/reactions/troe/bad_reaction_component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"version": "1.0.0",
"name": "Bad reaction component",
"species": [
{
"name": "A"
},
{
"name": "B"
}
],
"phases": [
{
"name": "gas",
"species": [
"A",
"B"
]
}
],
"reactions": [
{
"type": "TROE",
"gas phase": "gas",
"reactants": [
{
"Species name": "A"
}
],
"products": [
{
"species name": "B"
}
]
}
]
}
Loading

0 comments on commit 3e768bf

Please sign in to comment.