Skip to content

[GP-02] Fix optim-config.yml doc inaccuracies: solver-options.name enum claim, required mode/location fields #262

Description

@tbittar

Process GP-02 — Triggered by internal initiative to fix, improve, or extend GemsPy. Not driven by a new GEMS Language version.

Deviation from standard workflow — Step 3: extended impact analysis on results is required. You must explicitly state whether solver results are expected to change, and if so, document the reasoning.

Affected Component

Decomposition / optim-config (optim_config/)

Type of Change

Patch: dependency update, code optimisation, or internal refactor with no syntax impact

Description

While auditing docs/user-guide/optim-config.md against the actual Pydantic schema in src/gems_craft/optim_config/parsing.py, I found two places where the documented format doesn't match what load_optim_config() actually accepts. Both were confirmed by loading real YAML through load_optim_config().

1. solver-options.name is documented as a closed enum, but it's a free string.

The docs table (optim-config.md, "solver-options" section) reads:

name | str | "highs" | Solver name: "highs" (default), "xpress", or "gurobi"

SolverOptionsConfig.name (parsing.py:112) is a plain str field with no validator restricting its value. It's forwarded verbatim to linopy's solve(solver_name=...) (gems_runner/simulation/optimization.py:347), which supports additional solvers (e.g. cbc, glpk, scip, mosek, copt...). Confirmed:

load_optim_config(path_with("solver-options:\n  name: cbc\n"))
# -> config.solver_options.name == "cbc", no error

The doc should either state that name accepts any solver name supported by the installed linopy backend (with highs/xpress/gurobi as the officially supported/tested ones), or explicitly note that GemsPy itself does not validate this value — validation/failure happens at solve time in the solver backend.

2. The "(default)" annotations for mode and location are misleading — both fields are actually required once an entry is listed.

  • In "out-of-bounds-processing" the table shows: `cyclic` (default) | Wrap around...
  • In "model-decomposition" the table shows: `subproblems` (default) | Element lives in each operational subproblem

Both read as if you can omit the mode / location key on a listed entry and get the default. In reality:

models:
  - id: storage
    out-of-bounds-processing:
      constraints:
        - id: soc_balance   # no `mode` key

raises pydantic.ValidationError: models.0.out-of-bounds-processing.constraints.0.mode — Field required, because OutOfBoundsConstraintConfig.mode (parsing.py:70) has no default. Same for ElementLocationConfig.location (parsing.py:54) — omitting location on a listed variable/constraint/objective-contribution also raises Field required.

The actual default only applies to elements that are not listed at all in the constraints / variables / constraints / objective-contributions arrays (per the OutOfBoundsFilter docstring in gems_runner/simulation/optimization.py:141-147: "Constraints not listed in the config default to cyclic wrap-around"). The docs should clarify that mode/location are mandatory for any entry that is listed, and that "default" refers only to entirely-omitted elements.

Results Impact

No — this is a documentation-only change. No parsing code, defaults, or solver behaviour are modified; solver output values are unaffected. Confirmed by re-running the existing optim-config unit test suite unchanged.

Validation Strategy

  • Existing unit tests in tests/unittests/gems_craft/optim_config/ already cover the actual (correct) required-field and free-string behaviour described above — the fix only touches prose/tables in docs/user-guide/optim-config.md, so no new tests are needed.
  • Manual repro used to confirm both discrepancies (reproducible against main @ 7fbc3f41):
    from pathlib import Path
    from gems_craft.optim_config import load_optim_config
    # 1) arbitrary solver name accepted
    load_optim_config(<yaml with solver-options.name: cbc>)  # succeeds
    # 2) missing `mode` / `location` on a listed entry raises
    load_optim_config(<yaml with out-of-bounds constraint missing `mode`>)  # ValidationError: Field required
    load_optim_config(<yaml with model-decomposition variable missing `location`>)  # ValidationError: Field required
  • No E2E/reference-study validation needed since no solver-facing code changes.

Process Checklist

Step 1 — Issue Creation

  • Issue created and linked to process GP-02

Step 2 — Triage

  • Process confirmed applicable
  • Assigned to responsible contributor
  • Priority and milestone set (if applicable)

Step 3 — Impact Analysis ⚠️ extended results analysis required

  • Affected modules identified
  • Results impact explicitly stated: no change intended (docs-only)
  • If results expected to change: before/after difference described and justified
  • Breaking vs backward-compatible change determined (backward-compatible; docs-only)

Step 4 — Implementation

  • Code changes implemented
  • Backward compatibility maintained unless explicitly intended as breaking

Step 5 — Testing & Validation

  • If results expected to change: reference studies updated with new expected values
  • If results must not change: solver equivalence confirmed via tests
  • Unit tests cover changed components

Step 6 — CI Validation

  • Type checking passes (mypy)
  • Formatting passes (black, isort)
  • All tests pass in CI (pytest)

Step 7 — Review & Merge

  • PR reviewed; documentation changes included

Step 8 — Versioning

  • pyproject.toml version bumped

Step 9 — Supporting Files

  • AGENTS.md reviewed for impact and updated if needed

Step 10 — Release

  • If a release is needed: follow the release process in the Developer Guidelines

Metadata

Metadata

Assignees

No one assigned

    Labels

    GP-02Internal GemsPy bug fixes, features, or improvements (not driven by a GEMS Language release)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions