Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Myopic fix #217

Merged
merged 19 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions data/override_component_attrs/generators.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
attribute,type,unit,default,description,status
build_year,integer,year,n/a,build year,Input (optional)
lifetime,float,years,n/a,lifetime,Input (optional)
carrier,string,n/a,n/a,carrier,Input (optional)
lifetime,float,years,inf,lifetime,Input (optional)
build_year,int,year ,0,build year,Input (optional)
16 changes: 8 additions & 8 deletions data/override_component_attrs/links.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ attribute,type,unit,default,description,status
bus2,string,n/a,n/a,2nd bus,Input (optional)
bus3,string,n/a,n/a,3rd bus,Input (optional)
bus4,string,n/a,n/a,4th bus,Input (optional)
efficiency2,static or series,per unit,1.,2nd bus efficiency,Input (optional)
efficiency3,static or series,per unit,1.,3rd bus efficiency,Input (optional)
efficiency4,static or series,per unit,1.,4th bus efficiency,Input (optional)
p2,series,MW,0.,2nd bus output,Output
p3,series,MW,0.,3rd bus output,Output
p4,series,MW,0.,4th bus output,Output
build_year,integer,year,n/a,build year,Input (optional)
lifetime,float,years,n/a,lifetime,Input (optional)
efficiency2,static or series,per unit,1,2nd bus efficiency,Input (optional)
efficiency3,static or series,per unit,1,3rd bus efficiency,Input (optional)
efficiency4,static or series,per unit,1,4th bus efficiency,Input (optional)
p2,series,MW,0,2nd bus output,Output
p3,series,MW,0,3rd bus output,Output
p4,series,MW,0,4th bus output,Output
carrier,string,n/a,n/a,carrier,Input (optional)
lifetime,float,years,inf,lifetime,Input (optional)
build_year,int,year ,0,build year,Input (optional)
4 changes: 2 additions & 2 deletions data/override_component_attrs/stores.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
attribute,type,unit,default,description,status
build_year,integer,year,n/a,build year,Input (optional)
lifetime,float,years,n/a,lifetime,Input (optional)
carrier,string,n/a,n/a,carrier,Input (optional)
lifetime,float,years,inf,lifetime,Input (optional)
build_year,int,year ,0,build year,Input (optional)
47 changes: 41 additions & 6 deletions scripts/add_brownfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@

import pypsa
import yaml
import numpy as np

from add_existing_baseyear import add_build_year_to_new_assets
from helper import override_component_attrs
from solve_network import basename


def add_brownfield(n, n_p, year):

print("adding brownfield")

# electric transmission grid set optimised capacities of previous as minimum
n.lines.s_nom_min = n_p.lines.s_nom_opt
dc_i = n.links[n.links.carrier=="DC"].index
n.links.loc[dc_i, "p_nom_min"] = n_p.links.loc[dc_i, "p_nom_opt"]

for c in n_p.iterate_components(["Link", "Generator", "Store"]):

attr = "e" if c.name == "Store" else "p"
Expand All @@ -25,7 +32,7 @@ def add_brownfield(n, n_p, year):
# CO2 or global EU values since these are already in n
n_p.mremove(
c.name,
c.df.index[c.df.lifetime.isna()]
c.df.index[c.df.lifetime==np.inf]
)

# remove assets whose build_year + lifetime < year
Expand All @@ -44,7 +51,7 @@ def add_brownfield(n, n_p, year):
)]

threshold = snakemake.config['existing_capacities']['threshold_capacity']

if not chp_heat.empty:
threshold_chp_heat = (threshold
* c.df.efficiency[chp_heat.str.replace("heat", "electric")].values
Expand All @@ -55,7 +62,7 @@ def add_brownfield(n, n_p, year):
c.name,
chp_heat[c.df.loc[chp_heat, attr + "_nom_opt"] < threshold_chp_heat]
)

