Skip to content

refac!: size and capacity are what a flow and a storage have, decided or given - #350

Closed
FBumann wants to merge 1 commit into
refac/reportingfrom
refac/size-expressions
Closed

FBumann wants to merge 1 commit into
refac/reportingfrom
refac/size-expressions

Conversation

@FBumann

@FBumann FBumann commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

Prompt: "I think the "size" should be an expression after all! With a var where its a var, and a number where its fixed etc...? Than we can use the size epression in constraints"

(Intent: to be written by the author.)

Note

The following content was generated by AI.

Description

Stacked on #349. The program names the expressions size and capacity: the decision where there is one, the given number otherwise. The rows that scale with a size or a capacity read them. The decisions are renamed chosen_size and chosen_capacity, and only the rows that bound or link a decision name them. Same model, row for row.

size:                      # sizing.yaml (was flow_size)
  cases: {decided: {when: "chosen_size", expression: chosen_size}}
  otherwise: size_bound
capacity:                  # storage.yaml (new; was reporting's storage_capacity)
  cases: {decided: {when: "chosen_capacity", expression: chosen_capacity}}
  otherwise: given_capacity
reads the expression still names the decision
envelope rows, status_sizing_rate_max/min, ramps, load factor sizing_min/max, status_sizing_gate_size, investment links, where: that asks whether a decision exists
storage cap_level_max, cap_level_rel_min/max cap_min/max on the capacity decision
capacity_factor, relative_mean_level per-size cost contributions (chosen_size * effects_per_size)

Not changed: the variable bounds for fixed sizes (rate_min/max, level_min/max) stay folded in the data. A bound must be a parameter, and turning them into rows would add one row per flow and step.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Code refactoring

Related Issues

Stacked on #349.

Testing

  • I have tested my changes
  • Existing tests still pass
Model counts and gates

The same variables, rows and nonzeros as #349 on all five reference systems at 168 steps:

district_heating   2691 / 2017 / 6551
industry_park      5887 / 8058 / 23324
green_city         4710 / 2864 / 11602
energy_transition  37664 / 18856 / 84704
stress             94480 / 214338 / 656818

Result still reports flow--size and storage--capacity from the decision variables, so no reader changes. stats.resolved_sizes and resolved_capacities read the new expressions.

pytest tests -n auto           732 passed, 74 skipped
benchmark/ pytest (smoke)      41 passed
ruff check / format            clean
pyrefly check                  2 local pandas-stubs errors, the same as on base

Checklist

  • My code follows the project style
  • I have updated documentation if needed
  • I have added tests for new functionality (if applicable)

🤖 Generated with Claude Code

https://claude.ai/code/session_01UVhM31okkc7zrhYj7DncVs


Generated by Claude Code

…ided or given

The program names the expressions `size` and `capacity`: the decision
where there is one, the given number otherwise. The rows that scale with
a size or a capacity read them (envelope, ramps, load factor, storage
level, reporting). The decisions themselves are `chosen_size` and
`chosen_capacity`, and only the rows that bound or link a decision name
those. The fixed capacity is bound as `given_capacity` in storage.yaml.
Same model, row for row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UVhM31okkc7zrhYj7DncVs
@github-actions

Copy link
Copy Markdown
Contributor

Benchmark hint

benchmark/test_reference.py under pytest-benchmem — quarter-year horizon; peak = memray allocator high-water, as on CodSpeed. The label columns are each model's size: the temporal grid (timesteps × periods), element stats (components/flows/effects/series) and the measured solver model (variables/binaries/constraints). Shared-runner walltime is noisy: a hint, not a gate.

test_reference_build

name time (s) mean peak (MiB) mean timesteps periods components flows effects series variables constraints
test_reference_build[district_heating] (run) 1.151 8.99 2,190 1 8 15 2 6 35,043 26,281
test_reference_build[energy_transition] (run) 2.16 73.09 2,190 8 15 25 3 10 490,592 245,320
test_reference_build[green_city] (run) 1.258 9.33 2,190 1 15 25 3 10 61,326 37,238
test_reference_build[industry_park] (run) 1.345 8.93 2,190 1 9 16 2 5 76,657 105,114
test_reference_build[stress] (run) 9.016 125.89 136 16 83 204 30 270 503,056 1,180,226
Replicate locally / compare against refac/reporting
uvx --from 'pytest-benchmem[plot]' benchmem sweep fluxopt \
    git+https://github.com/fluxopt/fluxopt@refac/reporting \
    git+https://github.com/fluxopt/fluxopt@refac/size-expressions \
    --suite benchmark/ --memory
