{
  "$defs": {
    "RawDiversionChannel": {
      "additionalProperties": false,
      "description": "The `diversion` sub-object.",
      "properties": {
        "downstream_id": {
          "description": "Identifier of the downstream hydro plant receiving diverted water.",
          "format": "int32",
          "type": "integer"
        },
        "max_flow_m3s": {
          "description": "Maximum diversion flow capacity (m³/s).",
          "format": "double",
          "type": "number"
        }
      },
      "required": [
        "downstream_id",
        "max_flow_m3s"
      ],
      "type": "object"
    },
    "RawEfficiency": {
      "description": "The `efficiency` sub-object.",
      "oneOf": [
        {
          "description": "Constant efficiency across all operating points.",
          "properties": {
            "type": {
              "const": "constant",
              "type": "string"
            },
            "value": {
              "description": "Turbine efficiency as a fraction in (0, 1].",
              "format": "double",
              "type": "number"
            }
          },
          "required": [
            "type",
            "value"
          ],
          "type": "object"
        }
      ]
    },
    "RawEvaporation": {
      "additionalProperties": false,
      "description": "The `evaporation` sub-object.",
      "properties": {
        "coefficients_mm": {
          "description": "Monthly evaporation coefficients (mm/month), one per calendar month.\nIndex 0 = January, index 11 = December.",
          "items": {
            "format": "double",
            "type": "number"
          },
          "type": "array"
        },
        "reference_volumes_hm3": {
          "default": null,
          "description": "Monthly reservoir reference volumes (hm³) used as the linearization\nreference point for evaporation, one per calendar month.\nIndex 0 = January, index 11 = December.\nAbsent = no reference volume override; the calling algorithm uses its\nown default (e.g., mid-point of the storage range).",
          "items": {
            "format": "double",
            "type": "number"
          },
          "type": [
            "array",
            "null"
          ]
        }
      },
      "required": [
        "coefficients_mm"
      ],
      "type": "object"
    },
    "RawFillingConfig": {
      "additionalProperties": false,
      "description": "The `filling` sub-object.",
      "properties": {
        "filling_min_rate_m3s": {
          "default": 0.0,
          "description": "Minimum accumulation rate applied during filling (m³/s).\nAbsent = passive filling (no minimum rate, defaults to 0.0 per spec).",
          "format": "double",
          "type": "number"
        },
        "start_stage_id": {
          "description": "Stage index at which filling begins (inclusive).",
          "format": "int32",
          "type": "integer"
        }
      },
      "required": [
        "start_stage_id"
      ],
      "type": "object"
    },
    "RawGeneration": {
      "description": "The `generation` sub-object.\n\nThe `model` key selects the production model, and each model accepts only\nits own fields. The `productivity_mw_per_m3s` field is NOT accepted here —\nproductivity coefficients are read from `system/hydro_production_models.json`\nand are associated per `(hydro, stage)` outside this file.\nA `hydros.json` input that includes `productivity_mw_per_m3s` in its\n`generation` block will be rejected with a parse error.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "Constant productivity: `power = productivity * turbined_m3s`.\n\nThe productivity coefficient is read from\n`system/hydro_production_models.json` per `(hydro, stage)`. It is not\naccepted in `hydros.json`; supplying `productivity_mw_per_m3s` here\nproduces a hard parse error.",
          "properties": {
            "max_generation_mw": {
              "description": "Maximum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "max_turbined_m3s": {
              "description": "Maximum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "min_generation_mw": {
              "description": "Minimum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "min_turbined_m3s": {
              "description": "Minimum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "model": {
              "const": "constant_productivity",
              "type": "string"
            }
          },
          "required": [
            "model",
            "min_turbined_m3s",
            "max_turbined_m3s",
            "min_generation_mw",
            "max_generation_mw"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Head-dependent productivity linearized around an operating point.\n\nThe productivity coefficient is read from\n`system/hydro_production_models.json` per `(hydro, stage)`. It is not\naccepted in `hydros.json`; supplying `productivity_mw_per_m3s` here\nproduces a hard parse error.",
          "properties": {
            "max_generation_mw": {
              "description": "Maximum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "max_turbined_m3s": {
              "description": "Maximum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "min_generation_mw": {
              "description": "Minimum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "min_turbined_m3s": {
              "description": "Minimum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "model": {
              "const": "linearized_head",
              "type": "string"
            }
          },
          "required": [
            "model",
            "min_turbined_m3s",
            "max_turbined_m3s",
            "min_generation_mw",
            "max_generation_mw"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Full production function with head-area-productivity tables (FPHA model).\n\nProductivity is derived from the FPHA tables in\n`system/hydro_production_models.json`. The `productivity_mw_per_m3s`\nfield is not accepted here or in any other `generation` variant.",
          "properties": {
            "max_generation_mw": {
              "description": "Maximum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "max_turbined_m3s": {
              "description": "Maximum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "min_generation_mw": {
              "description": "Minimum electrical generation (MW).",
              "format": "double",
              "type": "number"
            },
            "min_turbined_m3s": {
              "description": "Minimum turbined flow (m³/s).",
              "format": "double",
              "type": "number"
            },
            "model": {
              "const": "fpha",
              "type": "string"
            }
          },
          "required": [
            "model",
            "min_turbined_m3s",
            "max_turbined_m3s",
            "min_generation_mw",
            "max_generation_mw"
          ],
          "type": "object"
        }
      ]
    },
    "RawHydraulicLosses": {
      "description": "The `hydraulic_losses` sub-object.",
      "oneOf": [
        {
          "description": "Losses as a fraction of net head.",
          "properties": {
            "type": {
              "const": "factor",
              "type": "string"
            },
            "value": {
              "description": "Dimensionless loss factor.",
              "format": "double",
              "type": "number"
            }
          },
          "required": [
            "type",
            "value"
          ],
          "type": "object"
        },
        {
          "description": "Constant head loss independent of flow or head.",
          "properties": {
            "type": {
              "const": "constant",
              "type": "string"
            },
            "value_m": {
              "description": "Fixed head loss (m).",
              "format": "double",
              "type": "number"
            }
          },
          "required": [
            "type",
            "value_m"
          ],
          "type": "object"
        }
      ]
    },
    "RawHydro": {
      "additionalProperties": false,
      "description": "A single hydro plant entry.",
      "properties": {
        "diversion": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawDiversionChannel"
            },
            {
              "type": "null"
            }
          ],
          "description": "Diversion channel configuration. Absent or null = no diversion channel."
        },
        "downstream_id": {
          "description": "Downstream hydro plant in the cascade. `null` = no downstream.",
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "efficiency": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawEfficiency"
            },
            {
              "type": "null"
            }
          ],
          "description": "Turbine efficiency model. Absent or null = 100% efficiency."
        },
        "entry_stage_id": {
          "default": null,
          "description": "Stage index when the plant enters service. Absent or null = always exists.",
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "evaporation": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawEvaporation"
            },
            {
              "type": "null"
            }
          ],
          "description": "Monthly evaporation coefficients. Absent or null = no evaporation."
        },
        "exit_stage_id": {
          "default": null,
          "description": "Stage index when the plant is decommissioned. Absent or null = never.",
          "format": "int32",
          "type": [
            "integer",
            "null"
          ]
        },
        "filling": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawFillingConfig"
            },
            {
              "type": "null"
            }
          ],
          "description": "Reservoir filling configuration. Absent or null = no filling operation."
        },
        "generation": {
          "$ref": "#/$defs/RawGeneration",
          "description": "Generation model configuration (tagged union on `model` field)."
        },
        "hydraulic_losses": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawHydraulicLosses"
            },
            {
              "type": "null"
            }
          ],
          "description": "Hydraulic loss model. Absent or null = lossless penstock."
        },
        "id": {
          "description": "Hydro plant identifier. Must be unique within the file.",
          "format": "int32",
          "type": "integer"
        },
        "name": {
          "description": "Human-readable plant name.",
          "type": "string"
        },
        "operational_start_date": {
          "description": "Date the entity enters service (ISO 8601 `YYYY-MM-DD`).",
          "type": "string"
        },
        "outflow": {
          "$ref": "#/$defs/RawOutflow",
          "description": "Total outflow bounds."
        },
        "penalties": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawHydroPenaltyOverrides"
            },
            {
              "type": "null"
            }
          ],
          "description": "Entity-level penalty overrides. When absent, every penalty uses the `hydro` section of `penalties.json`."
        },
        "reservoir": {
          "$ref": "#/$defs/RawReservoir",
          "description": "Reservoir storage bounds."
        },
        "specific_productivity_mw_per_m3s_per_m": {
          "default": null,
          "description": "Specific productivity `ρ_esp` (MW / ((m³/s) · m)).\n\n**Resolution cascade** (first source that supplies a non-`null` value wins):\n\n1. Per-`(hydro, stage)` row in `system/hydro_energy_productivity.parquet`\n   (loaded at study setup time by the solver).\n2. This field — a single value applied uniformly across all stages.\n\nAbsent or `null` means this fallback level is skipped.  If the cascade\nfinds no value for a hydro whose generation model requires one\n(`constant_productivity` or `linearized_head`), study setup fails with an\nexplicit error.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "tailrace": {
          "anyOf": [
            {
              "$ref": "#/$defs/RawTailrace"
            },
            {
              "type": "null"
            }
          ],
          "description": "Tailrace elevation model. Absent or null = no tailrace."
        },
        "travel_time_hours": {
          "default": null,
          "description": "Travel time on the cascade arc to `downstream_id` (hours). Absent or\nnull = instantaneous (v1 excludes diversion and pumping arcs).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "unit_groups": {
          "description": "Turbine groups partitioning this plant's generation envelope. Required:\nevery hydro declares at least one group, each with its own `id`, `name`,\n`bus_id`, and generation/turbined bounds; an absent or empty array is\nrejected.",
          "items": {
            "$ref": "#/$defs/RawUnitGroup"
          },
          "type": "array"
        }
      },
      "required": [
        "id",
        "name",
        "operational_start_date",
        "reservoir",
        "outflow",
        "generation",
        "unit_groups"
      ],
      "type": "object"
    },
    "RawHydroPenaltyOverrides": {
      "additionalProperties": false,
      "description": "Entity-level hydro penalty overrides.\n\nEach field is named after a field of the `hydro` section of `penalties.json`; an absent field falls back to that section's value.",
      "properties": {
        "diversion_cost": {
          "default": null,
          "description": "Diversion flow penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "evaporation_violation_cost": {
          "default": null,
          "description": "Symmetric evaporation violation penalty of this plant, applied in both\ndirections ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "filling_target_violation_cost": {
          "default": null,
          "description": "Filling-target violation penalty ($/hm³).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "generation_violation_below_cost": {
          "default": null,
          "description": "Generation below-minimum violation penalty ($/`MWh`).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "inflow_nonnegativity_cost": {
          "default": null,
          "description": "Inflow non-negativity penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "outflow_violation_above_cost": {
          "default": null,
          "description": "Outflow above-maximum violation penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "outflow_violation_below_cost": {
          "default": null,
          "description": "Outflow below-minimum violation penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "spillage_cost": {
          "default": null,
          "description": "Spillage penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "storage_violation_below_cost": {
          "default": null,
          "description": "Storage below-minimum violation penalty ($/hm³).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "turbined_cost": {
          "default": null,
          "description": "Turbined-flow regularization cost ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "turbined_violation_below_cost": {
          "default": null,
          "description": "Turbined-flow below-minimum violation penalty ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "water_withdrawal_violation_cost": {
          "default": null,
          "description": "Symmetric water withdrawal violation penalty of this plant, applied in\nboth directions ($/(m³/s·h)).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "RawOutflow": {
      "additionalProperties": false,
      "description": "The `outflow` sub-object.",
      "properties": {
        "max_outflow_m3s": {
          "description": "Maximum total outflow (m³/s). `null` = no upper bound.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "min_outflow_m3s": {
          "description": "Minimum total outflow (m³/s).",
          "format": "double",
          "type": "number"
        }
      },
      "required": [
        "min_outflow_m3s"
      ],
      "type": "object"
    },
    "RawReservoir": {
      "additionalProperties": false,
      "description": "The `reservoir` sub-object.",
      "properties": {
        "max_storage_hm3": {
          "description": "Maximum operational storage (hm³).",
          "format": "double",
          "type": "number"
        },
        "min_storage_hm3": {
          "description": "Minimum operational storage (dead volume) (hm³).",
          "format": "double",
          "type": "number"
        }
      },
      "required": [
        "min_storage_hm3",
        "max_storage_hm3"
      ],
      "type": "object"
    },
    "RawTailrace": {
      "description": "The `tailrace` sub-object. The `type` key selects the tailrace model.",
      "oneOf": [
        {
          "description": "Polynomial tailrace curve.",
          "properties": {
            "coefficients": {
              "description": "Polynomial coefficients in ascending power order.",
              "items": {
                "format": "double",
                "type": "number"
              },
              "type": "array"
            },
            "type": {
              "const": "polynomial",
              "type": "string"
            }
          },
          "required": [
            "type",
            "coefficients"
          ],
          "type": "object"
        },
        {
          "description": "Piecewise-linear tailrace curve.",
          "properties": {
            "points": {
              "description": "Breakpoints defining the piecewise-linear curve.",
              "items": {
                "$ref": "#/$defs/RawTailracePoint"
              },
              "type": "array"
            },
            "type": {
              "const": "piecewise",
              "type": "string"
            }
          },
          "required": [
            "type",
            "points"
          ],
          "type": "object"
        }
      ]
    },
    "RawTailracePoint": {
      "additionalProperties": false,
      "description": "A single piecewise tailrace breakpoint.",
      "properties": {
        "height_m": {
          "description": "Downstream water level (tailrace height) at this outflow (m).",
          "format": "double",
          "type": "number"
        },
        "outflow_m3s": {
          "description": "Total outflow at this point (m³/s).",
          "format": "double",
          "type": "number"
        }
      },
      "required": [
        "outflow_m3s",
        "height_m"
      ],
      "type": "object"
    },
    "RawUnitGroup": {
      "additionalProperties": false,
      "description": "A single declared entry in the `unit_groups` array.",
      "properties": {
        "bus_id": {
          "description": "Bus to which this group's generation is injected.",
          "format": "int32",
          "type": "integer"
        },
        "id": {
          "description": "Identifier, unique within the owning plant (not globally).",
          "format": "int32",
          "type": "integer"
        },
        "max_generation_mw": {
          "description": "Maximum electrical generation (MW).",
          "format": "double",
          "type": "number"
        },
        "max_turbined_m3s": {
          "description": "Maximum turbined flow (m³/s).",
          "format": "double",
          "type": "number"
        },
        "min_generation_mw": {
          "description": "Minimum electrical generation (MW).",
          "format": "double",
          "type": "number"
        },
        "min_turbined_m3s": {
          "description": "Minimum turbined flow (m³/s).",
          "format": "double",
          "type": "number"
        },
        "name": {
          "description": "Human-readable group name.",
          "type": "string"
        }
      },
      "required": [
        "id",
        "name",
        "bus_id",
        "min_generation_mw",
        "max_generation_mw",
        "min_turbined_m3s",
        "max_turbined_m3s"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "description": "Root object of `hydros.json`.",
  "properties": {
    "$schema": {
      "description": "`$schema` field — informational, not validated.",
      "type": [
        "string",
        "null"
      ]
    },
    "hydros": {
      "description": "Array of hydro plant entries.",
      "items": {
        "$ref": "#/$defs/RawHydro"
      },
      "type": "array"
    }
  },
  "required": [
    "hydros"
  ],
  "title": "RawHydroFile",
  "type": "object"
}