Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion examples/v1/full_configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -328,5 +328,58 @@
}
]
}
]
],
"emissions": {
"inventories": [
{
"name": "cams global anthro",
"directory": "cams/v6.2",
"file pattern": "CAMS-GLOB-ANT_v6.2_{YYYY}-{MM}.nc",
"convention": "uptempo"
}
],
"species maps": [
{
"name": "MOZART-T1 from CAMS",
"mappings": [
{
"inventory species": "NOx",
"mechanism species": "NO",
"scaling factor": 0.9
},
{
"inventory species": "NOx",
"mechanism species": "NO2",
"scaling factor": 0.1
},
{
"inventory species": "CO",
"mechanism species": "CO"
},
{
"inventory species": "bc_anth_sum",
"mechanism species": "BC"
}
]
}
],
"regridding": {
"type": "none"
},
"sources": [
{
"name": "cams anthro",
"mode": "offline",
"type": "anthropogenic",
"inventory": "cams global anthro",
"species map": "MOZART-T1 from CAMS",
"temporal interpolation": "linear",
"vertical injection": "surface",
"category": 0,
"hierarchy": 1,
"scaling factor": 1.0,
"sector": "anthropogenic"
}
]
}
}
35 changes: 34 additions & 1 deletion examples/v1/full_configuration.yaml
Comment thread
K20shores marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,37 @@ reactions:
coefficient: 1
products:
- species name: C
coefficient: 1
coefficient: 1
emissions:
inventories:
- name: cams global anthro
directory: cams/v6.2
file pattern: CAMS-GLOB-ANT_v6.2_{YYYY}-{MM}.nc
convention: uptempo
species maps:
- name: MOZART-T1 from CAMS
mappings:
- inventory species: NOx
mechanism species: NO
scaling factor: 0.9
- inventory species: NOx
mechanism species: NO2
scaling factor: 0.1
- inventory species: CO
mechanism species: CO
- inventory species: bc_anth_sum
mechanism species: BC
regridding:
type: none
sources:
- name: cams anthro
mode: offline
type: anthropogenic
inventory: cams global anthro
species map: MOZART-T1 from CAMS
temporal interpolation: linear
vertical injection: surface
category: 0
hierarchy: 1
scaling factor: 1.0
sector: anthropogenic
11 changes: 11 additions & 0 deletions include/mechanism_configuration/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ namespace mechanism_configuration
FileNotFound,
UnexpectedError,
EmptyObject,
// Emissions-specific error codes
DuplicateInventoryDetected,
DuplicateSpeciesMapDetected,
DuplicateSourceDetected,
DuplicateCategoryHierarchy,
SourceRequiresUnknownInventory,
SourceRequiresUnknownSpeciesMap,
SpeciesMapScalingExceedsOne,
OnlineSourcesNotSupported,
UnsupportedRegriddingType,
UnsupportedVerticalInjection,
};

std::string ErrorCodeToString(const ErrorCode& status);
Expand Down
3 changes: 3 additions & 0 deletions include/mechanism_configuration/mechanism.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <filesystem>
#include <iostream>
#include <optional>
#include <string>
#include <variant>

Expand Down Expand Up @@ -90,5 +91,7 @@ namespace mechanism_configuration
Version version;
/// @brief Relative tolerance for solver (optional, default: 1e-6)
double relative_tolerance{ 1e-6 };
/// @brief Emissions configuration (optional)
std::optional<types::EmissionsConfig> emissions;
};
} // namespace mechanism_configuration
84 changes: 84 additions & 0 deletions include/mechanism_configuration/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,88 @@ namespace mechanism_configuration::types
std::vector<LambdaRateConstant> lambda_rate_constant;
};

// ── Emissions configuration types ─────────────────────────────────────────

struct SpeciesMapping
{
std::string inventory_species;
std::string mechanism_species;
double scaling_factor{ 1.0 };
};

struct SpeciesMap
Comment thread
K20shores marked this conversation as resolved.
{
std::string name;
std::vector<SpeciesMapping> mappings;
};

struct Inventory
{
Comment thread
K20shores marked this conversation as resolved.
std::string name;
std::string directory;
std::string file_pattern;
std::string convention;
};

enum class SourceMode
{
Offline,
};

