Skip to content

43 new variable statistics final energy by carrierelectricity#47

Merged
maxnutz merged 9 commits into
mainfrom
43-new-variable-statistics-final-energy-by-carrierelectricity
Apr 25, 2026
Merged

43 new variable statistics final energy by carrierelectricity#47
maxnutz merged 9 commits into
mainfrom
43-new-variable-statistics-final-energy-by-carrierelectricity

Conversation

@maxnutz
Copy link
Copy Markdown
Owner

@maxnutz maxnutz commented Apr 21, 2026

Completely refactors existing Statistics Function for Variable Final Energy [by Carrier]|Electricity implementing pypsa-de logic

Remaining To Dos:

Note

Implementation of tests depends on PR #20 for MockNetwork

  • make sure, that the newest version of main is merged into your feature Branch
  • Add a testing routine for your Function to tests/ - stick to the testing-README

Test-run with existing network file

variable PyPSA-output IAMC Energy Balance 🟢 🟡 🟠 🔴
Final Energy [by Sector]|Electricity 208038 224896 🟡 in range

summary of variables

Summary by Sourcery

Refactor electricity final energy statistics to align with pypsa-de sectoral logic and add targeted tests for withdrawal queries and result composition.

Bug Fixes:

  • Exclude non-residential/commercial low-voltage carriers from residential/commercial electricity final energy aggregation.
  • Include DAC electricity demand explicitly in final electricity carrier statistics.

Enhancements:

  • Reimplement Final_Energy_by_Carrier__Electricity to build sectoral electricity final energy from dedicated withdrawal queries for agriculture, residential/commercial, transport, industry, and DAC.
  • Document the sectoral composition and inclusion/exclusion rules for electricity final energy statistics.

Tests:

  • Introduce minimal mock electricity statistics accessor and network to validate filtering of low-voltage carriers, ordering and concatenation of sectoral contributions, handling of empty series, and exact withdrawal query parameters for Final_Energy_by_Carrier__Electricity.

@maxnutz maxnutz linked an issue Apr 21, 2026 that may be closed by this pull request
7 tasks
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Apr 21, 2026

Reviewer's Guide

Refactors the Final_Energy_by_Carrier__Electricity statistics function to use sector-specific withdrawal queries aligned with pypsa-de logic, and adds focused tests using a minimal mock statistics accessor to validate filtering, ordering, and query patterns.

Sequence diagram for refactored Final_Energy_by_Carrier__Electricity statistics function

sequenceDiagram
    participant Caller
    participant FinalEnergyByCarrierElectricity
    participant Network_n
    participant StatisticsAccessor as n_statistics

    Caller->>FinalEnergyByCarrierElectricity: call(n, aggregate_per_year)

    activate FinalEnergyByCarrierElectricity

    Note over FinalEnergyByCarrierElectricity: Final Energy|Agriculture|Electricity
    FinalEnergyByCarrierElectricity->>Network_n: get statistics
    Network_n-->>FinalEnergyByCarrierElectricity: n.statistics
    FinalEnergyByCarrierElectricity->>n_statistics: withdrawal(carrier=[agriculture electricity, agriculture machinery electric], components=Load, aggregate_time=aggregate_per_year, kwargs)
    n_statistics-->>FinalEnergyByCarrierElectricity: agri Series

    Note over FinalEnergyByCarrierElectricity: Final Energy|Residential and Commercial|Electricity
    FinalEnergyByCarrierElectricity->>n_statistics: withdrawal(bus_carrier=low voltage, aggregate_time=aggregate_per_year, kwargs_filtering)
    n_statistics-->>FinalEnergyByCarrierElectricity: lv Series
    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: build forbitten_list from lv carrier index using regex patterns
    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: rescom = lv excluding forbitten carriers
    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: rescom = rescom.groupby(groupby).sum()

    Note over FinalEnergyByCarrierElectricity: Final Energy|Transportation|Electricity
    FinalEnergyByCarrierElectricity->>n_statistics: withdrawal(bus_carrier=low voltage, carrier=BEV charger, components=Link, aggregate_time=aggregate_per_year, kwargs)
    n_statistics-->>FinalEnergyByCarrierElectricity: transpo Series

    Note over FinalEnergyByCarrierElectricity: Final Energy|Industry|Electricity
    FinalEnergyByCarrierElectricity->>n_statistics: withdrawal(carrier=industry electricity, components=Load, aggregate_time=aggregate_per_year, kwargs)
    n_statistics-->>FinalEnergyByCarrierElectricity: industry Series

    Note over FinalEnergyByCarrierElectricity: DAC electricity demand
    FinalEnergyByCarrierElectricity->>n_statistics: withdrawal(bus_carrier=AC, carrier=DAC, components=Link, aggregate_time=aggregate_per_year, kwargs)
    n_statistics-->>FinalEnergyByCarrierElectricity: dac Series

    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: series_list = [agri, rescom, transpo, industry, dac]
    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: filter out empty series from series_list
    FinalEnergyByCarrierElectricity->>FinalEnergyByCarrierElectricity: result = concat(series_list)

    FinalEnergyByCarrierElectricity-->>Caller: return result Series/DataFrame
    deactivate FinalEnergyByCarrierElectricity
Loading

File-Level Changes

Change Details Files
Refactor electricity final energy aggregation to sector-specific withdrawals with carrier-based low-voltage filtering and DAC handling.
  • Replace generic AC energy_balance aggregation plus battery correction with explicit withdrawal calls per sector (agriculture, residential/commercial, transport, industry, DAC).
  • Introduce low-voltage load filtering by excluding carriers matching central heating, industry, agriculture, charger, and distribution patterns before aggregating residential/commercial demand.
  • Concatenate sectoral contribution Series (agriculture, res/com, transport, industry, DAC), dropping empty Series before concatenation, and return the combined result without further grouping.