uvx --from 'pytest-benchmem[plot]' benchmem compare .benchmarks/sweep/*.json

One fresh venv per ref, checkout untouched; covers the archetype, IO and reference-system benchmarks. Alternative flows: benchmark/README.md.

@FBumann
FBumann marked this pull request as ready for review September 29, 2026 07:00
FBumann added a commit that referenced this pull request Sep 29, 2026
_(Intent: to be written by the author.)_

> [!NOTE]
> The following content was generated by AI.

## Description

The stack #274 → #357 in one PR, so it lands with one merge and one CI
run instead of 62. Each commit below was already reviewed in its own PR.
This PR adds only the merges that bring the stack up to date with
`main`, plus one doc fix.

**Included PRs, bottom to top:** #274, #275, #289, #290, #291, #293,
#294, #295, #296, #297, #298, #299, #300, #301, #302, #303, #304, #305,
#306, #307, #308, #310, #311, #312, #313, #314, #315, #316, #317, #318,
#319, #320, #321, #322, #323, #324, #325, #326, #327, #328, #329, #330,
#331, #332, #333, #336, #341, #342, #343, #344, #345, #346, #347, #348,
#349, #350, #351, #352, #353, #354, #355, #357.

**How `main` was brought in:** main was merged into #274 and then
carried up the stack one branch at a time. The branch that first ran
into each conflict got the fix:
- `pyproject.toml` (#290, #341): kept the stack's dependency block and
applied main's `linopy==0.9.0` pin. #354 later drops `linopy` and
`netcdf4`, and that wins.
- `README.md` (#319, #351): kept the stack's text and restyled the code
blocks the way ruff 0.16 formats them (main's lint bump).
- `benchmark/uv.lock` (#341): regenerated with `uv lock`.
- ruff 0.16 also reformats four notebooks (#351). The same formatting is
in 19ab587.
- #213 is already reverted on `main` (#356). `main`'s tree equals the
revert commit inside the stack (ef32b05), so the merge with `main` takes
the stack's tree unchanged.
- #357 on top: the ruff `T201` ignores keep main's
`benchmark/flixopt_stress.py` and swap `src/fluxopt/benchmark.py` for
`benchmark/reference.py`. The two `python -m fluxopt.benchmark stress`
commands that main's #271 added (`benchmark/flixopt_stress.py`,
`docs/benchmark.md`) now point at `reference.py`.

These merge commits were never pushed to the stack branches, so those
PRs still show conflicts on GitHub. Once this merges, they can be
closed.

## Type of Change
- [ ] Bug fix
- [x] New feature
- [x] Documentation update
- [x] Code refactoring

## Related Issues
Supersedes #274 … #357 (the list above).

## Testing
- [x] I have tested my changes
- [x] Existing tests still pass

<details><summary>Gates</summary>

On this branch:

```text
pytest tests -n auto                    695 passed, 72 skipped
benchmark/ pytest --benchmark-disable   31 passed
ruff check / format                     clean
pyrefly check                           0 errors
```

At the branches where a conflict was resolved (before #357):

```text
#290 chore/pin-lpspec                700 passed, 83 skipped   lint ok
#341 chore/specsolve-mathspec-0.2    704 passed, 74 skipped   lint ok
#351 refac/specsolve-api             710 passed, 72 skipped   lint ok
#354 refac/drop-dead-weight          704 passed, 72 skipped   lint ok
#355 refac/timestamps-only           703 passed, 72 skipped   lint ok
```

#274 and #319 could not be tested: their pinned git dependencies no
longer resolve (`farkas` is now published as `specsolve`). That affects
only those intermediate states, not this branch. The docs build and
notebooks were left to CI.

</details>

## Checklist
- [x] My code follows the project style
- [x] I have updated documentation if needed
- [x] I have added tests for new functionality (if applicable)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_0182CG6AhGfcNcWshCsR8Rt5

---
_Generated by [Claude
Code](https://claude.ai/code/session_0182CG6AhGfcNcWshCsR8Rt5)_

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

FBumann commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

Note

The following content was generated by AI.

Landed in #358 (squash-merged into main as 4c0f220).


Generated by Claude Code

@FBumann FBumann closed this Sep 29, 2026
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.

2 participants