enum class SourceType
{
Anthropogenic,
Fire,
Biogenic,
Dust,
SeaSalt,
Lightning,
};

enum class TemporalInterpolation
{
Linear,
Nearest,
None,
};

enum class VerticalInjection
{
Surface,
};

struct SourceDescriptor
{
std::string name;
SourceMode mode{ SourceMode::Offline };
SourceType type{ SourceType::Anthropogenic };
std::string inventory;
std::string species_map;
TemporalInterpolation temporal_interpolation{ TemporalInterpolation::Linear };
VerticalInjection vertical_injection{ VerticalInjection::Surface };
int category{ 0 };
int hierarchy{ 1 };
double scaling_factor{ 1.0 };
std::string sector;
std::unordered_map<std::string, std::string> unknown_properties;
};

enum class RegriddingType
{
None,
};

struct Regridding
{
RegriddingType type{ RegriddingType::None };
};

struct EmissionsConfig
{
std::vector<Inventory> inventories;
std::vector<SpeciesMap> species_maps;
Regridding regridding;
std::vector<SourceDescriptor> sources;
};

} // namespace mechanism_configuration::types
32 changes: 32 additions & 0 deletions include/mechanism_configuration/validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,43 @@ namespace mechanism_configuration
std::optional<ErrorLocation> location;
};

struct SpeciesMappingRef
{
std::string inventory_species;
std::string mechanism_species;
double scaling_factor{ 1.0 };
};

struct SpeciesMapRef
{
std::string name;
std::vector<SpeciesMappingRef> mappings;
std::optional<ErrorLocation> location;
};

struct SourceRef
{
std::string name;
NamedRef inventory; // .name = referenced inventory name, .location = reference site
NamedRef species_map; // .name = referenced species-map name, .location = reference site
int category{ 0 };
int hierarchy{ 1 };
std::optional<ErrorLocation> location; // location of the source entry itself
};

struct EmissionsRef
{
std::vector<NamedRef> inventories;
std::vector<SpeciesMapRef> species_maps;
std::vector<SourceRef> sources;
};

struct Input
{
std::vector<NamedRef> species;
std::vector<PhaseRef> phases;
std::vector<ReactionRef> reactions;
std::optional<EmissionsRef> emissions; // nullopt only when there's no emissions at all
};
} // namespace semantics

Expand Down
32 changes: 32 additions & 0 deletions src/detail/v1/emissions_parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2023–2026 University Corporation for Atmospheric Research
// University of Illinois at Urbana-Champaign
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <mechanism_configuration/errors.hpp>
#include <mechanism_configuration/types.hpp>

#include <yaml-cpp/yaml.h>

namespace mechanism_configuration::v1
{
// Structural (schema) validation of the emissions section. Checks required/optional keys,
// value shape, and fixed-enum-membership only; semantic invariants (duplicate names, unknown
// inventory/species-map references, scaling-factor sums) are checked separately by the
// version-neutral ValidateSemantics on the built Mechanism.

/// @brief Schema-validates the emissions section: inventories, species maps (and their
/// mappings), regridding, and sources.
/// @param emissions_node YAML node for the `emissions` key
/// @return List of structural errors, or empty if the section conforms
Errors CheckEmissionsSchema(const YAML::Node& emissions_node);

/// @brief Parses a YAML node into an EmissionsConfig.
/// The input must be validated using CheckEmissionsSchema().
/// This function assumes the structure and types are correct.
/// @param emissions_node YAML node for the `emissions` key
/// @return The parsed EmissionsConfig
types::EmissionsConfig ParseEmissionsSection(const YAML::Node& emissions_node);

} // namespace mechanism_configuration::v1
55 changes: 55 additions & 0 deletions src/detail/v1/keys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,59 @@ namespace mechanism_configuration::v1::keys
// products
// name

// ── Emissions section ──────────────────────────────────────────────────────
inline constexpr std::string_view emissions = "emissions";

// Emissions top-level sections
inline constexpr std::string_view inventories = "inventories";
inline constexpr std::string_view species_maps = "species maps";
inline constexpr std::string_view regridding = "regridding";
inline constexpr std::string_view sources = "sources";

// Inventory entry
inline constexpr std::string_view directory = "directory";
inline constexpr std::string_view file_pattern = "file pattern";
inline constexpr std::string_view convention = "convention";

// Species map entry
inline constexpr std::string_view mappings = "mappings";
inline constexpr std::string_view inventory_species = "inventory species";
inline constexpr std::string_view mechanism_species = "mechanism species";
// scaling_factor already defined above

// Regridding values
inline constexpr std::string_view regridding_none = "none";
inline constexpr std::string_view regridding_scrip = "scrip";

// Source descriptor entry
inline constexpr std::string_view mode = "mode";
inline constexpr std::string_view inventory = "inventory";
inline constexpr std::string_view species_map = "species map";
inline constexpr std::string_view temporal_interpolation = "temporal interpolation";
inline constexpr std::string_view vertical_injection = "vertical injection";
inline constexpr std::string_view category = "category";
inline constexpr std::string_view hierarchy = "hierarchy";
inline constexpr std::string_view sector = "sector";

// Mode values
inline constexpr std::string_view mode_offline = "offline";
inline constexpr std::string_view mode_online = "online";

// Source type values
inline constexpr std::string_view type_anthropogenic = "anthropogenic";
inline constexpr std::string_view type_fire = "fire";
inline constexpr std::string_view type_biogenic = "biogenic";
inline constexpr std::string_view type_dust = "dust";
inline constexpr std::string_view type_sea_salt = "sea salt";
inline constexpr std::string_view type_lightning = "lightning";

// Temporal interpolation values
inline constexpr std::string_view interp_linear = "linear";
inline constexpr std::string_view interp_nearest = "nearest";
inline constexpr std::string_view interp_none = "none";

// Vertical injection values
inline constexpr std::string_view inject_surface = "surface";
inline constexpr std::string_view inject_plume = "plume";

} // namespace mechanism_configuration::v1::keys
3 changes: 2 additions & 1 deletion src/detail/v1/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ namespace mechanism_configuration::v1
/// invariants are checked separately by ValidateSemantics.
Errors CheckSchema(const YAML::Node& object);

/// @brief Constructs a Mechanism from an already-validated node.
/// @brief Constructs a Mechanism from an already-validated node. The emissions section, if
/// present, is parsed separately and assigned by the caller (ValidateAndBuild).
Mechanism Build(const YAML::Node& object);

inline void SetConfigPath(const std::string& config_path)
Expand Down
3 changes: 3 additions & 0 deletions src/detail/v1/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ namespace mechanism_configuration::v1
/// @return A YAML sequence node containing the original node(s)
YAML::Node AsSequence(const YAML::Node& node);

/// @brief Extracts a YAML node's source location, for error messages that carry line:col.
ErrorLocation LocationOf(const YAML::Node& node);

void AppendFilePath(const std::string& config_path, Errors& errors);

std::unordered_map<std::string, std::string> GetComments(const YAML::Node& object);
Expand Down
10 changes: 10 additions & 0 deletions src/errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ namespace mechanism_configuration
case ErrorCode::FileNotFound: return "FileNotFound";
case ErrorCode::UnexpectedError: return "UnexpectedError";
case ErrorCode::EmptyObject: return "EmptyObject";
case ErrorCode::DuplicateInventoryDetected: return "DuplicateInventoryDetected";
case ErrorCode::DuplicateSpeciesMapDetected: return "DuplicateSpeciesMapDetected";
case ErrorCode::DuplicateSourceDetected: return "DuplicateSourceDetected";
case ErrorCode::DuplicateCategoryHierarchy: return "DuplicateCategoryHierarchy";
case ErrorCode::SourceRequiresUnknownInventory: return "SourceRequiresUnknownInventory";
case ErrorCode::SourceRequiresUnknownSpeciesMap: return "SourceRequiresUnknownSpeciesMap";
case ErrorCode::SpeciesMapScalingExceedsOne: return "SpeciesMapScalingExceedsOne";
case ErrorCode::OnlineSourcesNotSupported: return "OnlineSourcesNotSupported";
case ErrorCode::UnsupportedRegriddingType: return "UnsupportedRegriddingType";
case ErrorCode::UnsupportedVerticalInjection: return "UnsupportedVerticalInjection";
default: return "Unknown";
}
}
Expand Down
Loading
Loading