Inquiry about capex() and opex() in pypsa.statistics

441 views
Skip to first unread message

Matthew Dumlao

unread,
Aug 28, 2023, 4:10:57 AM8/28/23
to pypsa
Dear All, 

For those who have used the `capex()` and `opex()` functions in the `pypsa.statistics`, I was wondering why their sum is not the same as the `Optimal objective`?

I tried to recreate these functions and as far as I can understand, the capex is the product of the capacity and capital cost while the opex is the product of the marginal production and marginal cost for the snapshot of the simulation (in my case, 1 year). 

In the four scenarios that I am currently testing, the `Optimal objective` is lower by 5-10%.

I suppose that the lifetime of the components has something to do with the difference? Any leads would be helpful.

Thank you very much!

Matthew

Fabian Neumann

unread,
Aug 29, 2023, 9:39:24 AM8/29/23
to pypsa
Hi Matthew,

The trusted calculation is

n.statistics.capex() + n.statistics.opex(aggregate_time="sum")

The n.objective is the raw solver output, and constant terms of already existing infrastructure (e.g. with p_nom_min) are subtracted in this case.

Best wishes,

Fabian

Matthew Dumlao

unread,
Aug 30, 2023, 12:02:13 AM8/30/23
to Fabian Neumann, pypsa
Dear Fabian,

Thank you for your reply.

Q1: I would like to clarify further about this statement:

The n.objective is the raw solver output, and constant terms of already existing infrastructure (e.g. with p_nom_min) are subtracted in this case.

Is there a way to get the same value for `n.objective` and `(n.statistics.capex() + n.statistics.opex()).sum()`. I wanted to understand what the optimization sees as constant terms. I tried to make `p_nom_min` as 0 for all components but there is still a difference between the two outputs.


Q2: While I was trying to find the answer to my initial question, I tried to search for "capital_cost" and stumbled upon the following in the documentation under Optimising investment and operation over multiple investment periods:
In general, there are two different methods of pathway optimisation with perfect foresight. These differ in the way of accounting the investment costs:
- In the first case (type I), the complete overnight investment costs are applied.
- In the second case (type II), the investment costs are annualised over the years, in which an asset is active (depending on the build year and lifetime).

Method II is used in PyPSA since it allows a separation of the discounting over different years and the end-of-horizon effects are smaller compared to method I. For a more detailed comparison of the two methods and a reference to other energy system models see https://nworbmot.org/energy/multihorizon.pdf.

Be aware, that the attribute capital_cost represents the annualised investment costs NOT the overnight investment costs for the multi-investment.
...
...
Note that the `capital_cost` of the assets is now the fixed annual costs, including annuity and FOM.

I would like to clarify that for non-multi-year investment, `capital_cost` is used as overnight investment costs? In this case, the optimizer assumes that the infrastructures are built at the start of the snapshots. Therefore, it will not consider the lifetime of the project (assuming I am only doing annual simulation) and there is no way to include interest rates.

I think the answer is yes, but I just wanted to clarify. In case we want to calculate the annual cost, then we should follow the documentation on Optimising total annual system costs where the capital_cost is treated as the capital_cost per year (annualised). 


Thank you very much!

Matthew
--
You received this message because you are subscribed to a topic in the Google Groups "pypsa" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pypsa/k45-oXGqWGQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pypsa+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/pypsa/63320180-4c01-40f7-88ef-d62cc383a454n%40googlegroups.com.

Matthew Dumlao

unread,
Aug 30, 2023, 3:59:05 AM8/30/23
to Fabian Neumann, pypsa
Dear Fabian,

I tried to dig deeper. Thank you for pointing out "constant". I noticed that there is also a `n.objective_constant`. The answer to my initial question was discussed in PyPSA 0.17.0 (23rd March 2020)
After optimizing, the network has now an additional attribute `objective_constant` which reflects the capital cost of already existing infrastructure in the network referring to `p_nom` and `s_nom` values.

It could be replicated with this code (based on n.statistics):
from pypsa.descriptors import nominal_attrs

def objective_constant(n):
    components = n.branch_components | n.one_port_components
    values = []
    for c in components:
        try:
            values.append(n.df(c).eval(f"{nominal_attrs[c]} * capital_cost"))
        except (KeyError, AttributeError):
            pass
    return pd.concat(values)


print(nominal_attrs)
{'Generator': 'p_nom', 'Line': 's_nom', 'Transformer': 's_nom', 'Link': 'p_nom', 'Store': 'e_nom', 'StorageUnit': 'p_nom'}

In my case, the objective_constant was from n.store.e_nom. 

I think this also clarifies my second question but if you have the time, I would like to know your thoughts about the treatment of the capital_cost variable too.

Thank you very much!

Matthew


Sophie Pelland

unread,
Apr 12, 2024, 3:03:32 PM4/12/24
to pypsa
Hello,

In running statistics.capex() for a network with multi-investment periods, it returns a cumulative sum over the different periods. However, the costs of expandable assets get dropped for periods when they are no longer in operation. Is there a way to recover either the cumulative sum of all capex (including for expandable assets that are no longer active), or to get the capex for assets built only in each period?

Best regards,
Sophie

Fabian Neumann

unread,
Apr 20, 2024, 3:30:15 AM4/20/24
to pypsa
Hi Sophie,

If you need a custom solution, that n.statistics() does not provide, you can revert to calculating investment and operating costs component-wise, e.g.:

(n.generators.capital_cost * n.generators.p_nom_opt).sum()

and use some pandas grouper/filter here while iterating over different components.

Best wishes,

Fabian
Reply all
Reply to author
Forward
0 new messages