Skip to content

Small penalties to prevent volatile asset utilisation - #1478

Merged
tsmbland merged 5 commits into
mainfrom
timeslice_equalisation
Aug 12, 2026
Merged

Small penalties to prevent volatile asset utilisation#1478
tsmbland merged 5 commits into
mainfrom
timeslice_equalisation

Conversation

@tsmbland

@tsmbland tsmbland commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds a small penalty on peak seasonal/annual utilisation to promote even spreading of utilisation, rather than loading all production onto a single timeslice/season. This is especially useful for seasonally/annually balanced commodities, which may otherwise have no incentive for one activity profile over the other. The rationale for this is that there may be costs involved with having to maintain a high level of capacity to support peak use, and/or costs associated with switching between high and low activity. The penalties should be kept very small so they don't dominate the primary objective and only serve to break ties between otherwise equally good solutions.

The main reason for this is to avoid arbitrary activity profiles as a result of the solver picking one amongst many equally good solutions. We can see in the results that there are fewer zeros in the flows files, which previously often arose when assets choose to serve full seasonal demands in one or two timeslices, which in the real world wouldn't happen.

This also helps with #1399 and #1174, although to fully close both of these we also need additional constraints to spread utilisation evenly among equally good assets (i.e. removing the ability to chose arbitrarily among equally good assets). That's coming in #1477

Screenshot from documentation

Screenshot 2026-08-11 at 13 35 51

Performance discussion

If both penalties are active (>0), this adds:

  • n_assets * (n_seasons + 1) variables
  • n_assets * (n_timeslices + n_seasons) constraints

i.e. scales linearly with the number of assets and temporal granularity. The performance cost for the example models is about 5-10%. For the simple_modified example, which has many more assets, it's more like 30%. I think this is probably acceptable, and since the number of added variables/constraints increases linearly with the problem size, I wouldn't expect the performance cost to vary much in % terms even for much larger models.

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change to fix an issue)
  • New feature (non-breaking change to add functionality)
  • Refactoring (non-breaking, non-functional change to improve maintainability)
  • Optimization (non-breaking change to speed up the code)
  • Breaking change (whatever its nature)
  • Documentation (improve or add documentation)

Key checklist

  • All tests pass: $ cargo test
  • The documentation builds and looks OK: $ cargo doc
  • Update release notes for the latest release if this PR adds a new feature or fixes a bug
    present in the previous release

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.29730% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.91%. Comparing base (aa7a39d) to head (6046c6b).

Files with missing lines Patch % Lines
src/simulation/optimisation/constraints.rs 97.24% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1478      +/-   ##
==========================================
+ Coverage   89.78%   89.91%   +0.13%     
==========================================
  Files          60       60              
  Lines        8445     8556     +111     
  Branches     8445     8556     +111     
==========================================
+ Hits         7582     7693     +111     
+ Misses        545      543       -2     
- Partials      318      320       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tsmbland
tsmbland force-pushed the timeslice_equalisation branch from 93a1eb9 to ea81668 Compare August 11, 2026 10:01
@tsmbland
tsmbland changed the base branch from asset_equalisation to main August 11, 2026 10:01
@tsmbland
tsmbland requested a lite review from Copilot August 11, 2026 11:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces optional seasonal and annual utilisation “peak” penalties in the dispatch optimisation objective to encourage smoother intra-season and inter-season activity profiles, helping break ties when seasonal/annual commodity balances otherwise leave dispatch underdetermined.

Changes:

  • Added auxiliary variables and constraints to represent seasonal peak capacity requirements (and optionally annual peak) per asset, and included them as small weighted terms in the optimisation objective.
  • Added two new model parameters (seasonal_utilisation_penalty, annual_utilisation_penalty) with defaults and schema support.
  • Documented the mathematical formulation of the new penalties in the dispatch optimisation docs.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/simulation/optimisation/constraints.rs Adds seasonal/annual peak variables, constraints, and objective coefficients for utilisation equalisation.
src/model/parameters.rs Introduces new penalty parameters and defaults in ModelParameters.
schemas/input/model.yaml Exposes the new parameters in the input schema (types, defaults, notes).
docs/model/dispatch_optimisation.md Documents the new penalties and their mathematical formulation.
Suppressed comments (1)

src/simulation/optimisation/constraints.rs:174

  • This comment says the variable represents "seasonal peak activity", but the variable is actually the peak capacity required (as used in the constraints and objective).
    // Create a variable for each (asset, season) pair, representing the seasonal peak activity
    let mut seasonal_peak_vars = SeasonalPeakVariableMap::new();

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/simulation/optimisation/constraints.rs Outdated
Comment thread src/simulation/optimisation/constraints.rs Outdated
Comment thread docs/model/dispatch_optimisation.md
Comment thread src/model/parameters.rs
Comment on lines +147 to +148
seasonal_utilisation_penalty: MoneyPerCapacityPerYear(1e-6),
annual_utilisation_penalty: MoneyPerCapacityPerYear(1e-6),
Comment thread src/simulation/optimisation/constraints.rs
@tsmbland
tsmbland force-pushed the timeslice_equalisation branch from 9e118c3 to 8daa78d Compare August 11, 2026 12:13
@tsmbland
tsmbland marked this pull request as ready for review August 11, 2026 12:50
@tsmbland tsmbland changed the title Timeslice equalisation Small penalties to prevent volatile asset utilisation Aug 11, 2026

@ahawkes ahawkes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Would be good to be able to roll back though, in case we find issues when running more complex models.

@tsmbland

Copy link
Copy Markdown
Collaborator Author

LGTM. Would be good to be able to roll back though, in case we find issues when running more complex models.

It can be turned off by setting the penalties to zero (in this case the variables/constraints wouldn't be added). The code is also pretty self-contained, so would be easy to delete if we ever wanted to.

@tsmbland tsmbland added this to MUSE Aug 12, 2026
@tsmbland tsmbland moved this to 👀 In review in MUSE Aug 12, 2026
@tsmbland tsmbland self-assigned this Aug 12, 2026

@dc2917 dc2917 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Implementation looks perfectly reasonable to me

@tsmbland
tsmbland merged commit f3af853 into main Aug 12, 2026
7 of 8 checks passed
@tsmbland
tsmbland deleted the timeslice_equalisation branch August 12, 2026 13:53
@github-project-automation github-project-automation Bot moved this from 👀 In review to ✅ Done in MUSE Aug 12, 2026
@tsmbland tsmbland mentioned this pull request Aug 14, 2026
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

4 participants