Skip to content

Constraint Files

This page documents the constraints/ files that override entity bounds per stage and block (thermal, hydro, hydro unit group, line, pumping, contract and NCS bounds) and the files that define generic constraints: generic_constraints.json, generic_constraint_bounds.parquet and generic_parameters.json. The other case files, including the penalty overrides that share the constraints/ directory, are listed in the Case Format overview.

All bounds Parquet files use sparse storage: only (entity_id, stage_id) pairs that differ from the base entity-level value need rows. Absent rows use the entity-level value unchanged.


Methodology: Equipment-Specific Formulations

Stage-varying generation and cost overrides for thermal plants.

NameTypeRequiredDefaultUnitsDescription
thermal_idInt32Yes——Thermal plant ID
stage_idInt32Yes——Stage ID
min_generation_mwFloat64No—MWMinimum generation override (MW)
max_generation_mwFloat64No—MWMaximum generation override (MW)
cost_per_mwhFloat64No—USD/MWhDispatch cost override (USD/MWh)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s min_generation_mw/max_generation_mw override. null applies at the stage level. A non-null cost_per_mwh on the same row, or any block_id on a thermal declaring anticipated_config, is rejected at validation.

cost_per_mwh is deliberately not block-eligible, unlike contract_bounds.price_per_mwh — commitment is a stage-level decision, so a per-block dispatch cost has nothing to attach to.

Validation:

  • Every override value must be finite; cost_per_mwh must be >= 0.

Methodology: System Element Modeling Overview

Stage-varying operational bound overrides for hydro plants.

NameTypeRequiredDefaultUnitsDescription
hydro_idInt32Yes——Hydro plant ID
stage_idInt32Yes——Stage ID
min_turbined_m3sFloat64No—m³/sPlant-level minimum turbined flow (m³/s); written to training/dictionaries/bounds.parquet, but no LP row reads it: the minimum turbined-flow rows read the unit groups’ resolved minima (constraints/hydro_unit_group_bounds.parquet)
max_turbined_m3sFloat64No—m³/sMaximum turbined flow (m³/s)
min_storage_hm3Float64No—hm³Minimum reservoir storage (hm³)
max_storage_hm3Float64No—hm³Maximum reservoir storage (hm³)
min_outflow_m3sFloat64No—m³/sMinimum total outflow (m³/s)
max_outflow_m3sFloat64No—m³/sMaximum total outflow (m³/s)
min_generation_mwFloat64No—MWPlant-level minimum generation (MW); written to training/dictionaries/bounds.parquet, but no LP row reads it: the minimum-generation rows read the unit groups’ resolved minima (constraints/hydro_unit_group_bounds.parquet)
max_generation_mwFloat64No—MWMaximum generation (MW)
max_diversion_m3sFloat64No—m³/sMaximum diversion flow (m³/s)
min_diversion_m3sFloat64No—m³/sMinimum diversion flow (m³/s); requires a declared diversion channel
min_spillage_m3sFloat64No—m³/sMinimum spillage flow (m³/s)
max_spillage_m3sFloat64No—m³/sMaximum spillage flow (m³/s); >= min_spillage_m3s
filling_min_rate_m3sFloat64No—m³/sFilling minimum-rate override (m³/s)
water_withdrawal_m3sFloat64No—m³/sWater withdrawal (m³/s)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s turbined/outflow/generation/diversion/spillage override. null applies at the stage level. A non-null min_storage_hm3/max_storage_hm3/filling_min_rate_m3s/water_withdrawal_m3s value on the same row is rejected at validation — those four stay stage-level only, with no per-block variant.

A min_diversion_m3s override on a hydro that declares no diversion channel is rejected at validation — with no channel, the diversion column is pinned [0, 0], making a positive floor infeasible. min_diversion_m3s, min_spillage_m3s, and max_spillage_m3s must each be non-negative, and a row combining min_spillage_m3s and max_spillage_m3s with min_spillage_m3s > max_spillage_m3s is rejected. See Error Codes for the full failure-mode catalog.

Validation:

  • A row’s max_turbined_m3s or max_generation_mw must not exceed the plant’s declared value.
  • Every override value must be finite.
  • filling_min_rate_m3s must be >= 0.

constraints/hydro_unit_group_bounds.parquet

Section titled “constraints/hydro_unit_group_bounds.parquet”

Methodology: System Element Modeling Overview

Stage-varying, optionally per-block bound overrides for a hydro plant’s declared unit groups (hydros[].unit_groups[]; see system/hydros.json). A row overrides one of a group’s four declared bounds for one (hydro_id, hydro_unit_group_id, stage_id), optionally narrowed to a single block; a group with no override row reads its declared value. Group id is unique within its plant, not necessarily dense or 0-based, and hydro_unit_group_id addresses the group by that declared id.