n_p.mremove(
c.name,
c.df.index[c.df[attr + "_nom_extendable"] & ~c.df.index.isin(chp_heat) & (c.df[attr + "_nom_opt"] < threshold)]
Expand All @@ -75,16 +82,44 @@ def add_brownfield(n, n_p, year):
for tattr in n.component_attrs[c.name].index[selection]:
n.import_series_from_dataframe(c.pnl[tattr], c.name, tattr)


# deal with gas network
pipe_carrier = ['gas pipeline']
if snakemake.config["sector"]['H2_retrofit']:
# drop capacities of previous year to avoid duplicating
to_drop = n.links.carrier.isin(pipe_carrier) & (n.links.build_year!=year)
n.mremove("Link", n.links.loc[to_drop].index)

# subtract the already retrofitted from today's gas grid capacity
h2_retrofitted_fixed_i = n.links[(n.links.carrier=='H2 pipeline retrofitted') & (n.links.build_year!=year)].index
gas_pipes_i = n.links[n.links.carrier.isin(pipe_carrier)].index
CH4_per_H2 = 1 / snakemake.config["sector"]["H2_retrofit_capacity_per_CH4"]
fr = "H2 pipeline retrofitted"
to = "gas pipeline"
# today's pipe capacity
pipe_capacity = n.links.loc[gas_pipes_i, 'p_nom']
# already retrofitted capacity from gas -> H2
already_retrofitted = (n.links.loc[h2_retrofitted_fixed_i, 'p_nom']
.rename(lambda x: basename(x).replace(fr, to)).groupby(level=0).sum())
remaining_capacity = pipe_capacity - CH4_per_H2 * already_retrofitted.reindex(index=pipe_capacity.index).fillna(0)
n.links.loc[gas_pipes_i, "p_nom"] = remaining_capacity
else:
new_pipes = n.links.carrier.isin(pipe_carrier) & (n.links.build_year==year)
n.links.loc[new_pipes, "p_nom"] = 0.
n.links.loc[new_pipes, "p_nom_min"] = 0.



#%%
if __name__ == "__main__":
if 'snakemake' not in globals():
from helper import mock_snakemake
snakemake = mock_snakemake(
'add_brownfield',
simpl='',
clusters=48,
clusters="37",
opts="",
lv=1.0,
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1',
sector_opts='168H-T-H-B-I-solar+p3-dist1',
planning_horizons=2030,
)

Expand Down
42 changes: 27 additions & 15 deletions scripts/add_existing_baseyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import pypsa
import yaml

from prepare_sector_network import prepare_costs
from prepare_sector_network import prepare_costs, define_spatial
from helper import override_component_attrs

from types import SimpleNamespace
spatial = SimpleNamespace()

def add_build_year_to_new_assets(n, baseyear):
"""
Expand All @@ -28,7 +30,7 @@ def add_build_year_to_new_assets(n, baseyear):
# Give assets with lifetimes and no build year the build year baseyear
for c in n.iterate_components(["Link", "Generator", "Store"]):

assets = c.df.index[~c.df.lifetime.isna() & c.df.build_year==0]
assets = c.df.index[(c.df.lifetime!=np.inf) & (c.df.build_year==0)]
c.df.loc[assets, "build_year"] = baseyear

# add -baseyear to name
Expand Down Expand Up @@ -159,7 +161,7 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
inv_busmap = {}
for k, v in busmap.iteritems():
inv_busmap[v] = inv_busmap.get(v, []) + [k]

clustermaps = busmap_s.map(busmap)
clustermaps.index = clustermaps.index.astype(int)

Expand Down Expand Up @@ -197,10 +199,15 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
capacity = capacity[capacity > snakemake.config['existing_capacities']['threshold_capacity']]

if generator in ['solar', 'onwind', 'offwind']:

suffix = '-ac' if generator == 'offwind' else ''
name_suffix = f' {generator}{suffix}-{baseyear}'

# to consider electricity grid connection costs or a split between
# solar utility and rooftop as well, rather take cost assumptions
# from existing network than from the cost database
capital_cost = n.generators.loc[n.generators.carrier==generator+suffix, "capital_cost"].mean()

if 'm' in snakemake.wildcards.clusters:

for ind in capacity.index:
Expand All @@ -213,14 +220,14 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas

p_max_pu = n.generators_t.p_max_pu[[i + name_suffix for i in inv_ind]]
p_max_pu.columns=[i + name_suffix for i in inv_ind ]

n.madd("Generator",
[i + name_suffix for i in inv_ind],
bus=ind,
carrier=generator,
p_nom=capacity[ind] / len(inv_ind), # split among regions in a country
marginal_cost=costs.at[generator,'VOM'],
capital_cost=costs.at[generator,'fixed'],
capital_cost=capital_cost,
efficiency=costs.at[generator, 'efficiency'],
p_max_pu=p_max_pu,
build_year=grouping_year,
Expand All @@ -238,19 +245,22 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
carrier=generator,
p_nom=capacity,
marginal_cost=costs.at[generator, 'VOM'],
capital_cost=costs.at[generator, 'fixed'],
capital_cost=capital_cost,
efficiency=costs.at[generator, 'efficiency'],
p_max_pu=p_max_pu.rename(columns=n.generators.bus),
build_year=grouping_year,
lifetime=costs.at[generator, 'lifetime']
)

else:
bus0 = vars(spatial)[carrier[generator]].nodes
if "EU" not in vars(spatial)[carrier[generator]].locations:
bus0 = bus0.intersection(capacity.index + " gas")

n.madd("Link",
capacity.index,
suffix= " " + generator +"-" + str(grouping_year),
bus0="EU " + carrier[generator],
bus0=bus0,
bus1=capacity.index,
bus2="co2 atmosphere",
carrier=generator,
Expand Down Expand Up @@ -399,10 +409,11 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
lifetime=costs.at[costs_name, 'lifetime']
)


n.madd("Link",
nodes[name],
suffix= f" {name} gas boiler-{grouping_year}",
bus0="EU gas",
bus0=spatial.gas.nodes,
bus1=nodes[name] + " " + name + " heat",
bus2="co2 atmosphere",
carrier=name + " gas boiler",
Expand All @@ -417,7 +428,7 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
n.madd("Link",
nodes[name],
suffix=f" {name} oil boiler-{grouping_year}",
bus0="EU oil",
bus0=spatial.oil.nodes,
bus1=nodes[name] + " " + name + " heat",
bus2="co2 atmosphere",
carrier=name + " oil boiler",
Expand All @@ -436,17 +447,17 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
threshold = snakemake.config['existing_capacities']['threshold_capacity']
n.mremove("Link", [index for index in n.links.index.to_list() if str(grouping_year) in index and n.links.p_nom[index] < threshold])


#%%
if __name__ == "__main__":
if 'snakemake' not in globals():
from helper import mock_snakemake
snakemake = mock_snakemake(
'add_existing_baseyear',
simpl='',
clusters=45,
clusters="37",
lv=1.0,
opts='',
sector_opts='Co2L0-168H-T-H-B-I-solar+p3-dist1',
sector_opts='168H-T-H-B-I-solar+p3-dist1',
planning_horizons=2020,
)

Expand All @@ -459,7 +470,8 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years

overrides = override_component_attrs(snakemake.input.overrides)
n = pypsa.Network(snakemake.input.network, override_component_attrs=overrides)

# define spatial resolution of carriers
spatial = define_spatial(n.buses[n.buses.carrier=="AC"].index, options)
add_build_year_to_new_assets(n, baseyear)

Nyears = n.snapshot_weightings.generators.sum() / 8760.
Expand All @@ -471,7 +483,7 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
snakemake.config['costs']['lifetime']
)

grouping_years=snakemake.config['existing_capacities']['grouping_years']
grouping_years = snakemake.config['existing_capacities']['grouping_years']
add_power_capacities_installed_before_baseyear(n, grouping_years, costs, baseyear)

if "H" in opts:
Expand Down
Loading