Skip to content
Closed
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
11 changes: 6 additions & 5 deletions src/metkit/mars2grib/backend/concepts/AllConcepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
#include "metkit/mars2grib/backend/concepts/destine/destineConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/ensemble/ensembleConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/generating-process/generatingProcessConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/iteration/iterationConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/level/levelConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/longrange/longrangeConceptDescriptor.h"
#include "metkit/mars2grib/backend/concepts/mars/marsConceptDescriptor.h"
Expand Down Expand Up @@ -168,10 +169,10 @@ using TypeList = metkit::mars2grib::backend::compile_time_registry_engine::TypeL
/// Higher-level code should interact with concepts exclusively through
/// registry APIs, not by iterating this list directly.
///
using AllConcepts =
TypeList<AnalysisConcept, CompositionConcept, DataTypeConcept, DerivedConcept, DestineConcept, EnsembleConcept,
GeneratingProcessConcept, LevelConcept, LongrangeConcept, MarsConcept, NilConcept, OriginConcept,
PackingConcept, ParamConcept, PointInTimeConcept, ReferenceTimeConcept, RepresentationConcept,
SatelliteConcept, ShapeOfTheEarthConcept, StatisticsConcept, TablesConcept, WaveConcept>;
using AllConcepts = TypeList<AnalysisConcept, CompositionConcept, DataTypeConcept, DerivedConcept, DestineConcept,
EnsembleConcept, GeneratingProcessConcept, LevelConcept, LongrangeConcept,
IterationConcept, MarsConcept, NilConcept, OriginConcept, PackingConcept, ParamConcept,
PointInTimeConcept, ReferenceTimeConcept, RepresentationConcept, SatelliteConcept,
ShapeOfTheEarthConcept, StatisticsConcept, TablesConcept, WaveConcept>;

} // namespace metkit::mars2grib::backend::concepts_::detail
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ void AnalysisOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& o
MARS2GRIB_LOG_CONCEPT(analysis);

// Structural validation
validation::match_LocalDefinitionNumber_or_throw(opt, out, {36L});
validation::match_LocalDefinitionNumber_or_throw(opt, out, {36L, 38L});

// Deductions
long offsetToEndOf4DvarWindowVal = deductions::resolve_offsetToEndOf4DvarWindow_or_throw(mars, par, opt);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* (C) Copyright 2025- ECMWF and individual contributors.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation nor
* does it submit to any jurisdiction.
*/

///
/// @file IterationConcept.h
/// @brief Compile-time registry entry for the GRIB `iteration` concept.
///
/// This header defines `IterationConcept`, the **compile-time descriptor**
/// that registers the GRIB `iteration` concept into the mars2grib
/// compile-time registry engine.
///
/// The descriptor provides:
/// - The concept name
/// - The mapping between variants and their symbolic names
/// - The set of callbacks associated with each encoding phase
/// - The entry-level matcher used to activate the concept
///
/// This file contains **no runtime logic**. All decisions are resolved
/// at compile time through template instantiation.
///
/// @ingroup mars2grib_backend_concepts
///
#pragma once

// System include
#include <cstddef>

// Registry engine
#include "metkit/mars2grib/backend/compile-time-registry-engine/RegisterEntryDescriptor.h"
#include "metkit/mars2grib/backend/compile-time-registry-engine/common.h"
#include "metkit/mars2grib/utils/generalUtils.h"

// Core concept includes
#include "metkit/mars2grib/backend/concepts/iteration/iterationEncoding.h"
#include "metkit/mars2grib/backend/concepts/iteration/iterationEnum.h"
#include "metkit/mars2grib/backend/concepts/iteration/iterationMatcher.h"

