use thiserror::Error;
/// Error type for invalid operations.
#[derive(Error, Debug)]
pub enum RSCMError {
#[error("{0}")]
Error(String),
#[error("Extrapolation is not allowed. Target={0}, {1} interpolation range={2}")]
ExtrapolationNotAllowed(f32, String, f32),
#[error("Wrong input units. Expected {0}, got {1}")]
WrongUnits(String, String),
/// Grid transformation errors for unsupported conversions
#[error("Unsupported grid transformation from {from} to {to}. This transformation is not defined because it would require additional physical assumptions. Consider creating a custom component that explicitly handles this disaggregation, or use an intermediate transformation.")]
UnsupportedGridTransformation { from: String, to: String },
/// Grid type mismatch between connected components
#[error("Grid type mismatch for variable '{variable}': producer component '{producer_component}' outputs {producer_grid} but consumer component '{consumer_component}' expects {consumer_grid}. \n\nPossible resolutions:\n 1. Change {producer_component} to output {consumer_grid}\n 2. Change {consumer_component} to accept {producer_grid}\n 3. Insert a grid transformation component between them\n 4. If aggregation is acceptable, the model coupler can auto-transform from finer to coarser grids")]
GridTypeMismatch {
variable: String,
producer_component: String,
consumer_component: String,
producer_grid: String,
consumer_grid: String,
},
/// Missing initial value for a state variable
#[error("Missing initial value for state variable '{variable}' in component '{component}'. State variables require an initial value. Use ModelBuilder::with_initial_value(\"{variable}\", value) to provide one, or set a default in the component's parameter configuration.")]
MissingInitialValue { variable: String, component: String },
/// Variable not found in state
#[error("Variable '{name}' not found in state. Available variables: {available}. Ensure the variable is produced by a component or provided as exogenous input.")]
VariableNotFound { name: String, available: String },
/// Invalid region index for grid type
#[error(
"Invalid region index {index} for grid type {grid_type}. Valid indices are 0..{max_index}."
)]
InvalidRegionIndex {
index: usize,
grid_type: String,
max_index: usize,
},
/// Component cycle detected in dependency graph
#[error("Circular dependency detected in component graph: {cycle}. Components cannot form cycles. Consider splitting the cycle by introducing intermediate state variables or restructuring the component dependencies.")]
CircularDependency { cycle: String },
/// Grid output type mismatch between component output and variable definition
#[error("Grid output mismatch for variable '{variable}': component tried to output {component_grid} but variable expects {expected_grid}. Ensure the component's StateValue variant matches the RequirementDefinition's grid_type.")]
GridOutputMismatch {
variable: String,
expected_grid: String,
component_grid: String,
},
/// Grid transformation not supported (disaggregation/broadcast attempt)
///
/// This error occurs when a component requires a finer grid resolution than
/// the schema or producer provides. Disaggregation (broadcasting coarse data
/// to finer grids) is not supported because it would require inventing
/// spatial structure that doesn't exist in the source data.
#[error("Grid transformation not supported for variable '{variable}': cannot transform from {source_grid} to {target_grid}. Disaggregation (broadcasting from coarser to finer grids) is not supported because it would require inventing spatial structure. \n\nPossible resolutions:\n 1. Change the consumer component to accept {source_grid} resolution\n 2. Change the producer component or schema to provide {target_grid} resolution\n 3. Create an explicit disaggregation component with domain-specific assumptions")]
GridTransformationNotSupported {
variable: String,
source_grid: String,
target_grid: String,
},
/// Aggregate contributor not defined in schema
#[error("Undefined contributor '{contributor}' in aggregate '{aggregate}'. The contributor must be defined as a variable or aggregate in the schema before it can be used.")]
UndefinedContributor {
contributor: String,
aggregate: String,
},
/// Unit mismatch between schema variable/aggregate and its contributor
#[error("Unit mismatch in aggregate '{aggregate}': contributor '{contributor}' has unit '{contributor_unit}' but aggregate expects '{aggregate_unit}'.")]
SchemaUnitMismatch {
aggregate: String,
contributor: String,
contributor_unit: String,
aggregate_unit: String,
},
/// Grid type mismatch between schema aggregate and its contributor
#[error("Grid type mismatch in aggregate '{aggregate}': contributor '{contributor}' has grid type '{contributor_grid}' but aggregate expects '{aggregate_grid}'.")]
SchemaGridTypeMismatch {
aggregate: String,
contributor: String,
contributor_grid: String,
aggregate_grid: String,
},
/// Weight count mismatch for weighted aggregate
#[error("Weight count mismatch in weighted aggregate '{aggregate}': {weight_count} weights provided but {contributor_count} contributors defined.")]
WeightCountMismatch {
aggregate: String,
weight_count: usize,
contributor_count: usize,
},
/// Circular dependency detected in aggregate graph
#[error(
"Circular dependency detected in aggregate schema: {cycle}. Aggregates cannot form cycles."
)]
AggregateCircularDependency { cycle: String },
/// Component output not defined in schema
#[error("Component '{component}' outputs variable '{variable}' which is not defined in the schema. Add it with schema.variable(\"{variable}\", \"{unit}\") or remove the schema constraint.")]
SchemaUndefinedOutput {
component: String,
variable: String,
unit: String,
},
/// Component input not defined in schema or produced by any component
#[error("Component '{component}' requires variable '{variable}' which is not defined in the schema. Add it with schema.variable(\"{variable}\", \"{unit}\") or remove the schema constraint.")]
SchemaUndefinedInput {
component: String,
variable: String,
unit: String,
},
/// Component output unit mismatch with schema
#[error("Unit mismatch for variable '{variable}': component '{component}' uses '{component_unit}' but schema defines '{schema_unit}'.")]
ComponentSchemaUnitMismatch {
variable: String,
component: String,
component_unit: String,
schema_unit: String,
},
/// Component output grid type mismatch with schema
#[error("Grid type mismatch for variable '{variable}': component '{component}' uses '{component_grid}' but schema defines '{schema_grid}'.")]
ComponentSchemaGridMismatch {
variable: String,
component: String,
component_grid: String,
schema_grid: String,
},
}
/// Convenience type for `Result<T, RSCMError>`.
pub type RSCMResult<T> = Result<T, RSCMError>;