Skip to content

Add grid model: event-constrained power flow on IEEE 14-bus#101

Merged
bernalde merged 6 commits into
SECQUOIA:mainfrom
dovallev:add-grid-model
May 14, 2026
Merged

Add grid model: event-constrained power flow on IEEE 14-bus#101
bernalde merged 6 commits into
SECQUOIA:mainfrom
dovallev:add-grid-model

Conversation

@dovallev

@dovallev dovallev commented May 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a new GDP benchmark model for event-constrained optimal power flow on the IEEE 14-bus network.

Model description

The model minimizes the total capacity slack added to generators and transmission lines so that power balance constraints are satisfied across a set of Monte Carlo load scenarios (default: 500 samples drawn from a multivariate normal distribution).

Rather than requiring all equipment to stay within limits in every scenario (a joint chance constraint), an event constraint with ATLEAST logic requires that at least active_gens generators and active_lines transmission lines simultaneously satisfy their capacity bounds. This event must hold in at least 90% of scenarios (\alpha = 0.9), approximated via Sample Average Approximation.

The GDP formulation encodes whether each capacity constraint is satisfied or violated per scenario using disjunctions, and connects them to a per-scenario Boolean event variable via a logical equivalence (equivalent + land + atleast).

Reference

Ovalle, D., Mazzadi, S., Laird, C. D., Grossmann, I. E., & Pulsipher, J. L. (2025). Event constrained programming. Computers & Chemical Engineering, 199, 109145. https://doi.org/10.1016/j.compchemeng.2025.109145

Problem size (default: active_gens=4, active_lines=20, num_samples=500)

Problem vars Bool bin int cont cons nl disj disjtn
grid 47525 35000 0 0 12525 52000 0 35000 12500

Changes

  • gdplib/grid/grid.py — new model with build_model(active_gens=4, active_lines=20, num_samples=500)
  • gdplib/grid/__init__.py — exposes build_model following library conventions
  • gdplib/grid/README.md — model documentation with problem description, reference, and size table
  • gdplib/__init__.py — registers gdplib.grid
  • tests/test_comprehensive_coverage.py, tests/test_model_structure.py, tests/test_module_imports.py — added "grid" to the manual module lists

Comment thread gdplib/grid/grid.py

@bernalde bernalde left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking issues:

  1. build_model() resets NumPy's process-global RNG.
  2. The new grid model only has generic smoke coverage; it needs grid-specific tests for the public behavior and transformation path.

Nonblocking issues:

  1. gdplib/grid/grid.py does not pass the repo Black check.
  2. The branch currently conflicts with main after #98 added multiperiod_blending; rebase/merge main and keep both modules in the import and test lists.
  3. Consider tightening validation for integer parameters and num_samples > 0.

Questions:
None.

Tests run and outcomes:

  • pytest tests/test_module_imports.py::TestModuleImports::test_build_model_callable[grid] tests/test_comprehensive_coverage.py::TestComprehensiveCoverage::test_model_construction_and_execution[grid] tests/test_model_structure.py::TestModelStructure::test_build_model_has_docstring[grid] -v --tb=short: passed, 3 tests.
  • python -c "from gdplib.grid import build_model; from pyomo.environ import TransformationFactory; m=build_model(num_samples=3); TransformationFactory('core.logical_to_linear').apply_to(m); TransformationFactory('gdp.bigm').apply_to(m)": passed.
  • pytest tests/ -v --tb=short: passed, 212 passed, 1 skipped, 4 warnings, under local Python 3.13.5.
  • black gdplib/grid/grid.py --check --diff -S -C: failed; Black would reformat the new file.
  • flake8 gdplib/grid/grid.py --count --select=E9,F63,F7,F82 --show-source --statistics: passed.
  • typos --config ./.github/workflows/typos.toml gdplib/grid/README.md gdplib/grid/grid.py: not run because typos is not installed locally.
  • Supported-version local pytest was attempted with Python 3.12, but that interpreter has neither pytest nor pyomo installed here. GitHub Actions reports test-python-3.9, 3.10, 3.11, 3.12, coverage-report, and test-pip-installation passing; lint/style-and-typos failing at Black Formatting Check.

This PR should not be merged as-is. I would not merge this until the blocking issues above are addressed.

Comment thread gdplib/grid/grid.py Outdated
Comment thread tests/test_comprehensive_coverage.py
Comment thread gdplib/grid/grid.py Outdated
@dovallev

