Skip to content

Commit 17e9c4e

Browse files
committed
Merge branch 'mahf708/emulators/inference' (PR #8048)
adding a mostly performative/stub inference backend (we will add libtorch, pytroch, lapis, onnxruntime, etc. in the future). [BFB]
2 parents 6c5460c + 47d1fc3 commit 17e9c4e

11 files changed

+316
-7
lines changed
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
# Common source library
1+
# Common emulator library
22

33
add_library(emulator_common
44
emulator.cpp
5+
inference/stub_inference_backend.cpp
6+
inference/create_inference_backend.cpp
57
)
68

79
target_compile_features(emulator_common PUBLIC cxx_std_17)
810

911
target_include_directories(emulator_common PUBLIC
1012
${CMAKE_CURRENT_SOURCE_DIR}
13+
${CMAKE_CURRENT_SOURCE_DIR}/inference
1114
)

components/emulators/common/src/emulator.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* @brief Abstract base class for all E3SM emulators.
44
*/
55

6-
#ifndef EMULATOR_HPP
7-
#define EMULATOR_HPP
6+
#ifndef E3SM_EMULATOR_HPP
7+
#define E3SM_EMULATOR_HPP
88

99
#include <string>
1010

@@ -67,4 +67,4 @@ class Emulator {
6767

6868
} // namespace emulator
6969

70-
#endif // EMULATOR_HPP
70+
#endif // E3SM_EMULATOR_HPP

components/emulators/common/src/emulator_registry.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* for creating and retrieving emulator instances by name.
77
*/
88

9-
#ifndef EMULATOR_REGISTRY_HPP
10-
#define EMULATOR_REGISTRY_HPP
9+
#ifndef E3SM_EMULATOR_REGISTRY_HPP
10+
#define E3SM_EMULATOR_REGISTRY_HPP
1111

1212
#include <any>
1313
#include <memory>
@@ -154,4 +154,4 @@ inline void cleanup_emulator_registry() {
154154

155155
} // namespace emulator
156156

157-
#endif // EMULATOR_REGISTRY_HPP
157+
#endif // E3SM_EMULATOR_REGISTRY_HPP
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @file create_backend.cpp
3+
* @brief Factory for creating inference backends.
4+
*/
5+
6+
#include "create_inference_backend.hpp"
7+
#include "stub_inference_backend.hpp"
8+
9+
namespace emulator {
10+
namespace inference {
11+
12+
std::shared_ptr<InferenceBackend>
13+
create_backend(BackendType type, const InferenceConfig &config) {
14+
switch (type) {
15+
case BackendType::STUB:
16+
return std::make_shared<StubBackend>(config);
17+
default:
18+
return std::make_shared<StubBackend>(config);
19+
}
20+
}
21+
22+
} // namespace inference
23+
} // namespace emulator
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @file create_backend.hpp
3+
* @brief Factory for creating inference backends.
4+
*/
5+
6+
#ifndef E3SM_EMULATOR_CREATE_INFERENCE_BACKEND_HPP
7+
#define E3SM_EMULATOR_CREATE_INFERENCE_BACKEND_HPP
8+
9+
#include <memory>
10+
11+
#include "inference_backend.hpp"
12+
13+
namespace emulator {
14+
namespace inference {
15+
16+
/**
17+
* @brief Create an inference backend by type.
18+
* @param type Backend type to create
19+
* @param config Configuration for the backend
20+
* @return Shared pointer to new backend instance
21+
*/
22+
std::shared_ptr<InferenceBackend>
23+
create_backend(BackendType type, const InferenceConfig &config);
24+
25+
} // namespace inference
26+
} // namespace emulator
27+
28+
#endif // E3SM_EMULATOR_CREATE_INFERENCE_BACKEND_HPP
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @file inference_backend.hpp
3+
* @brief Abstract interface for neural network inference backends.
4+
*/
5+
6+
#ifndef E3SM_EMULATOR_INFERENCE_BACKEND_HPP
7+
#define E3SM_EMULATOR_INFERENCE_BACKEND_HPP
8+
9+
#include <string>
10+
11+
namespace emulator {
12+
namespace inference {
13+
14+
/**
15+
* @brief Enumeration of available inference backend types.
16+
*/
17+
enum class BackendType {
18+
STUB, ///< No-op backend for testing (no ML dependencies)
19+
};
20+
21+
/**
22+
* @brief Minimal configuration for inference backends.
23+
*/
24+
struct InferenceConfig {
25+
int input_channels = 0; ///< Number of input features per grid point
26+
int output_channels = 0; ///< Number of output features per grid point
27+
bool verbose = false; ///< Enable verbose output (for debugging)
28+
};
29+
30+
/**
31+
* @brief Abstract interface for inference backends.
32+
*
33+
* Provides a unified API for running neural network inference.
34+
* All backends:
35+
* - Accept input as a flat array [batch_size * input_channels]
36+
* - Produce output as a flat array [batch_size * output_channels]
37+
*
38+
* Backends are fully configured on construction (config is passed
39+
* to the constructor). No separate initialization step is needed.
40+
*/
41+
class InferenceBackend {
42+
public:
43+
explicit InferenceBackend(const InferenceConfig &config) : m_config(config) {}
44+
virtual ~InferenceBackend() = default;
45+
46+
/**
47+
* @brief Run inference on input data.
48+
* @param inputs Input data array [batch_size * input_channels]
49+
* @param outputs Output data array [batch_size * output_channels]
50+
* @param batch_size Number of samples in the batch
51+
* @return true if inference succeeded
52+
*/
53+
virtual bool infer(const double *inputs, double *outputs,
54+
int batch_size = 1) = 0;
55+
56+
/**
57+
* @brief Release resources and finalize the backend.
58+
*/
59+
virtual void finalize() = 0;
60+
61+
/**
62+
* @brief Get the human-readable name of this backend.
63+
*/
64+
virtual std::string name() const = 0;
65+
66+
protected:
67+
InferenceConfig m_config; ///< Backend configuration
68+
};
69+
70+
} // namespace inference
71+
} // namespace emulator
72+
73+
#endif // E3SM_EMULATOR_INFERENCE_BACKEND_HPP
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @file stub_backend.cpp
3+
* @brief Stub inference backend implementation.
4+
*
5+
* Provides a no-op backend for testing the emulator framework without
6+
* requiring ML dependencies. Leaves outputs unchanged.
7+
*/
8+
9+
#include "stub_inference_backend.hpp"
10+
11+
namespace emulator {
12+
namespace inference {
13+
14+
/**
15+
* @brief Run stub inference (no-op).
16+
*
17+
* Leaves outputs unchanged. Useful for testing the data pipeline
18+
* without actual model inference.
19+
*
20+
* @param inputs Input data (unused)
21+
* @param outputs Output data (unchanged)
22+
* @param batch_size Number of samples in batch (unused)
23+
* @return Always returns true
24+
*/
25+
bool StubBackend::infer(const double *inputs, double *outputs, int batch_size) {
26+
(void)inputs; // Unused
27+
(void)outputs; // Unchanged
28+
(void)batch_size; // Unused
29+
30+
// No-op: leave outputs unchanged
31+
return true;
32+
}
33+
34+
/**
35+
* @brief Finalize the stub backend.
36+
*
37+
* No-op for stub backend; included for interface compliance.
38+
*/
39+
void StubBackend::finalize() {}
40+
41+
} // namespace inference
42+
} // namespace emulator
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @file stub_backend.hpp
3+
* @brief Stub inference backend for testing without ML dependencies.
4+
*/
5+
6+
#ifndef E3SM_EMULATOR_STUB_INFERENCE_BACKEND_HPP
7+
#define E3SM_EMULATOR_STUB_INFERENCE_BACKEND_HPP
8+
9+
#include "inference_backend.hpp"
10+
11+
namespace emulator {
12+
namespace inference {
13+
14+
/**
15+
* @brief Stub backend for testing without actual inference.
16+
*
17+
* Leaves outputs unchanged. Useful for testing the data pipeline
18+
* without actual model inference.
19+
*
20+
* @see InferenceBackend for the base interface
21+
*/
22+
class StubBackend : public InferenceBackend {
23+
public:
24+
explicit StubBackend(const InferenceConfig &config)
25+
: InferenceBackend(config) {}
26+
~StubBackend() override = default;
27+
28+
/// @copydoc InferenceBackend::infer
29+
bool infer(const double *inputs, double *outputs,
30+
int batch_size = 1) override;
31+
32+
/// @copydoc InferenceBackend::finalize
33+
void finalize() override;
34+
35+
/// @copydoc InferenceBackend::name
36+
std::string name() const override { return "Stub"; }
37+
};
38+
39+
} // namespace inference
40+
} // namespace emulator
41+
42+
#endif // E3SM_EMULATOR_STUB_INFERENCE_BACKEND_HPP

components/emulators/common/tests/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,17 @@ add_executable(test_emulator test_emulator.cpp)
1111
target_link_libraries(test_emulator PRIVATE emulator_common)
1212
target_include_directories(test_emulator PRIVATE ${CATCH2_INCLUDE_DIR})
1313
add_test(NAME emulator_tests COMMAND test_emulator)
14+
15+
# Test for InferenceConfig and utilities
16+
add_executable(test_inference_config test_inference_config.cpp)
17+
target_link_libraries(test_inference_config PRIVATE emulator_common)
18+
target_include_directories(test_inference_config PRIVATE ${CATCH2_INCLUDE_DIR})
19+
add_test(NAME inference_config_tests COMMAND test_inference_config)
20+
21+
# Test for StubBackend
22+
add_executable(test_inference_stub_backend test_inference_stub_backend.cpp)
23+
target_link_libraries(test_inference_stub_backend PRIVATE emulator_common)
24+
target_include_directories(test_inference_stub_backend PRIVATE ${CATCH2_INCLUDE_DIR})
25+
add_test(NAME inference_stub_backend_tests COMMAND test_inference_stub_backend)
26+
27+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Catch2 v2 single header
2+
#define CATCH_CONFIG_MAIN
3+
#include <catch2/catch.hpp>
4+
5+
#include "create_inference_backend.hpp"
6+
7+
namespace emulator {
8+
namespace inference {
9+
namespace test {
10+
11+
TEST_CASE("InferenceConfig defaults", "[inference_config]") {
12+
InferenceConfig config;
13+
14+
REQUIRE(config.input_channels == 0);
15+
REQUIRE(config.output_channels == 0);
16+
REQUIRE_FALSE(config.verbose);
17+
}
18+
19+
TEST_CASE("InferenceConfig can be set", "[inference_config]") {
20+
InferenceConfig config;
21+
config.input_channels = 10;
22+
config.output_channels = 5;
23+
config.verbose = true;
24+
25+
REQUIRE(config.input_channels == 10);
26+
REQUIRE(config.output_channels == 5);
27+
REQUIRE(config.verbose);
28+
}
29+
30+
} // namespace test
31+
} // namespace inference
32+
} // namespace emulator

0 commit comments

Comments
 (0)