Skip to content

Add input for ElectricStorage SOC timeseries#486

Open
adfarth wants to merge 34 commits intodevelopfrom
fixed-bess-soc
Open

Add input for ElectricStorage SOC timeseries#486
adfarth wants to merge 34 commits intodevelopfrom
fixed-bess-soc

Conversation

@adfarth
Copy link
Copy Markdown
Collaborator

@adfarth adfarth commented Mar 10, 2025

Added

  • Add ElectricStorage inputs field fixed_soc_series_fraction and fixed_soc_series_fraction_tolerance to allow users to fix the SOC timeseries within a chosen absolute tolerance

Changed

  • ElectricStorage state_of_health to state_of_health_series_fraction

Cherry-picked from branch h2-tldrd-mpc by @lixiangk1 with a few small mods

@adfarth adfarth requested a review from lixiangk1 April 11, 2025 19:08
@adfarth adfarth marked this pull request as ready for review April 11, 2025 19:08
@lixiangk1
Copy link
Copy Markdown
Collaborator

I reviewed the changes and ran some tests and everything seems to make sense. I was wondering if you've noticed in your runs that the cases with the fixed SOC dispatch returns a slightly lower LCC compared to the fixed sizes but unconstrained dispatch? We'd expect it to be slightly higher if results are different right? Is that just a mathematical tolerance thing?

@adfarth
Copy link
Copy Markdown
Collaborator Author

adfarth commented Apr 21, 2026

I reviewed the changes and ran some tests and everything seems to make sense. I was wondering if you've noticed in your runs that the cases with the fixed SOC dispatch returns a slightly lower LCC compared to the fixed sizes but unconstrained dispatch? We'd expect it to be slightly higher if results are different right? Is that just a mathematical tolerance thing?

@lixiangk1 I've found that if I have a run1 with fixed PV and BESS sizes, then do a run2 where the SOC is fixed to run1 SOC with a 1-5% tolerance (and all else held equal):

  • the LCC is lower in run2 than run1 due to lower electricity costs (the % diff is a fraction of a %)
  • I think this is because the min_soc gets ignored in the second case, so the model can go below the default 20% min as long as it's in the tolerance range.
  • So, I think this is okay and makes sense

@adfarth adfarth requested a review from lixiangk1 April 21, 2026 22:07
Comment thread src/mpc/model.jl

for t in p.s.storage.types.elec
fix(m[:dvGridToStorage][t, ts], 0.0, force=true)
for b in p.s.storage.types.elec
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changing for consistency in how we index storage

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for fixing ElectricStorage state-of-charge (SOC) as a time series (with tolerance), and updates degradation-related naming for battery results.

Changes:

  • Add fixed_soc_series_fraction and fixed_soc_series_fraction_tolerance inputs for ElectricStorage, plus corresponding dispatch constraints to enforce a fixed SOC trajectory within tolerance.
  • Rename ElectricStorage degradation output state_of_health to state_of_health_series_fraction.
  • Add a new scenario + test coverage for fixed SOC behavior.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/scenarios/fixed_pv_bess.json Adds a simple PV+BESS scenario used by the new fixed-SOC test.
test/runtests.jl Adds a HiGHS testset validating fixed SOC behavior.
src/constraints/storage_constraints.jl Implements fixed SOC constraints (and refactors a power-capacity constraint).
src/core/energy_storage/electric_storage.jl Adds ElectricStorage inputs for fixed SOC series and tolerance; adjusts SOC-related defaults when fixed series is provided.
src/core/utils.jl Extends JSON/Dict key conversion list to include fixed_soc_series_fraction (and degradation segment arrays).
src/results/electric_storage.jl Renames degradation output key to state_of_health_series_fraction.
src/results/thermal_storage.jl Clarifies docstrings to describe outputs as “average year.”
src/results/electric_utility.jl Fixes formatting/indentation around storage-dependent results.
src/mpc/structs.jl Adds fixed SOC series/tolerance fields to MPC electric storage structs.
src/mpc/model.jl Minor variable naming fix in a storage loop.
src/core/reopt.jl Minor loop variable rename and updates a degradation-related log message.
src/core/electric_tariff.jl Docstring tweak (adds unit detail for wholesale export rate).
src/core/scenario.jl Minor docstring list adjustment in Scenario docs.
CHANGELOG.md Records the new inputs and the degradation output rename.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/constraints/storage_constraints.jl
Comment thread src/constraints/storage_constraints.jl
Comment on lines +131 to +139
# Constraint (4l): Constrain to fixed_soc_series_fraction
if hasproperty(p.s.storage.attr[b], :fixed_soc_series_fraction) && !isnothing(p.s.storage.attr[b].fixed_soc_series_fraction)
# Allow for a percentage point (fractional) buffer on user-provided fixed_soc_series_fraction
@constraint(m, [ts in p.time_steps],
m[Symbol("dvStoredEnergy"*_n)][b, ts] <= (p.s.storage.attr[b].fixed_soc_series_fraction_tolerance + p.s.storage.attr[b].fixed_soc_series_fraction[ts]) * m[Symbol("dvStorageEnergy"*_n)][b]
)
@constraint(m, [ts in p.time_steps],
m[Symbol("dvStoredEnergy"*_n)][b, ts] >= (-p.s.storage.attr[b].fixed_soc_series_fraction_tolerance + p.s.storage.attr[b].fixed_soc_series_fraction[ts]) * m[Symbol("dvStorageEnergy"*_n)][b]
)
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The fixed-SOC constraints only apply for ts in p.time_steps and do not constrain dvStoredEnergy[b, 0]. In MPC (and any case where soc_init_fraction isn’t auto-aligned to the fixed series), this can allow an inconsistent initial SOC or force a large first-step correction that may make the problem infeasible. Consider also constraining dvStoredEnergy[b, 0] to match the first fixed SOC value (within tolerance), or aligning soc_init_fraction automatically whenever a fixed series is provided.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

soc_init_fraction is set equal to fixed_soc_series_fraction[1] in electric_storage.jl. @lixiangk1 does this approach work for MPC?

Comment thread src/core/energy_storage/electric_storage.jl Outdated
Comment thread src/core/electric_tariff.jl
Comment thread test/runtests.jl Outdated
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.

4 participants