diff --git a/src/ispypsa/validation/schemas/custom_constraints.yaml b/src/ispypsa/validation/schemas/custom_constraints.yaml new file mode 100644 index 00000000..a06fd4ae --- /dev/null +++ b/src/ispypsa/validation/schemas/custom_constraints.yaml @@ -0,0 +1,28 @@ +table: custom_constraints +required: false +unique: + - [constraint_id] +description: > + Catalogue of custom (group) constraints and the sense of each constraint's + inequality. + + Each constraint's terms live in `custom_constraints_lhs` and its limit + values in `custom_constraints_rhs`; this table defines the constraint + itself. + + Source tables: + - PLEXOS model extract (`constraints.csv`), via the custom-constraints + templater. + + If absent: + No custom constraints are applied to the model. +columns: + constraint_id: + type: string + required: true + description: Unique identifier for the constraint (e.g. SWQLD1). + direction: + type: string + required: true + allowed_values: ["<=", ">=", "="] + description: Sense of the constraint inequality, applied as lhs rhs. diff --git a/src/ispypsa/validation/schemas/custom_constraints_lhs.yaml b/src/ispypsa/validation/schemas/custom_constraints_lhs.yaml new file mode 100644 index 00000000..29a1f15e --- /dev/null +++ b/src/ispypsa/validation/schemas/custom_constraints_lhs.yaml @@ -0,0 +1,60 @@ +table: custom_constraints_lhs +required: false +unique: + - [constraint_id, term_type, variable_name, date_from] +description: > + Left-hand-side terms of the custom constraints: one row per (constraint, + model variable) coefficient. + + Source tables: + - PLEXOS model extract (`lhs_terms.csv`), via the custom-constraints + templater. + + Source notes: + variable_name uses IASR IDs for generators and batteries and path_ids for + links. Generator and battery terms may reference units that are not in the + model (e.g. before generator templating lands, or units outside a filtered + region); such terms are skipped with a log line when constraints are + applied. + + If absent: + Constraints have no terms, so no custom constraints bind. +columns: + constraint_id: + type: string + required: true + allowed_values_from: + - custom_constraints: constraint_id + description: Constraint the term belongs to. + term_type: + type: string + required: true + allowed_values: [generator_output, generator_capacity, storage_output, link_flow, load] + description: > + Model variable type the term applies to: a generator's dispatch, a + generator's installed capacity, a battery's discharge, a transmission + path's flow, or a node's load consumption (load terms are not yet + modelled and are skipped, with a log line, when constraints are applied). + variable_name: + type: string + required: true + description: > + Name of the component the term's variable belongs to: an IASR ID for + generator_output and storage_output terms, a path_id for link_flow + terms. + coefficient: + type: float + required: true + description: Coefficient the variable is multiplied by in the constraint. + date_from: + type: date + required: false + format: "%Y-%m-%dT%H:%M:%S" + description: > + Date this row's coefficient takes effect. For each investment period, + the coefficient active at the period's start applies for the whole + period. + + If absent (or empty): + The coefficient applies from the start of the model horizon (until + another row's date_from supersedes it). diff --git a/src/ispypsa/validation/schemas/custom_constraints_rhs.yaml b/src/ispypsa/validation/schemas/custom_constraints_rhs.yaml new file mode 100644 index 00000000..d08aa20d --- /dev/null +++ b/src/ispypsa/validation/schemas/custom_constraints_rhs.yaml @@ -0,0 +1,51 @@ +table: custom_constraints_rhs +required: false +unique: + - [constraint_id, timeslice, date_from] +description: > + Right-hand-side limit values of the custom constraints, by timeslice. + + Source tables: + - PLEXOS model extract (`rhs_values.csv`), via the custom-constraints + templater. + + If absent: + Constraints have no limit values, so no custom constraints bind. +columns: + constraint_id: + type: string + required: true + allowed_values_from: + - custom_constraints: constraint_id + description: Constraint the limit value belongs to. + timeslice: + type: string + required: false + allowed_values_from: + - timeslices: timeslice_id + description: > + Demand condition the limit applies to: the constraint binds only at + snapshots inside the timeslice's active windows. + + If absent (or empty): + The limit is a fallback for this constraint_id, applying at snapshots not + covered by any non-NaN timeslice row for the same constraint_id. A + constraint may carry both a no-timeslice row and per-timeslice rows; where + a per-timeslice row covers a snapshot its limit takes precedence, and the + no-timeslice limit fills the remainder. A constraint with per-timeslice + rows but no no-timeslice row does not bind outside those timeslices. + rhs: + type: float + required: true + description: Limit value the constraint's LHS is compared against. + date_from: + type: date + required: false + format: "%Y-%m-%dT%H:%M:%S" + description: > + Date this row's limit takes effect. For each investment period, the + limit active at the period's start applies for the whole period. + + If absent (or empty): + The limit applies from the start of the model horizon (until another + row's date_from supersedes it). diff --git a/src/ispypsa/validation/schemas/network_expansion_options.yaml b/src/ispypsa/validation/schemas/network_expansion_options.yaml index 6e434267..02108c82 100644 --- a/src/ispypsa/validation/schemas/network_expansion_options.yaml +++ b/src/ispypsa/validation/schemas/network_expansion_options.yaml @@ -29,11 +29,11 @@ columns: required: true allowed_values_from: - network_transmission_paths: path_id - - constraints_rhs: constraint_id + - custom_constraints_rhs: 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. + in custom_constraints_rhs for group constraints. expansion_type: type: string required: true diff --git a/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml b/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml index bdeb2d5e..977a8bbf 100644 --- a/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml +++ b/src/ispypsa/validation/schemas/network_transmission_path_limits.yaml @@ -1,20 +1,17 @@ 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. +unique: + - [path_id, direction, timeslice] description: > Transmission capacity limits for each path, by direction and optionally by demand condition (timeslice). - A limit with no timeslice applies to all demand conditions; a limit with a - timeslice applies to that condition only. The schema permits either form for - any path. In the default IASR data, flow-path limits vary by demand condition - while REZ-to-subregion connection limits are static, but that reflects the - source tables rather than a schema rule. + A limit with a timeslice applies to that demand condition only; a limit with + no timeslice is a fallback for the conditions no per-timeslice limit covers + (see the timeslice column). A path may carry either or both. In the default + IASR data, flow-path limits vary by demand condition while REZ-to-subregion + connection limits are static, but that reflects the source tables rather than + a schema rule. Source tables: - `flow_path_transfer_capability` @@ -40,10 +37,15 @@ columns: allowed_values_from: - timeslices: timeslice_id description: > - Demand condition the limit applies to. + Demand condition the limit applies to: the limit binds only at snapshots + inside the timeslice's active windows. If absent (or empty): - Capacity is treated as a static limit applying to all conditions. + The limit is a fallback for this path_id and direction, applying at + snapshots not covered by any non-NaN timeslice row for the same path_id + and direction. A path_id and direction may carry both a no-timeslice row + and per-timeslice rows; where a per-timeslice row covers a snapshot its + limit takes precedence, and the no-timeslice limit fills the remainder. capacity: type: float required: false