Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

All runtime parameters for cobre run are controlled by config.json in the case directory. This page documents every section and field.


Minimal Config

{
  "training": {
    "forward_passes": 50,
    "stopping_rules": [{ "type": "iteration_limit", "limit": 100 }]
  }
}

All other sections are optional with defaults documented below.


training

Controls the SDDP training phase.

Mandatory Fields

FieldTypeDescription
forward_passesintegerNumber of scenario trajectories per iteration. Larger values reduce variance in each iteration’s cut but increase cost per iteration.
stopping_rulesarrayAt least one stopping rule (see below). The rule set must contain at least one iteration_limit rule.

Optional Fields

FieldTypeDefaultDescription
enabledbooleantrueSet to false to skip training and proceed directly to simulation (requires a pre-trained policy).
tree_seedintegernullRandom seed for the opening scenario tree. When null, a default seed of 42 is used (deterministic but arbitrary). See Stochastic Modeling for the dual-seed architecture.
stopping_mode"any" or "all""any"How multiple stopping rules combine: "any" stops when the first rule is satisfied; "all" requires all rules to be satisfied simultaneously.

For the per-class scenario_source configuration, see the scenario_source sub-section below and Stochastic Modeling.

scenario_source

Controls where the forward-pass noise comes from for each entity class during training. When absent, all classes default to in_sample (reusing the pre-generated opening tree).

FieldTypeDefaultDescription
seedinteger or nullnullShared forward-pass seed for out_of_sample, historical, and external schemes.
inflowobjectin_sampleSampling scheme for hydro inflow. Object with "scheme" key.
loadobjectin_sampleSampling scheme for bus load. Object with "scheme" key.
ncsobjectin_sampleSampling scheme for NCS availability. Object with "scheme" key.
historical_yearsarray or objectauto-discoverRestrict the pool of historical windows. List ([1940, 1953]) or range ({"from": 1940, "to": 2010}).

Valid values for "scheme": "in_sample", "out_of_sample", "historical", "external".

Example — out-of-sample inflow with in-sample load and NCS:

{
  "training": {
    "tree_seed": 42,
    "forward_passes": 50,
    "stopping_rules": [{ "type": "iteration_limit", "limit": 200 }],
    "scenario_source": {
      "seed": 99,
      "inflow": { "scheme": "out_of_sample" },
      "load": { "scheme": "in_sample" },
      "ncs": { "scheme": "in_sample" }
    }
  }
}

See Stochastic Modeling — Sampling Schemes for a full description of each scheme and the historical_years field.

Stopping Rules

Each entry in stopping_rules is a JSON object with a "type" discriminator.

iteration_limit

Stop after a fixed number of training iterations.

{ "type": "iteration_limit", "limit": 200 }
FieldTypeDescription
limitintegerMaximum number of SDDP iterations to run.

time_limit

Stop after a wall-clock time budget is exhausted.

{ "type": "time_limit", "seconds": 3600.0 }
FieldTypeDescription
secondsfloatMaximum training time in seconds.

bound_stalling

Stop when the relative improvement in the lower bound falls below a threshold.

{ "type": "bound_stalling", "iterations": 20, "tolerance": 0.0001 }
FieldTypeDescription
iterationsintegerWindow size: the number of past iterations over which to compute the relative improvement.
tolerancefloatRelative improvement threshold. Training stops when the improvement over the window is below this value.

simulation

Stop when both the lower bound and a Monte Carlo policy cost estimate have stabilized. Periodically runs a batch of forward simulations and compares the result against previous evaluations.

{
  "type": "simulation",
  "replications": 100,
  "period": 10,
  "bound_window": 5,
  "distance_tol": 0.01,
  "bound_tol": 0.0001
}
FieldTypeDescription
replicationsintegerNumber of Monte Carlo forward simulations per check.
periodintegerIterations between simulation checks.
bound_windowintegerNumber of past iterations for bound stability check.
distance_tolfloatNormalized distance threshold between consecutive simulation results.
bound_tolfloatRelative tolerance for bound stability.

stopping_mode

When multiple stopping rules are listed, stopping_mode controls how they combine:

  • "any" (default): stop when any one rule is satisfied.
  • "all": stop only when every rule is satisfied simultaneously.
{
  "training": {
    "forward_passes": 50,
    "stopping_mode": "all",
    "stopping_rules": [
      { "type": "iteration_limit", "limit": 500 },
      { "type": "bound_stalling", "iterations": 20, "tolerance": 0.0001 }
    ]
  }
}

simulation

Controls the optional post-training simulation phase.

FieldTypeDefaultDescription
enabledbooleanfalseEnable the simulation phase after training.
num_scenariosinteger2000Number of independent Monte Carlo simulation scenarios to evaluate.

When simulation.enabled is false or num_scenarios is 0, the simulation phase is skipped entirely.

Example:

{
  "simulation": {
    "enabled": true,
    "num_scenarios": 1000
  }
}

scenario_source

Controls where the forward-pass noise comes from during the simulation phase. When absent, simulation falls back to the scheme configured under training.scenario_source. This allows you to train with in-sample noise and simulate with a different scheme (for example, out-of-sample or historical) without modifying the training configuration.

The fields are identical to training.scenario_source:

FieldTypeDefaultDescription
seedinteger or nullnullShared forward-pass seed for out_of_sample, historical, and external schemes.
inflowobjectin_sampleSampling scheme for hydro inflow. Object with "scheme" key.
loadobjectin_sampleSampling scheme for bus load. Object with "scheme" key.
ncsobjectin_sampleSampling scheme for NCS availability. Object with "scheme" key.
historical_yearsarray or objectauto-discoverRestrict the pool of historical windows. List ([1940, 1953]) or range ({"from": 1940, "to": 2010}).

Example — simulate with out-of-sample inflow while training uses in-sample:

{
  "training": {
    "forward_passes": 50,
    "stopping_rules": [{ "type": "iteration_limit", "limit": 200 }]
  },
  "simulation": {
    "enabled": true,
    "num_scenarios": 2000,
    "scenario_source": {
      "seed": 77,
      "inflow": { "scheme": "out_of_sample" },
      "load": { "scheme": "in_sample" },
      "ncs": { "scheme": "in_sample" }
    }
  }
}

modeling

Controls physical modeling options.

FieldTypeDefaultDescription
inflow_non_negativityobjectsee belowStrategy for handling negative PAR model inflow draws.

inflow_non_negativity

FieldTypeDefaultDescription
methodstring"penalty"One of "none", "penalty", "truncation", or "truncation_with_penalty".
  • "none" – no treatment; negative inflows are passed through to the LP.
  • "penalty" – adds a slack variable to the LP that absorbs negative inflow realisations. The slack carries a per-hydro objective cost from penalties.json::hydro.inflow_nonnegativity_cost.
  • "truncation" – clamps negative PAR model draws to zero before applying noise.
  • "truncation_with_penalty" – combines both: clamps the inflow to zero and adds a bounded slack variable penalised by penalties.json::hydro.inflow_nonnegativity_cost, providing a smooth backstop for extreme tail realisations.

Example:

{
  "modeling": {
    "inflow_non_negativity": {
      "method": "penalty"
    }
  }
}

cut_selection

Controls the row management pipeline for managing row pool growth. The pipeline has up to two stages: strategy-based selection and budget enforcement. Row management periodically scans the row pool and deactivates rows that are unlikely to improve the policy, reducing LP size without sacrificing convergence quality. For a detailed explanation of each stage, see Performance Accelerators.

The block has two always-on knobs at the top level plus a selection sub-object that chooses the method and carries only that method’s parameters. Omitting selection (or setting it to null) disables row selection — that is the default.

Always-on fields