namespace metkit::mars2grib::backend::concepts_ {

// Importing the compile-time registry engine namespace locally to avoid
// excessive verbosity in template-heavy code. This is restricted to an
// internal scope and not exposed through public headers.
using namespace metkit::mars2grib::backend::compile_time_registry_engine;

///
/// @brief Compile-time descriptor for the `iteration` concept.
///
/// `IterationConcept` registers the GRIB `iteration` concept into the
/// compile-time registry engine.
///
/// The descriptor defines:
/// - The canonical concept name
/// - The mapping from variant enum values to symbolic names
/// - The callbacks associated with each encoding phase
/// - The entry-level matcher used to detect applicability
///
/// All functions in this descriptor are `constexpr` and are evaluated
/// entirely at compile time.
///
struct IterationConcept : RegisterEntryDescriptor<IterationType, IterationList> {

///
/// @brief Return the canonical name of the concept.
///
/// This name is used for:
/// - Registry identification
/// - Diagnostics and logging
/// - Debug and introspection facilities
///
static constexpr std::string_view entryName() { return iterationName; }

///
/// @brief Return the symbolic name of a concept variant.
///
/// @tparam T Variant enumeration value
///
/// @return String view representing the variant name
///
template <IterationType T>
static constexpr std::string_view variantName() {
return iterationTypeName<T>();
}

///
/// @brief Return the callback associated with a specific encoding phase.
///
/// This function is queried by the registry engine to obtain the
/// callback implementing the `iteration` concept for a given:
///
/// - Capability
/// - Encoding stage
/// - GRIB section
/// - Concept variant
///
/// The function returns:
/// - A valid function pointer if the concept is applicable
/// - `nullptr` otherwise
///
/// @tparam Capability Encoding capability index
/// @tparam Stage Encoding stage
/// @tparam Sec GRIB section
/// @tparam Variant Concept variant
/// @tparam MarsDict_t Type of MARS dictionary
/// @tparam ParDict_t Type of parameter dictionary
/// @tparam OptDict_t Type of options dictionary
/// @tparam OutDict_t Type of output GRIB dictionary
///
/// @return Function pointer implementing the phase, or `nullptr`
///
template <std::size_t Capability, std::size_t Stage, std::size_t Sec, IterationType Variant, class MarsDict_t,
class ParDict_t, class OptDict_t, class OutDict_t>
static constexpr Fn<MarsDict_t, ParDict_t, OptDict_t, OutDict_t> phaseCallbacks() {

if constexpr (Capability == 0) {

if constexpr (iterationApplicable<Stage, Sec, Variant>()) {
return &IterationOp<Stage, Sec, Variant, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>;
}
else {
return nullptr;
}
}
else {
return nullptr;
}

mars2gribUnreachable();
}

///
/// @brief Variant-specific callbacks (not used for this concept).
///
template <std::size_t Capability, IterationType Variant, class MarsDict_t, class ParDict_t, class OptDict_t,
class OutDict_t>
static constexpr Fn<MarsDict_t, ParDict_t, OptDict_t, OutDict_t> variantCallbacks() {
return nullptr;
}

///
/// @brief Entry-level matcher callback.
///
template <std::size_t Capability, class MarsDict_t, class OptDict_t>
static constexpr Fm<MarsDict_t, OptDict_t> entryCallbacks() {
if constexpr (Capability == 0) {
return &iterationMatcher<MarsDict_t, OptDict_t>;
}
else {
return nullptr;
}
}
};

} // namespace metkit::mars2grib::backend::concepts_
176 changes: 176 additions & 0 deletions src/metkit/mars2grib/backend/concepts/iteration/iterationEncoding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* (C) Copyright 2025- ECMWF and individual contributors.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation nor
* does it submit to any jurisdiction.
*/

///
/// @file iterationOp.h
/// @brief Implementation of the GRIB `iteration` concept operation.
///
/// This header defines the applicability rules and execution logic for the
/// **iteration concept** within the mars2grib backend.
///
/// The iteration concept is responsible for encoding GRIB keys associated with
/// *long-range forecast metadata* stored in the Local Use Section, specifically:
///
/// - `methodNumber`
/// - `systemNumber`
///
Comment on lines +18 to +23
/// These fields are used to identify the forecasting method and system
/// used for long-range or seasonal products.
///
/// The implementation follows the standard mars2grib concept model:
/// - Compile-time applicability via `iterationApplicable`
/// - Runtime validation of Local Definition Number
/// - Explicit deduction of required values
/// - Strict error handling with contextual concept exceptions
///
/// @note
/// The namespace name `concepts_` is intentionally used instead of `concepts`
/// to avoid ambiguity and potential conflicts with the C++20 `concept` language
/// feature and related standard headers.
///
/// This is a deliberate design choice and must not be changed.
///
/// @ingroup mars2grib_backend_concepts
///
#pragma once

// Core concept includes
#include "metkit/mars2grib/backend/compile-time-registry-engine/common.h"
#include "metkit/mars2grib/backend/concepts/iteration/iterationEnum.h"
#include "metkit/mars2grib/utils/generalUtils.h"

// Deductions
#include "metkit/mars2grib/backend/deductions/iterationNumber.h"
#include "metkit/mars2grib/backend/deductions/totalNumberOfIterations.h"