pypsa_validation_processing/statistics_functions.py
Add targeted tests for Final_Energy_by_Carrier__Electricity using a minimal custom statistics accessor and network wrapper.
  • Implement _ElectricityStatisticsAccessor with a withdrawal stub that records call parameters and returns controlled Series for different carrier/bus/component combinations, including optional empty DAC data.
  • Implement _ElectricityNetwork wrapper exposing the custom statistics accessor for isolated testing of electricity statistics behavior.
  • Add tests that verify forbidden low-voltage carrier filtering, ordering and inclusion of non-empty sector contributions, dropping of empty contributions (DAC), and that expected withdrawal queries (bus_carrier/carrier/components combinations) are issued in the correct count and configuration.
tests/test_statistics_functions.py

Assessment against linked issues

Issue Objective Addressed Explanation
#43 Implement a statistics function Final_Energy_by_Carrier__Electricity that extracts final electricity energy by carrier from a PyPSA network (following project conventions) and provide a comprehensive docstring.
#43 Register/map the variable `Final Energy [by Carrier] Electricityto its statistics function in the configuration mapping file (e.g.config.default.yaml`).
#43 Add automated tests under tests/ for the Final_Energy_by_Carrier__Electricity function, following the testing guidelines.

Possibly linked issues

  • #: PR implements and refines the Final Energy [by Carrier]|Electricity statistics function plus tests requested in the issue

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@maxnutz
Copy link
Copy Markdown
Owner Author

maxnutz commented Apr 23, 2026

@sourcery-ai review

sourcery-ai[bot]

This comment was marked as outdated.

@maxnutz maxnutz marked this pull request as ready for review April 23, 2026 14:00
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The new implementation relies on kwargs and kwargs_filtering in Final_Energy_by_Carrier__Electricity, but these are neither defined nor passed into the function, which will currently raise a NameError and should be replaced with explicit parameters or constructed locally from the function arguments.
  • The residential/commercial low-voltage filtering builds forbitten_list via nested loops and substring checks on lv.index.get_level_values('carrier'); this can be simplified and made more robust with vectorized string matching (e.g. using Series.str.contains with a combined pattern and a boolean mask) instead of accumulating a Python list.
  • In rescom = rescom.groupby(kwargs['groupby']).sum(), the code assumes a 'groupby' key in kwargs, which may not exist; consider deriving the grouping directly from the index or from explicit parameters to avoid key errors and make the grouping behavior clearer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new implementation relies on `kwargs` and `kwargs_filtering` in `Final_Energy_by_Carrier__Electricity`, but these are neither defined nor passed into the function, which will currently raise a `NameError` and should be replaced with explicit parameters or constructed locally from the function arguments.
- The residential/commercial low-voltage filtering builds `forbitten_list` via nested loops and substring checks on `lv.index.get_level_values('carrier')`; this can be simplified and made more robust with vectorized string matching (e.g. using `Series.str.contains` with a combined pattern and a boolean mask) instead of accumulating a Python list.
- In `rescom = rescom.groupby(kwargs['groupby']).sum()`, the code assumes a `'groupby'` key in `kwargs`, which may not exist; consider deriving the grouping directly from the index or from explicit parameters to avoid key errors and make the grouping behavior clearer.

## Individual Comments

### Comment 1
<location path="pypsa_validation_processing/statistics_functions.py" line_range="129-132" />
<code_context>
+        **kwargs,
+    )
+
+    series_list = [agri, rescom, transpo, industry, dac]
+    series_list = [series for series in series_list if not series.empty]
+
+    result = pd.concat(
+        series_list
+    )  # reduce(lambda a, b: a.add(b, fill_value=0), series_list)
</code_context>
<issue_to_address>
**issue:** Concatenating an empty `series_list` will raise a `ValueError` and may need explicit handling.

If this “all components empty” case is possible (e.g. networks with no demand in these categories), handle it explicitly by either returning an empty Series/DataFrame with the expected index/columns, or short‑circuiting before `pd.concat` so the API remains consistent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread pypsa_validation_processing/statistics_functions.py Outdated
Copy link
Copy Markdown
Collaborator

@pworschischek-aggmag pworschischek-aggmag left a comment

Choose a reason for hiding this comment

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

Looks good, just some questions from my side:

  • can we really negelct heat?

Also, it might be time to think about caching. the evals module uses a cache here: https://github.com/AGGM-AG/pypsa-at/blob/af8f49ea2be27e2c8c5cf34df1babb6008b91bfe/evals/views/demand.py#L297

for the expensive very fed calculations (conversion of useful energy as heat into final energy by carrier, e.g. electricity)

BEV charging) industry electricity loads, and DAC electricity demand
change in home battery is of magnitude 1e-9 compared to electricity demand.
Concerning heat: rural air heat pump, rural ground heat pump, rural resisive
heater and urban decentral heatings are included. Central heatings using
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

central heat electricity demands my be relevant. Whats the reason for the exclusion?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I did not see the carrier of central heat as element of "Final Energy" and therefore excluded it, as the respective Final Energy would be heat

pd.concat([res, res_storage.mul(-1)], axis=0)
.groupby(["location", "unit"])
.sum()
forbitten_parts = [
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

typo in varname: forbidden

agriculture electricity loads, residential/commercial low-voltage loads
(excluding dedicated industry/agriculture/charger/distribution categories,
BEV charging) industry electricity loads, and DAC electricity demand
change in home battery is of magnitude 1e-9 compared to electricity demand.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does this mean home battery charge cycle losses are neglected?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Yes!

@maxnutz maxnutz merged commit bd5f398 into main Apr 25, 2026
2 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.

New Variable Statistics: Final Energy [by Carrier]|Electricity

2 participants