FieldTypeDefaultDescription
row_activity_tolerancefloat0.0Minimum dual-multiplier magnitude for a constraint row to count as binding at a solution point. Rows whose dual falls below this are treated as inactive in tracking.
max_active_per_stageintegernullHard cap on active rows per stage LP, enforced after the selection method runs. null = no cap.
selectionobjectnullThe active selection method and its parameters (see below). null (the default) disables row selection.

The selection object

selection.method is the discriminator; each method exposes only its own parameters. Supplying a parameter that belongs to a different method is a config load error, and a misspelled method is rejected with the list of valid methods.

  • "level1" — evaluates all populated rows at every visited state and retains any row whose value is within tie_tolerance of the per-state maximum at some state. Least aggressive; preserves the convergence guarantee.

    FieldTypeDefaultDescription
    tie_tolerancefloat1e-10A row is active at a state when within this of the best row value there.
    check_frequencyinteger5Iterations between periodic pruning checks. Must be > 0.
  • "lml1" — at each visited state, retains only the oldest eligible row within tie_tolerance of the per-state maximum; the selected set is the union of those per-state survivors. More aggressive than "level1". Same fields as "level1" (tie_tolerance, check_frequency).

  • "domination" — removes rows dominated at all visited states.

    FieldTypeDefaultDescription
    domination_tolerancefloatA row survives if within this of the maximum at any visited state. Required.
    check_frequencyinteger5Iterations between periodic pruning checks. Must be > 0.
  • "dynamic" — a per-solve lazy loop that loads only a small resident subset of rows per solve while retaining the full pool. The resident set is seeded from the most recent iterations, and each lazy-solve round adds the most-violated candidate rows.

    FieldTypeDefaultDescription
    start_iterationinteger2First 1-based iteration at which the lazy loop becomes active. Must be >= 1.
    seed_windowinteger5Number of most-recent iterations whose rows seed the initial resident set. 0 is valid (seeds only the current iteration).
    candidate_recencyintegernullOnly rows generated within the last candidate_recency iterations are scored. null (the default) is unbounded — every pool row is a candidate, which preserves exactness. Some(n) (must be >= 1) makes the loop deliberately inexact: rows older than the window are never added.
    max_added_per_roundinteger10Maximum rows added per lazy-solve round. Must be >= 1.
    violation_tolerancefloat1e-10Violation tolerance for accepting a candidate row. Must be > 0.

The dynamic method is mutually exclusive with the periodic-pruning methods by construction — choosing it from the tagged selection block means none of level1 / lml1 / domination can run.

Example with the dynamic method:

{
  "training": {
    "cut_selection": {
      "row_activity_tolerance": 1e-6,
      "max_active_per_stage": 4000,
      "selection": {
        "method": "dynamic",
        "start_iteration": 2,
        "seed_window": 5,
        "max_added_per_round": 10,
        "violation_tolerance": 1e-10
      }
    }
  }
}

Example with the level1 method and a per-stage budget:

{
  "training": {
    "cut_selection": {
      "row_activity_tolerance": 1e-6,
      "max_active_per_stage": 500,
      "selection": {
        "method": "level1",
        "tie_tolerance": 1e-10,
        "check_frequency": 5
      }
    }
  }
}

estimation

Controls the PAR(p) model estimation pipeline. When the case provides inflow_history.parquet, Cobre can automatically estimate AR coefficients instead of requiring pre-computed inflow_ar_coefficients.parquet.

FieldTypeDefaultDescription
max_orderinteger6Maximum lag order considered during autoregressive model fitting.
order_selectionstring"pacf"Order selection criterion: "pacf" (PACF-based) or "pacf_annual" (PACF with annual component).
min_observations_per_seasoninteger30Minimum observations per (entity, season) group to proceed with estimation.
max_coefficient_magnitudefloatnullSafety net: reduce to order 0 if any coefficient exceeds this magnitude.

Example:

{
  "estimation": {
    "max_order": 6,
    "order_selection": "pacf",
    "min_observations_per_season": 30
  }
}

