Skip to content

Fix swapped annuity parameters in stochastic-optimization.ipynb example#1398

Merged
lkstrp merged 2 commits intomasterfrom
copilot/fix-annuity-lifetime-discount-rate
Oct 15, 2025
Merged

Fix swapped annuity parameters in stochastic-optimization.ipynb example#1398
lkstrp merged 2 commits intomasterfrom
copilot/fix-annuity-lifetime-discount-rate

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 15, 2025

Description

This PR fixes a bug in the stochastic-optimization.ipynb example notebook where the parameters to the annuity() function were swapped, causing incorrect calculation of annualized capital costs.

The Issue

The annuity() function signature is:

def annuity(r: float, n: int) -> float:
    """
    Parameters
    ----------
    r : float
        Discount rate (as a decimal, e.g. 0.05 for 5%).
    n : int
        Lifetime of loan or asset (in years).
    """

However, the notebook was calling it with reversed parameters:

# INCORRECT (before this fix)
cfg["fixed_cost"] = (annuity(LIFE, DR) + FOM / 100) * cfg["inv"]

The Fix

Changed the parameter order to match the function signature:

# CORRECT (after this fix)
cfg["fixed_cost"] = (annuity(DR, LIFE) + FOM / 100) * cfg["inv"]

Impact

With the example values from the notebook (DR=0.03, LIFE=25):

  • Incorrect calculation: annuity(25, 0.03) = 268.48 (vastly overestimated!)
  • Correct calculation: annuity(0.03, 25) = 0.0574 (correct value)

The bug was causing a massive overestimation of annualized capital costs by over 300,000%.

Verification

All other notebooks in the repository correctly use annuity(discount_rate, lifetime), including:

  • capacity-expansion-planning-single-node.ipynb
  • myopic-pathway.ipynb
  • 3-node-cem.ipynb
  • example-3.ipynb

The test file test/conftest.py also uses the correct parameter order.

Fixes #issue_number

Original prompt

This section details on the original issue you should resolve

<issue_title>swap annuity lifetime and discount rate in docs example</issue_title>
<issue_description>### Version Checks (indicate both or one)

  • I have confirmed this bug exists on the lastest release of PyPSA.

  • I have confirmed this bug exists on the current master branch of PyPSA.

Issue Description

I noticed the docs stochastic-optimization.ipynb looks off... and found that the annuity function has its discount rate and lifetime switched in cell 3:

# Calculate annualized capital costs
for cfg in TECH.values():
    cfg["fixed_cost"] = (annuity(LIFE, DR) + FOM / 100) * cfg["inv"]

should be

# Calculate annualized capital costs
for cfg in TECH.values():
    cfg["fixed_cost"] = (annuity(DR, LIFE) + FOM / 100) * cfg["inv"]

Reproducible Example

import pypsa
from pypsa.common import annuity
 
life = 25
DR = 0.03

annuity(LIFE, DR) # returns large val >>200

Expected Behavior

annuity(DR, LIFE) # returns correct value.

Installed Versions

Details v1.0

Comments on the Issue (you are @copilot in this section)

Fixes #1397


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI changed the title [WIP] Fix swapped annuity lifetime and discount rate in docs example Fix swapped annuity parameters in stochastic-optimization.ipynb example Oct 15, 2025
Copilot AI requested a review from fneum October 15, 2025 05:24
@fneum fneum marked this pull request as ready for review October 15, 2025 08:07
@lkstrp lkstrp merged commit a818ac6 into master Oct 15, 2025
21 of 22 checks passed
@lkstrp lkstrp deleted the copilot/fix-annuity-lifetime-discount-rate branch October 15, 2025 08:10
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.

swap annuity lifetime and discount rate in docs example

3 participants