NameTypeRequiredDefaultUnitsDescription
hydro_idInt32Yes——Hydro plant ID
hydro_unit_group_idInt32Yes——Unit group ID (unit_groups[].id), unique within the plant
stage_idInt32Yes——Stage ID
min_turbined_m3sFloat64No—m³/sMinimum turbined flow override for this group (m³/s)
max_turbined_m3sFloat64No—m³/sMaximum turbined flow override for this group (m³/s)
min_generation_mwFloat64No—MWMinimum generation override for this group (MW)
max_generation_mwFloat64No—MWMaximum generation override for this group (MW)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s override. null applies at the stage level; all four bound columns are block-eligible.

Validation:

  • A row’s max_turbined_m3s or max_generation_mw must not exceed that group’s declared value.
  • Every override value must be finite.

Methodology: Equipment-Specific Formulations

Stage-varying, absolute-MW flow capacity overrides for transmission lines.

NameTypeRequiredDefaultUnitsDescription
line_idInt32Yes——Transmission line ID
stage_idInt32Yes——Stage ID
direct_mwFloat64No—MWDirect-flow capacity override (MW)
reverse_mwFloat64No—MWReverse-flow capacity override (MW)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s direct_mw/reverse_mw override. null applies at the stage level.

Per-block line capacity is declared here as absolute MW; direct_mw = 0.0 closes the line in the direct direction for that block, or for the stage when block_id is null (and reverse_mw = 0.0 in the reverse one).


Methodology: Equipment-Specific Formulations

Stage-varying flow bounds for pumping stations.

NameTypeRequiredDefaultUnitsDescription
pumping_station_idInt32Yes——Pumping station ID
stage_idInt32Yes——Stage ID
min_m3sFloat64No—m³/sMinimum pumping flow (m³/s)
max_m3sFloat64No—m³/sMaximum pumping flow (m³/s)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s min_m3s/max_m3s override. null applies at the stage level.

Validation:

  • Every override value must be finite and >= 0.
  • A row’s min_m3s must not exceed its max_m3s.

Methodology: Equipment-Specific Formulations

Stage-varying power and price overrides for energy contracts.

NameTypeRequiredDefaultUnitsDescription
contract_idInt32Yes——Energy contract ID
stage_idInt32Yes——Stage ID
min_mwFloat64No—MWMinimum power (MW)
max_mwFloat64No—MWMaximum power (MW)
price_per_mwhFloat64No—USD/MWhPrice override (USD/MWh)
block_idInt32 (nullable)No——Zero-based block index within the stage, selecting one block’s min_mw/max_mw/price_per_mwh override. null applies at the stage level.

price_per_mwh is block-eligible — a study’s simulation cost path honors a per-block contract price — deliberately asymmetric with thermal_bounds.cost_per_mwh, which is not.


Methodology: Equipment-Specific Formulations

Stage-varying available generation bounds for non-controllable sources. Absent rows keep the entity’s declared max_generation_mw unchanged; a present row overrides that entity capacity with its per-stage available_generation_mw for the (ncs_id, stage_id) cell. The rows apply to a source with no stochastic availability model. A source with rows in scenarios/non_controllable_stats.parquet, or one that draws its availability from scenarios/external_ncs_scenarios.parquet under the external scheme, ignores its rows here: its available generation follows the model or the realizations (see Equipment-Specific Formulations §6).

NameTypeRequiredDefaultUnitsDescription
ncs_idInt32Yes——Non-controllable source ID
stage_idInt32Yes——Stage ID
available_generation_mwFloat64Yes—MWMaximum available generation for this stage (MW). Must be >= 0.

For a source these rows apply to, the per-block available generation bound in the LP is: available_mw_block = available_generation_mw * block_factor (max_generation_mw in place of available_generation_mw at a stage with no row), where block_factor comes from scenarios/non_controllable_factors.json (default 1.0 when absent).


Methodology: Generic Constraints · LP Formulation

User-defined linear constraints, added to every stage’s LP alongside the built-in constraint set. The file is optional; when absent, no generic constraints are added.

Top-level structure:

{
"constraints": [
{
"id": 1,
"name": "cap_ant_t1",
"expression": "anticipated_decision(2)",
"slack": { "enabled": false }
}
],
"expressions": [
{
"name": "total_hydro",
"expression": "hydro_generation(1) + hydro_generation(2)"
}
]
}

Per-entry fields (constraints[]):

NameTypeRequiredDefaultUnitsDescription
constraints[].idintegerYes——Constraint identifier. Must be unique within the file.
constraints[].namestringYes——Short name used in reports and log output.
constraints[].expressionstringYes——Expression string over variable references and constants (see below).
constraints[].descriptionstring | nullNo——Optional human-readable description.
constraints[].slackobjectYes——Slack variable configuration: enabled (boolean) and penalty (number; required and > 0 when enabled is true).
constraints[].slack.enabledbooleanYes——Whether a slack variable is allowed.
constraints[].slack.penaltynumber | nullConditional——Penalty per unit of violation. Required and > 0 when enabled is true.

Named expressions (expressions[]):

NameTypeRequiredDefaultUnitsDescription
expressionsarrayNo——Named linear expressions shared by every constraint and referenced by @name. Absent means none.
expressions[].namestringYes——Name bound to the expression. Must be unique in the file and distinct from every scalar-parameter name.
expressions[].expressionstringYes——Linear expression that name stands for, written in the same grammar as constraints[].expression.
expressions[].descriptionstring | nullNo——Optional human-readable description.