Setting "order_selection": "pacf_annual" activates the annual component extension. When enabled, the estimation pipeline performs four additional steps beyond the classical PAR path: (1) the Yule-Walker system is extended to include a cross-correlation term between the current-season inflow and the rolling 12-month average; (2) per-season sample statistics (mean and standard deviation) of that rolling average are computed for each hydro plant; (3) the coefficient, mean, and standard deviation are written to inflow_annual_component.parquet in the output directory; and (4) the lag stride used when building the LP noise columns is widened to accommodate the extra annual term. Use this option when your inflow series shows persistence that extends beyond the standard seasonal lag window.


policy

Controls policy persistence (checkpoint saving and warm-start loading).

FieldTypeDefaultDescription
pathstring"./policy"Directory where policy data (cuts, states) is stored.
mode"fresh", "warm_start", or "resume""fresh"Initialization mode. "fresh" starts from scratch; "warm_start" loads cuts from a previous run; "resume" continues an interrupted run.
validate_compatibilitybooleantrueWhen loading a policy, verify that entity counts, stage counts, and cut dimensions match the current system.
boundaryobject or nullnullTerminal boundary cut configuration for coupling with an outer model’s FCF. See below.

checkpointing

FieldTypeDefaultDescription
enabledbooleanfalseEnable periodic checkpointing during training.
initial_iterationintegernullFirst iteration to write a checkpoint.
interval_iterationsintegernullIterations between checkpoints.
store_basisbooleanfalseInclude LP basis in checkpoints for warm-start.
compressbooleanfalseCompress checkpoint files.

boundary

Optional configuration for loading terminal-stage boundary cuts from a different Cobre policy checkpoint. When present, the solver loads cuts from the source checkpoint and injects them as fixed boundary conditions at the terminal stage of the current study. The imported cuts are not updated by training — they remain fixed throughout.

This enables Cobre-to-Cobre model coupling: a monthly study produces a policy checkpoint, and a weekly+monthly coupled study loads that checkpoint’s cuts as its terminal-stage future cost function.

FieldTypeDescription
pathstringPath to the source policy checkpoint directory.
source_stageinteger0-based stage index in the source checkpoint to load cuts from.

Example — load stage 2’s cuts from a monthly policy as terminal boundary:

{
  "policy": {
    "mode": "fresh",
    "boundary": {
      "path": "../monthly_study/policy",
      "source_stage": 2
    }
  }
}

See Policy Management — Boundary Cuts for a full explanation of the coupling workflow.


Temporal Resolution

Cobre does not have dedicated config.json fields for temporal resolution. The resolution of each stage is determined entirely by the date boundaries in stages.json. However, when stages.json defines stages at different temporal resolutions — for example, four weekly stages within a month followed by monthly stages, or monthly stages transitioning to quarterly stages — three mechanisms activate automatically that users should understand.

Noise Group Sharing

When multiple SDDP stages share the same season_id within the same calendar period (for example, four weekly stages all assigned season_id: 0 for January), they receive identical PAR noise draws. This ensures that sub-monthly stages present an inflow trajectory consistent with the monthly PAR model they were fitted from, rather than fabricating independent weekly variability that the historical record does not support.

Observation Aggregation

When the study includes stages at different resolutions (for example, monthly and quarterly), Cobre automatically aggregates fine-grained historical observations into coarser season buckets before PAR fitting. A user supplying monthly inflow_history.parquet for a study that includes quarterly stages does not need to pre-aggregate the data; Cobre derives one observation per (entity, season, year) at the appropriate coarser resolution. Aggregating in the opposite direction (disaggregating coarser observations to a finer resolution) is not supported and will produce a validation error at case load time.

Lag Resolution Transition

For studies that transition from monthly to quarterly stages, the PAR lag state changes resolution at the boundary. During the monthly phase, each monthly inflow is accumulated into a ring buffer indexed by the downstream (quarterly) lag. When the first quarterly stage is reached, the ring buffer contains a complete set of duration-weighted monthly contributions, and the lag state is rebuilt automatically. This transition is transparent to the LP and the cut representation; it introduces no additional LP variables.

