1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Core traits and abstractions for building reduced-complexity climate models.
//!
//! This crate provides the fundamental building blocks for constructing modular
//! climate models in Rust. It defines the core abstractions that allow components
//! to be composed into complete climate models with automatic dependency resolution.
//!
//! # Key Types
//!
//! - [`Component`](component::Component): The fundamental trait for model components.
//! Each component encapsulates some physics (e.g., carbon cycle, radiative forcing)
//! and declares its inputs and outputs.
//!
//! - [`Model`](model::Model): Orchestrates multiple components, managing state flow
//! between them and solving them in dependency order.
//!
//! - [`Timeseries`](timeseries::Timeseries): Time-indexed data with configurable
//! interpolation strategies. Supports both scalar and spatially-resolved data
//! via [`GridTimeseries`](timeseries::GridTimeseries).
//!
//! - [`TimeseriesCollection`](timeseries_collection::TimeseriesCollection): A named
//! collection of timeseries that holds all model state during a simulation.
//!
//! # Architecture Overview
//!
//! Models are built by composing components:
//!
//! ```text
//! ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
//! │ Emissions │────▶│ Carbon Cycle │────▶│ ERF Component │
//! │ (exogenous) │ │ (concentration) │ │ (forcing) │
//! └─────────────────┘ └──────────────────┘ └─────────────────┘
//! ```
//!
//! The [`ModelBuilder`](model::ModelBuilder) constructs a dependency graph and
//! validates that all inputs are satisfied (either by other components or
//! exogenous data).
//!
//! # Basic Usage
//!
//! ```ignore
//! use std::sync::Arc;
//! use rscm_core::model::ModelBuilder;
//! use rscm_core::timeseries::{TimeAxis, Timeseries};
//!
//! // Build a model with components
//! let mut model = ModelBuilder::new()
//! .with_time_axis(TimeAxis::from_values(array![2020.0, 2021.0, 2022.0]))
//! .with_component(Arc::new(my_carbon_cycle))
//! .with_component(Arc::new(my_erf_component))
//! .with_exogenous_variable("Emissions|CO2", emissions_timeseries)
//! .build()?;
//!
//! // Run the model
//! model.run();
//!
//! // Access results
//! let concentrations = model.timeseries().get_data("Atmospheric Concentration|CO2");
//! ```
//!
//! # Creating Components
//!
//! Components are best created using the [`ComponentIO`] derive macro from `rscm-macros`:
//!
//! ```ignore
//! use rscm_core::ComponentIO;
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, Serialize, Deserialize, ComponentIO)]
//! #[inputs(
//! concentration { name = "Atmospheric Concentration|CO2", unit = "ppm" },
//! )]
//! #[outputs(
//! erf { name = "Effective Radiative Forcing|CO2", unit = "W / m^2" },
//! )]
//! pub struct CO2ERF {
//! pub erf_2xco2: f64,
//! pub conc_pi: f64,
//! }
//!
//! #[typetag::serde]
//! impl Component for CO2ERF {
//! fn definitions(&self) -> Vec<RequirementDefinition> {
//! Self::generated_definitions()
//! }
//!
//! fn solve(&self, t_current: Time, t_next: Time, input_state: &InputState) -> RSCMResult<OutputState> {
//! let inputs = CO2ERFInputs::from_input_state(input_state);
//! let concentration = inputs.concentration.current();
//! let erf = self.erf_2xco2 / 2.0_f64.ln()
//! * (1.0 + (concentration - self.conc_pi) / self.conc_pi).ln();
//! Ok(CO2ERFOutputs { erf }.into())
//! }
//! }
//! ```
//!
//! # Spatial Grids
//!
//! The framework supports spatially-resolved variables through different grid types:
//!
//! - **Scalar**: Global mean values (default)
//! - **FourBox**: Four regions (Northern Ocean, Northern Land, Southern Ocean, Southern Land)
//! - **Hemispheric**: Two hemispheres (Northern, Southern)
//!
//! Grid transformations (e.g., FourBox to Scalar aggregation) are handled automatically
//! by the [`grid_transform`] module when components with different spatial resolutions
//! are connected.
// Allow macro-generated code to reference this crate by name
extern crate self as rscm_core;
// Re-export derive macro for convenience
pub use ComponentIO;