The expression grammar, the variables it can name, named expressions (@name) and how a constraint’s shape follows from its bounds are specified in Generic Constraints: Expression grammar, Variable catalog, The @name grammar, Interval and shape derivation.


constraints/generic_constraint_bounds.parquet

Section titled “constraints/generic_constraint_bounds.parquet”

Methodology: Generic Constraints · LP Formulation

Stage-varying, optionally per-block RHS bound overrides for generic constraints declared in constraints/generic_constraints.json. This table is the activation grid: a constraint is active at a given (stage[, block]) if and only if a row exists for it here, regardless of whether that row supplies any bound value itself (an inline affine remainder can supply the value instead — see below).

NameTypeRequiredDefaultUnitsDescription
constraint_idInt32Yes——Generic constraint ID
stage_idInt32Yes——Stage ID
block_idInt32 (nullable)No——Zero-based block index within the stage. null applies to all blocks of the given stage.
bound_lowerFloat64 (nullable)No——Lower interval endpoint. null when the constraint is unbounded below at this cell.
bound_upperFloat64 (nullable)No——Upper interval endpoint. null when the constraint is unbounded above at this cell.

How the two endpoints set the shape: Interval and shape derivation. Which rows are rejected: The activation grid.


Methodology: Generic Constraints · LP Formulation

Named scalar parameters that can be referenced from generic-constraint coefficient expressions using the @name sigil. The file is optional; when absent, no parameters are loaded and any @name token in a constraint expression causes a load error.

Top-level structure:

{
"$schema": "https://docs.novomodelo.invalid/schemas/generic_parameters.schema.json",
"scalar_parameters": [
{
"id": 1,
"name": "rho_eq_h1",
"kind": "computed",
"computed_spec": { "tag": "equivalent_productivity", "hydro_id": 1 }
}
]
}

Per-entry fields:

NameTypeRequiredDefaultUnitsDescription
scalar_parameters[].idintegerYes——Unique parameter identifier (int32)
scalar_parameters[].namestringYes——Unique parameter name (non-empty, no leading/trailing whitespace)
scalar_parameters[].kindstringYes——One of "constant", "per_stage", "seasonal", "computed", "per_stage_block".
scalar_parameters[].valuenumber | nullConditional——Finite f64 value. Required for constant. Absent otherwise.
scalar_parameters[].valuesarray | nullConditional——Array of [index, value] pairs. Required for per_stage and seasonal.
scalar_parameters[].computed_specobject | nullConditional——{"tag": "<variant>", "hydro_id": <int>}. Required for computed.
scalar_parameters[].computed_spec.tagstringYes——One of "equivalent_productivity", "accumulated_productivity", "reference_volume", "reference_turbine", "min_storage", "max_storage", "specific_productivity", "integrated_equivalent_productivity", "integrated_accumulated_productivity", "max_stored_energy". See the computed_spec tag values table below.
scalar_parameters[].computed_spec.hydro_idintegerYes——Hydro plant ID.
scalar_parameters[].block_valuesarray | nullConditional——Array of [stage_id, block_id, value] triples. Required for per_stage_block; each (stage_id, block_id) pair within an entry must be unique.

computed_spec tag values:

ValueDescription
equivalent_productivityEquivalent productivity ρ_eq
accumulated_productivityAccumulated cascade productivity ρ_acum
reference_volumeReference reservoir volume V_ref
reference_turbineReference turbined flow Q_ref
min_storagePhysical minimum storage reservoir.min_storage_hm3 (the plant’s stage-invariant range, not a hydro_bounds per-stage override)
max_storagePhysical maximum storage reservoir.max_storage_hm3 (the plant’s stage-invariant range, not a hydro_bounds per-stage override)
specific_productivitySpecific productivity ρ_esp
integrated_equivalent_productivityUseful-range mean equivalent productivity ρ̄_eq (forebay level averaged over the physical storage range)
integrated_accumulated_productivityρ̄_eq summed along the downstream cascade — the coefficient that pairs with max_stored_energy
max_stored_energyintegrated_accumulated_productivity × (max_storage_hm3 − min_storage_hm3) over the physical range, in MW/(m³/s)·hm³ — not MWh

The productivity and stored-energy quantities these tags resolve to are defined in Hydro Production Function Models §5.

Validation:

  • id values must be unique across all entries.
  • name values must be unique (case-sensitive), non-empty, and have no leading or trailing whitespace.
  • kind must be exactly one of the five legal values.
  • For per_stage: values pairs must have contiguous stage_id keys starting at 0; duplicates and gaps are rejected.
  • For seasonal: season_id keys within an entry must be unique; duplicates are rejected.
  • For computed: computed_spec must be present with a valid tag and integer hydro_id. The referenced hydro must exist in hydros.json.
  • For per_stage_block: block_values must be present, and each (stage_id, block_id) pair within an entry must be unique; duplicates are rejected.
  • Unknown JSON fields on any entry are rejected immediately.

For what each kind means, see The five parameter kinds.