Example: Weekly Stages Within a Month

The following stages.json excerpt shows four weekly stages within January (stages 0-3, all with season_id: 0) followed by a normal monthly stage for February (season_id: 1). Stages 0-3 share the same season_id and will therefore receive identical PAR noise draws during training:

[
  {
    "id": 0,
    "start_date": "2024-01-01",
    "end_date": "2024-01-08",
    "season_id": 0,
    "num_scenarios": 50
  },
  {
    "id": 1,
    "start_date": "2024-01-08",
    "end_date": "2024-01-15",
    "season_id": 0,
    "num_scenarios": 50
  },
  {
    "id": 2,
    "start_date": "2024-01-15",
    "end_date": "2024-01-22",
    "season_id": 0,
    "num_scenarios": 50
  },
  {
    "id": 3,
    "start_date": "2024-01-22",
    "end_date": "2024-02-01",
    "season_id": 0,
    "num_scenarios": 50
  },
  {
    "id": 4,
    "start_date": "2024-02-01",
    "end_date": "2024-03-01",
    "season_id": 1,
    "num_scenarios": 50
  }
]

When weekly dispatch granularity is needed but true weekly-resolution noise data is unavailable, the recommended approach is to use a single monthly SDDP stage with chronological blocks rather than four separate weekly SDDP stages. This provides weekly LP granularity while keeping one noise realization per month — consistent with the data resolution — and avoids the lag-accumulation complications that arise with multiple independent weekly stages. See Stochastic Modeling — Temporal Resolution and PAR for the full explanation and a stages.json example of the block pattern.

See Also (Temporal Resolution)


exports

Controls which outputs are written to the results directory.

FieldTypeDefaultDescription
statesbooleanfalseWrite visited forward-pass trial points to the policy checkpoint (FlatBuffers).
stochasticbooleanfalseExport stochastic preprocessing artifacts to output/stochastic/.
fpha_deviation_pointsbooleanfalseExport the per-grid-point computed-FPHA fit-deviation table to output/hydro_models/fpha_deviation_points.parquet. Opt-in because it emits one row per (hydro, stage, V, Q) sample point at spillage = 0.

Full Example

{
  "$schema": "https://raw.githubusercontent.com/cobre-rs/cobre/refs/heads/main/book/src/schemas/config.schema.json",
  "training": {
    "tree_seed": 42,
    "forward_passes": 50,
    "stopping_rules": [
      { "type": "iteration_limit", "limit": 200 },
      { "type": "bound_stalling", "iterations": 20, "tolerance": 0.0001 }
    ],
    "stopping_mode": "any",
    "scenario_source": {
      "seed": 99,
      "inflow": { "scheme": "out_of_sample" },
      "load": { "scheme": "in_sample" },
      "ncs": { "scheme": "in_sample" }
    },
    "cut_selection": {
      "row_activity_tolerance": 1e-6,
      "max_active_per_stage": null,
      "selection": {
        "method": "level1",
        "tie_tolerance": 1e-10,
        "check_frequency": 5
      }
    }
  },
  "modeling": {
    "inflow_non_negativity": {
      "method": "penalty"
    }
  },
  "simulation": {
    "enabled": true,
    "num_scenarios": 2000
  },
  "policy": {
    "path": "./policy",
    "mode": "fresh"
  },
  "exports": {
    "states": false,
    "stochastic": false
  }
}

Advanced Fields

The Config struct supports additional sections not documented on this page. These fields are deserialized from config.json when present but are intended for advanced use cases and may change between releases:

SectionPurpose
upper_bound_evaluationInner approximation upper-bound evaluation settings
training.solverLP solver options (see Solver Safeguards for details)
simulation.io_channel_capacityAsync I/O channel buffer size for simulation output writing

All fields have defaults and can be omitted. Every JSON input file rejects unknown keys, so misspelled fields raise a parse error rather than being silently ignored. For the complete list of fields and their types, see the Config struct in the cobre-io API docs.


See Also