// checks
#include "metkit/mars2grib/backend/checks/matchLocalDefinitionNumber.h"

// Utils
#include "metkit/config/LibMetkit.h"
#include "metkit/mars2grib/utils/logUtils.h"
#include "metkit/mars2grib/utils/mars2gribExceptions.h"

namespace metkit::mars2grib::backend::concepts_ {

///
/// @brief Compile-time applicability predicate for the `iteration` concept.
///
/// This predicate determines whether the iteration concept is applicable
/// for a given combination of:
/// - encoding stage
/// - GRIB section
/// - concept variant
///
/// Applicability is evaluated entirely at compile time and is used by the
/// concept dispatcher to control instantiation and execution.
///
/// @tparam Stage Encoding stage (compile-time constant)
/// @tparam Section GRIB section index (compile-time constant)
/// @tparam Variant Iteration concept variant
///
/// @return `true` if the concept is applicable for the given parameters,
/// `false` otherwise.
///
/// @note
/// The default applicability rule enables the concept only when:
/// - `Variant == IterationType::Default`
/// - `Stage == StagePreset`
/// - `Section == SecLocalUseSection`
///
template <std::size_t Stage, std::size_t Section, IterationType Variant>
constexpr bool iterationApplicable() {
return ((Variant == IterationType::Default) && (Stage == StagePreset) && (Section == SecLocalUseSection));
}


///
/// @brief Execute the `iteration` concept operation.
///
/// This function implements the runtime logic of the GRIB `iteration` concept.
/// When applicable, it:
///
/// 1. Validates that the Local Use Section matches the expected definition.
/// 2. Deduces the long-range forecasting method and system identifiers.
/// 3. Encodes the corresponding GRIB keys in the output dictionary.
///
/// If the concept is invoked when not applicable, a
/// `Mars2GribConceptException` is thrown.
///
/// @tparam Stage Encoding stage (compile-time constant)
/// @tparam Section GRIB section index (compile-time constant)
/// @tparam Variant Iteration concept variant
/// @tparam MarsDict_t Type of the MARS input dictionary
/// @tparam ParDict_t Type of the parameter dictionary
/// @tparam OptDict_t Type of the options dictionary
/// @tparam OutDict_t Type of the GRIB output dictionary
///
/// @param[in] mars MARS input dictionary
/// @param[in] par Parameter dictionary
/// @param[in] opt Options dictionary
/// @param[out] out Output GRIB dictionary to be populated
///
/// @throws metkit::mars2grib::utils::exceptions::Mars2GribConceptException
/// If:
/// - the Local Definition Number does not match expectations,
/// - required deductions fail,
/// - any GRIB key cannot be set,
/// - the concept is invoked when not applicable.
///
/// @note
/// - All runtime errors are wrapped with full concept context
/// (concept name, variant, stage, section).
/// - This concept does not rely on pre-existing GRIB header state.
///
/// @see iterationApplicable
///
template <std::size_t Stage, std::size_t Section, IterationType Variant, class MarsDict_t, class ParDict_t,
class OptDict_t, class OutDict_t>
void IterationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& opt, OutDict_t& out) {

using metkit::mars2grib::utils::dict_traits::set_or_throw;
using metkit::mars2grib::utils::exceptions::Mars2GribConceptException;

if constexpr (iterationApplicable<Stage, Section, Variant>()) {


try {

MARS2GRIB_LOG_CONCEPT(iteration);

// Preconditions / contracts
validation::match_LocalDefinitionNumber_or_throw(opt, out, {20L, 38L});

// Deductions
auto iterationNumberVal = deductions::resolve_IterationNumber_or_throw(mars, par, opt);
auto totalNumberOfIterationsVal = deductions::resolve_TotalNumberOfIterations_opt(mars, par, opt);

// Encoding
set_or_throw<long>(out, "iterationNumber", iterationNumberVal);
if (totalNumberOfIterationsVal.has_value()) {
set_or_throw<long>(out, "totalNumberOfIterations", totalNumberOfIterationsVal.value());
}
}
catch (...) {
MARS2GRIB_CONCEPT_RETHROW(iteration, "Unable to set `iteration` concept...");
}

// Successful operation
return;
}

// Concept invoked outside its applicability domain
MARS2GRIB_CONCEPT_THROW(iteration, "Concept called when not applicable...");

// Remove compiler warning
mars2gribUnreachable();
}

} // namespace metkit::mars2grib::backend::concepts_
Loading
Loading