From 955269f50b0aa0de35378df451aaee9435becab6 Mon Sep 17 00:00:00 2001 From: nick-gorman Date: Mon, 2 Mar 2026 17:48:12 +1100 Subject: [PATCH] Add initial ISPyPSA input table validation schemas Introduces a YAML schema format and initial schemas for the network topology tables as part of the broader templater refactor (v2.8.0 workbook-parser support and input table restructuring). Schemas defined: - network_nodes - network_transmission_paths - network_transmission_path_limits (new table) - network_expansion_options (new table) - network_transmission_path_expansion_costs - node_resource_limits (new table) Schema format supports: required/optional tables and columns, static allowed_values, cross-table allowed_values_from (single and multiple sources), unique row constraints, and custom_validation hooks for logic too complex for declarative syntax. Co-Authored-By: Claude Sonnet 4.6 --- .../schemas/network_expansion_options.yaml | 32 +++++++++++++ .../validation/schemas/network_nodes.yaml | 31 ++++++++++++ ...ork_transmission_path_expansion_costs.yaml | 26 ++++++++++ .../network_transmission_path_limits.yaml | 46 ++++++++++++++++++ .../schemas/network_transmission_paths.yaml | 33 +++++++++++++ .../schemas/node_resource_limits.yaml | 47 +++++++++++++++++++ 6 files changed, 215 insertions(+) create mode 100644 src/ispypsa/validation/schemas/network_expansion_options.yaml create mode 100644 src/ispypsa/validation/schemas/network_nodes.yaml create mode 100644 src/ispypsa/validation/schemas/network_transmission_path_expansion_costs.yaml create mode 100644 src/ispypsa/validation/schemas/network_transmission_path_limits.yaml create mode 100644 src/ispypsa/validation/schemas/network_transmission_paths.yaml create mode 100644 src/ispypsa/validation/schemas/node_resource_limits.yaml diff --git a/src/ispypsa/validation/schemas/network_expansion_options.yaml b/src/ispypsa/validation/schemas/network_expansion_options.yaml new file mode 100644 index 00000000..f2fa73e6 --- /dev/null +++ b/src/ispypsa/validation/schemas/network_expansion_options.yaml @@ -0,0 +1,32 @@ +table: network_expansion_options +required: false +unique: + - [expansion_id] +description: > + Defines the selected expansion option and allowed capacity increase for + expandable network elements. Covers both physical transmission paths and + group constraints that can be relaxed through expansion. + expansion_id maps to either a path_id in network_transmission_paths or a + constraint_id in constraints_rhs. + If this table is absent, no network expansion is modelled. +columns: + expansion_id: + type: string + required: true + allowed_values_from: + - table: network_transmission_paths + column: path_id + - table: constraints_rhs + column: constraint_id + description: > + Identifier for the expandable network element. Maps to path_id in + network_transmission_paths for physical paths, or to constraint_id + in constraints_rhs for group constraints. + allowed_expansion: + type: float + required: true + description: Capacity increase in MW provided by the selected expansion option. + expansion_option: + type: string + required: false + description: Name of the selected augmentation option, retained for traceability. diff --git a/src/ispypsa/validation/schemas/network_nodes.yaml b/src/ispypsa/validation/schemas/network_nodes.yaml new file mode 100644 index 00000000..51361b69 --- /dev/null +++ b/src/ispypsa/validation/schemas/network_nodes.yaml @@ -0,0 +1,31 @@ +table: network_nodes +required: true +unique: + - [node_id] +description: > + Unified node table representing all spatial entities in the network model: + NEM subregions, NEM regions, and renewable energy zones (REZs). + All table mappings use node_id as the primary key. + Subregion and region nodes are for spatial rollups and results formatting only. + Required — the model cannot run without nodes defined. +columns: + node_id: + type: string + required: true + description: Unique identifier for the node. + node_type: + type: string + required: true + allowed_values: [subregion, region, rez] + description: Type of spatial entity. + region_id: + type: string + required: true + allowed_values: [QLD, NSW, VIC, SA, TAS] + description: NEM region the node belongs to. + subregion_id: + type: string + required: true + description: > + ISP sub-region the node belongs to. + For subregion nodes, equals node_id. diff --git a/src/ispypsa/validation/schemas/network_transmission_path_expansion_costs.yaml b/src/ispypsa/validation/schemas/network_transmission_path_expansion_costs.yaml new file mode 100644 index 00000000..014f82e1 --- /dev/null +++ b/src/ispypsa/validation/schemas/network_transmission_path_expansion_costs.yaml @@ -0,0 +1,26 @@ +table: network_transmission_path_expansion_costs +required: false +unique: + - [expansion_id, year] +description: > + Time-varying annualised expansion costs for network elements, covering both + physical transmission paths and group constraints. + Merges flow path and REZ transmission expansion costs into a single long-format + table. + If this table is absent, network expansion is treated as free. +columns: + expansion_id: + type: string + required: true + allowed_values_from: + table: network_expansion_options + column: expansion_id + description: Identifier for the expandable network element. + year: + type: integer + required: true + description: Financial year the cost applies to. + cost: + type: float + required: true + description: Annualised expansion cost in $/MW. diff --git a/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml b/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml new file mode 100644 index 00000000..61d74cee --- /dev/null +++ b/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml @@ -0,0 +1,46 @@ +table: network_transmission_path_limits +required: false +custom_validation: + - name: no_duplicate_path_direction_timeslice + description: > + No two rows may have the same path_id, direction, and timeslice value. + For NaN timeslice rows, at most one row is permitted per path_id and + direction combination. +description: > + Static transmission capacity limits for each path by direction and timeslice. + Sourced from flow_path_transfer_capability and interconnector_transfer_capability + in the IASR workbook. + For REZ connections that are constraint-modelled rather than physically limited, + capacity is NaN — the translator assigns a sufficiently large default capacity + for these rows. + If timeslice is absent, capacity is treated as a static limit applying to all + conditions. + If this table is absent, no transmission capacity limits are enforced. +columns: + path_id: + type: string + required: true + allowed_values_from: + table: network_transmission_paths + column: path_id + description: Transmission path identifier. + direction: + type: string + required: true + allowed_values: [forward, reverse] + description: Power flow direction relative to node_from and node_to. + timeslice: + type: string + required: false + allowed_values_from: + table: timeslices + column: timeslice_id + description: > + Demand condition the limit applies to. + If absent, capacity is treated as a static limit applying to all conditions. + capacity: + type: float + required: false + description: > + Transfer capability approximation in MW. + NaN indicates a constraint-modelled path with no explicit physical limit. diff --git a/src/ispypsa/validation/schemas/network_transmission_paths.yaml b/src/ispypsa/validation/schemas/network_transmission_paths.yaml new file mode 100644 index 00000000..4d87961e --- /dev/null +++ b/src/ispypsa/validation/schemas/network_transmission_paths.yaml @@ -0,0 +1,33 @@ +table: network_transmission_paths +required: false +unique: + - [path_id] +description: > + Transmission paths connecting nodes in the network model, including + inter-subregional flow paths, regional interconnectors, and REZ-to-subregion + connections. If absent, the model is constructed with no transmission paths. + Nodes with no connecting paths are electrically isolated. +columns: + path_id: + type: string + required: true + description: Unique identifier for the path, formatted as node_from-node_to. + node_from: + type: string + required: true + allowed_values_from: + table: network_nodes + column: node_id + description: Origin node. Defines the forward flow direction. + node_to: + type: string + required: true + allowed_values_from: + table: network_nodes + column: node_id + description: Destination node. Defines the forward flow direction. + carrier: + type: string + required: true + allowed_values: [AC, DC] + description: Transmission technology. diff --git a/src/ispypsa/validation/schemas/node_resource_limits.yaml b/src/ispypsa/validation/schemas/node_resource_limits.yaml new file mode 100644 index 00000000..560164a5 --- /dev/null +++ b/src/ispypsa/validation/schemas/node_resource_limits.yaml @@ -0,0 +1,47 @@ +table: node_resource_limits +required: false +unique: + - [node_id, resource_type, limit_type] +description: > + Resource and land use limits for nodes in the network model. + Each row represents a limit on a specific resource type within a node. + Nodes with no rows in this table have no resource limits applied. + If resource_limit_penalty is NaN, no violation is allowed (hard cap). + If resource_limit_penalty is 0.0, there is effectively no limit — generation + can exceed the limit at zero cost. + If resource_limit_penalty is a positive value, the translator creates dummy + penalty generators to allow relaxation at that annualised cost in $/MW. + If this table is absent, the model is constructed without resource limits. +columns: + node_id: + type: string + required: true + allowed_values_from: + table: network_nodes + column: node_id + description: Node identifier. + resource_type: + type: string + required: true + allowed_values: [wind_high, wind_medium, wind_offshore_fixed, wind_offshore_floating, solar, wind] + description: Resource type the limit applies to. + limit_type: + type: string + required: true + allowed_values: [generation, land_use] + description: > + Necessary to disambiguate resource_type values that appear in both + generation and land_use contexts (e.g. solar). + limit: + type: float + required: true + description: Limit value in MW. + resource_limit_penalty: + type: float + required: false + description: > + Annualised penalty in $/MW applied if a limit is exceeded. + NaN means no violation is allowed (hard cap). + 0.0 means there is effectively no limit — generation can exceed the + limit at zero cost. + If this column is absent, all limits are treated as hard caps.