Skip to content

scenario_loader: entsoe: new scenario loader for European Countries#813

Open
maurerle wants to merge 4 commits into
mainfrom
entsoe
Open

scenario_loader: entsoe: new scenario loader for European Countries#813
maurerle wants to merge 4 commits into
mainfrom
entsoe

Conversation

@maurerle

@maurerle maurerle commented Jun 2, 2026

Copy link
Copy Markdown
Member

Description

Adds an ENTSO-E Transparency Platform scenario loader to build country-level ASSUME scenarios from API data (no CSV plant lists).
Thanks to @mthede who inspired this as a simpler version which does not rely on data from OEDS

This is using a similar approach as AMIRIS to use minimum and maximum prices and splits the generation capacity into useful unit sizes with linear interpolated prices.

New code

  • assume/scenario/loader_entsoe.pyload_entsoe() and dev __main__
  • assume/scenario/entsoe_helper/ — ENTSO-E client (cached under ~/.assume/entsoe/), instrat.pl fuel/CO₂ prices, PSR → technology mappings
  • tests/test_loader_entsoe.py (18 tests)
  • Docs in docs/source/scenario_loader.rst, assume.scenario.rst
  • Agent handoff: docs/dev/entsoe_loader_handoff.md

Behaviour

  • Demand, generation, and installed capacity from ENTSO-E; fleet split into MW blocks with merit-order fuel spreads
  • Wind/solar: max_power = installed capacity, hourly availability = generation / capacity
  • Other plants: full block capacity, availability = 1
  • Shared CO₂ series for all fossils (instrat ETS or 70 €/tCO₂ fallback)
  • Storage units aligned with example_03 (8 h energy, 0.5 initial SOC, flexABLE storage strategy)
  • Fuel price sanitization (bad coal cache → fallback) so NaN bids do not break pay-as-clear merit order

Dependency: optional extra assume-framework[entsoe] (entsoe-py, yfinance). Requires ENTSOE_API_KEY.

Checklist

  • Documentation updated (docstrings, READMEs, user guides, inline comments, doc folder updates etc.)
  • New unit/integration tests added (if applicable)
  • Changes noted in release notes (if any)
  • Consent to release this PR's code under the GNU Affero General Public License v3.0

Screenshot

  • Verified 2024 DE run (entsoe_DE_2024)
image

maurerle added 3 commits June 2, 2026 08:40
Introduces an API-driven loader with ENTSO-E client, fuel price fetching,
technology mappings, and tests so DE/EU scenarios can be built without CSV inputs.

Assisted-by: Cursor:composer-2.5
Replace the incorrect fuel spread fallback with instrat CO2 data or 70 €/tCO2 so oil and other fossils share the same carbon cost input.

Assisted-by: Cursor:composer-2.5
…via availability.

Wind and solar bid full nameplate capacity from capacity.csv with hourly gen/cap
availability; all other technologies use full block capacity and availability 1.

Assisted-by: Cursor:composer-2.5

@reinecfi reinecfi 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.

I really like the idea of this addition. For me the changes look fine in general. Only documentation in general and especially for the the amount of hardcoded values / defaults could be improved for better understanding.

return hourly


class InstratFuelPrices:

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.

This maybe overkill for now: I feel like InstratFuelPrices has some similarities to EntsoeInterface. I wonder if we want to have a standardised way / Interface / common base class to incorporate new data from outside of ASSUME via API or downloads

"waste": (22.0, 18.0),
"nuclear": (9.0, 7.0),
}

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.

There is a lot of default values here that I don't really understand. As a user I would be interested if there is some reasoning behind them.

f"demand_{country}",
{
"min_power": 0,
"max_power": -demand.max(),

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.

In this line we seem sure about the sign of the demand.
Below in line 142 it seems like we are not sure about the sign of the demand (otherwise we would not need abs)
DemandForecaster(index, demand=-abs(demand))

Should we add abs() to the max_power as well?

"max_power_charge": -abs(block_capacity),
"max_power_discharge": block_capacity,
"capacity": block_capacity * DEFAULT_STORAGE_HOURS,
"max_soc": 1.0,

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.

A lot of hardcoded values that are either specified directly (like max_soc) or are imported from somewhere else (like additional_cost_charge). Maybe bundle them at one place or make them configurable?

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