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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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