Copy link
Copy Markdown
Contributor Author
  1. Global rng fixed.
  2. Tests grid-specific tests were added using num_samples=10.
  3. Black formatting applied to grid.py and all files from the merge.
  4. sympy>=1.0 added to requirements.txt and pyproject.toml (Sergey's comment)
  5. Parameter validation tightened (integers + num_samples > 0)
  6. Upstream merged — grid and multiperiod_blending coexist in all import/test lists

@bernalde bernalde left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking issues:

  1. Runtime dependency metadata and the committed Pixi lock are inconsistent after adding sympy.
  2. The new model is not registered with the generated model-size reporting workflow.

Nonblocking issues:

  1. The PR introduces trailing whitespace/line-ending churn in gdplib/kaibel/main_gdp.py.
  2. Focused flake8 on the new grid files reports avoidable lint debt.

Questions:
None.

Tests run and outcomes:

  • pixi run --locked pytest tests/test_grid.py -v --tb=short: failed immediately with lock-file not up-to-date with the workspace.
  • pixi run pytest tests/test_grid.py -v --tb=short: passed, 20 tests, after Pixi resolved the missing lock entries locally.
  • pixi run test: passed, 313 passed, 1 skipped, after Pixi resolved the missing lock entries locally.
  • pixi run lint: passed.
  • git diff --check origin/main...HEAD: failed on trailing whitespace in gdplib/kaibel/main_gdp.py.
  • pixi run flake8 gdplib/grid tests/test_grid.py --max-complexity=10 --max-line-length=88 --statistics: failed on unused imports, long lines, ambiguous l, and complexity.
  • Small solve smoke test with build_model(num_samples=5), core.logical_to_linear, gdp.bigm, and GLPK: optimal, objective 0.0.

This PR should not be merged as-is. I would not merge this until the blocking issues above are addressed.

Comment thread pyproject.toml
Comment thread gdplib/grid/README.md
Comment thread gdplib/kaibel/main_gdp.py
Comment thread gdplib/grid/grid.py Outdated
@dovallev

Copy link
Copy Markdown
Contributor Author

Addressed the blocking and nonblocking items from the latest review:

  • Added sympy>=1.0 to pixi.toml and setup.py; regenerated pixi.lock so pixi run --locked works correctly.
  • Registered grid in generate_model_size_report.py, generated gdplib/grid/model_size_report.md, and added the grid column to the root README.md size table.
  • Removed unused imports (Constraint, Disjunction in grid.py; Disjunct in test_grid.py); renamed ambiguous loop variable l to ln.

dovallev added 5 commits May 14, 2026 12:14
…etwork

Adds a GDP model for capacity expansion of the IEEE 14-bus power network under
stochastic nodal demands. Uses ATLEAST logic to enforce an event constraint
(alpha=0.9 via SAA) requiring a minimum number of generators and lines to
simultaneously satisfy capacity bounds across sampled scenarios.

Reference: Ovalle et al. (2025). Event constrained programming.
Computers & Chemical Engineering, 199, 109145.
https://doi.org/10.1016/j.compchemeng.2025.109145
- Add sympy>=1.0 to pixi.toml, setup.py; regenerate pixi.lock so
  pixi run --locked works correctly
- Register grid in generate_model_size_report.py, generate
  gdplib/grid/model_size_report.md, update root README.md size table
- Remove unused imports (Constraint, Disjunction in grid.py; Disjunct
  in test_grid.py); rename ambiguous loop variable l -> ln
@bernalde

bernalde commented May 14, 2026

Copy link
Copy Markdown
Member

Pushed f490890 (Address PR 101 review cleanup) to dovallev:add-grid-model.

Main changes made:

  • Applied Black formatting to the PR-touched files that were causing the current lint CI failure.
  • Removed the remaining Kaibel whitespace/line-ending artifacts so the PR diff is clean under git diff --check.
  • Wrapped the remaining long grid docstring lines and added a targeted # noqa: C901 for the expected large declarative build_model() body; the focused grid flake8 check now passes.
  • Verified the force-pushed branch already addressed the prior functional review items: local NumPy RNG use, grid-specific tests, parameter validation, SymPy dependency alignment, Pixi lock update, and generated model-size report integration.

Tests and checks run:

  • pixi run --locked pytest tests/test_grid.py -v --tb=short: 20 passed.
  • pixi run --locked flake8 gdplib/grid tests/test_grid.py --max-complexity=10 --max-line-length=88 --statistics: passed.
  • pixi run --locked lint: passed.
  • pixi run --locked test: 317 passed, 1 skipped.
  • git diff --check origin/main...HEAD: passed.

Comments intentionally not addressed:

  • None. The remaining unresolved review threads appear addressed by the force-pushed branch plus f490890.
  • I did not mark threads resolved, per request.

Remaining risks or follow-up:

  • GitHub Actions reran on f490890 and all checks passed.
  • No solver-backed default optimality run was added; coverage remains construction, validation, and GDP transformation focused, keeping optional solvers out of default tests.

@bernalde bernalde left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh maintainer review at f490890.

I do not see remaining blocking or nonblocking issues in the current diff. The previous review comments appear adequately addressed: RNG isolation, grid-specific tests, parameter validation, dependency and Pixi lock alignment, generated model-size reporting, whitespace cleanup, and focused grid lint cleanup are all in place.

Verification:

  • Inspected the current PR diff, commits since the prior reviews, generated docs, dependency manifests, tests, and surrounding registration code.
  • GitHub Actions on f490890 are all passing.
  • git diff --check origin/main...HEAD: passed.
  • pixi run --locked pytest tests/test_grid.py tests/test_generate_model_size_report.py -v --tb=short: 26 passed.
  • pixi run --locked flake8 gdplib/grid tests/test_grid.py --max-complexity=10 --max-line-length=88 --statistics: passed.
  • Focused model-size check for gdplib.grid.build_model() matched the committed report values.
  • Small transformed GLPK smoke test with num_samples=5: optimal, objective 0.0.

Residual risk: no solver-backed default optimality evidence for the full benchmark instance was added, which is appropriate for this repository because optional solvers should stay out of default CI.

@bernalde bernalde merged commit 867c720 into SECQUOIA:main May 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants