Questions regarding transmission line expansion and objective_constant

235 views
Skip to first unread message

Marissa Moultak

unread,
Jun 15, 2020, 7:52:26 PM6/15/20
to pypsa
Hello, 

I am currently running PyPSA-Eur 0.2.0 (w/ PyPSA 0.17.0) for a selection of countries (NL, DE, BE, DK, NO, GB, FR) and have a couple of questions: 

1. I am having a bit of difficulties understanding the {ll} wildcard. When I run the with the {lcopt} wildcard with the n.lines.s_nom_extendable set to "True", and then try to get the transmission line expansion with: n.lines.s_nom_opt - n.lines.s_nom, I get 0 for all lines for multiple different network scenarios. This is occurring in situations that I would expect transmission line expansion (i.e. very low CO2 emissions limits). 

2. Along this same line of the question above, where is the data for the original line capacities is stored? I originally thought it was in PyPSA-Eur/pypsa-eur/data/entsoegridkit/lines.csv, but this does not seem to include line capacities of existing lines. Am I overlooking something?

3. Finally, when I try to get the capital cost of already existing infrastructure (objective_constant), I consistently get zero for several different networks and can not seem to understand why this is occurring.  

I attached the current config.yaml file I am running. 

My apologies for the simplistic questions, I have read the documentation extensively but can not seem to figure out why these outcomes are occurring. Any help is much appreciated. 

Thank you! 

Kind regards, 
Marissa  
config.yaml

Fabian Hofmann

unread,
Jun 16, 2020, 4:53:40 AM6/16/20
to py...@googlegroups.com

Hey Marissa,


1. You are right, this might seem counter-intuitive. The line expansion is solved in an iterative process where `s_nom` (capacity) and `x_pu` (impedance) are updated in each iteration. In case we were only updating the impedance (which carries the necessary information), we would end up with a wrong s_nom/x_pu ratio. This is why we are updating both. 


2. The information that you are looking for is in s_nom_min which is the 'starting point' of the transmission capacities. You also have the option to track the iteration by setting `track_iterations` to True in config.yaml -> solving -> options. This will store the s_nom of each iteration under n.lines.s_nom_opt_{#itertation}. The starting point is stored under n.lines.s_nom_opt_0 (which should be the same as n.lines.s_nom_min).


3. Good point. This also comes from the iterative process. Probably it would be helpful to  store `objective_constant` for each iteration if `track_iterations` is True (you can raise a pypsa issue on that if you want :) ). For now you can manually reconstruct the objective constant by summing over the nominal attribute for all components except for lines where you take the lower bound something like this


nom_attr = pypsa.descriptors.nominal_attrs.items()

constant = 0
for c, attr in nom_attr:
    ext_i = pypsa.descriptors.get_extendable_i(n, c)
    if c in n.passive_branch_components:
        attr += '_min'
    constant += n.df(c)[attr][ext_i] @ n.df(c).capital_cost[ext_i]

Hope that helped!

Best,

Fabian H

--
You received this message because you are subscribed to the Google Groups "pypsa" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pypsa+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/pypsa/e8726cd9-1f2b-4b38-9c5b-a1f2a2d19474o%40googlegroups.com.

Marissa Moultak

unread,
Jun 16, 2020, 8:47:44 PM6/16/20
to pypsa
Hi Fabian, 

Thank you very much for the very helpful response! It certainly makes a lot more sense now, but I am having some difficulties back calculating the total system costs (i.e. n.objective) when using the n.lines.s_nom_min to be the initial transmission capacities. In an effort to get total system costs per country, I first tried to manually calculate the total system costs to ensure I am calculating system costs correctly. When doing so, the total system costs I get deviates from n.objective by approximately the cost of transmission line expansion. I have tried manually calculating the total system costs a number of different ways - below is an example code of one of the calculations: 

nom_attr = pypsa.descriptors.nominal_attrs.items()
constant = []
for c, attr in nom_attr:
    if c in n.passive_branch_components:
         attr += '_min'
    constant_int = (n.df(c)[attr] @ n.df(c).capital_cost)
    constant.append(constant_int)

constant2 = []
for c, attr in nom_attr:
    attr += '_opt'
    constant_opt = (n.df(c)[attr] @ n.df(c).capital_cost)
    constant2.append(constant_opt)
Objective = 0 
Objective += (sum(constant2)-sum(constant))

Gen_opex = sum(n.generators_t.p.sum()*n.generators.marginal_cost)
Storage_opex = sum((n.storage_units_t.p_dispatch).sum()*n.storage_units.marginal_cost)
 
Objective += (Gen_opex + Storage_opex)
 
print("Total system cost:",(Objective)/1e9, "billion euros")
print("n.objective output:", n.objective/1e9, "billion euros")
print("Difference between self calculated objective & objective function output:", (Objective-n.objective)/1e9, "billion euros")
lines_costs=(n.lines.s_nom_opt*n.lines.capital_cost).sum()-(n.lines.s_nom_min*n.lines.capital_cost).sum()
print("Additional line costs:", lines_costs/1e9, "billion euros")
 
And the output is the following: 
 
Total system cost: 46.70154794014095 billion euros
n.objective output: 45.27161382643129 billion euros
Difference between self calculated objective & objective function output: 1.4299341137096557 billion euros
Additional line costs: 1.4299340498999469 billion euros

The difference between my manually calculated total system costs and the "n.objective" output is nearly but not exactly the cost of the additional installed transmission lines. I can't seem to make sense of this difference. Do you know what could be causing this difference? 

Thank you! 

Best, 
Marissa 

Fabian Hofmann

unread,
Jun 17, 2020, 4:02:34 AM6/17/20
to py...@googlegroups.com

Hey Marissa,


you're welcome :) The difference you mention is not due to a wrong calculation but rather to an 'inaccuracy' of the solver. It's of order 10^-6 which is the default solver tolerance, see config.yaml -> solver -> FeasibilityTol & BarConvTol. If you want higher accuracy you should tweak these tolerances (not sure which one of those exactly), or switch to crossover > 0 (which takes a long time however to solve).


Best,

Fabian

--
You received this message because you are subscribed to the Google Groups "pypsa" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pypsa+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages