Small fixes (#167)

* update mocksnakemake for testing

* remove trailing whitespace in n.loads index

* add missing color for H2 liquification

* adjust to default lifetime 0 instead of NaN
This commit is contained in:
lisazeyen 2021-09-27 11:16:12 +02:00 committed by GitHub
parent 71be53af4f
commit 28264aa114
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 43 deletions

View File

@ -72,7 +72,7 @@ electricity:
# regulate what components with which carriers are kept from PyPSA-Eur; # regulate what components with which carriers are kept from PyPSA-Eur;
# some technologies are removed because they are implemented differently # some technologies are removed because they are implemented differently
# (e.g. battery or H2 storage) or have different year-dependent costs # (e.g. battery or H2 storage) or have different year-dependent costs
# in PyPSA-Eur-Sec # in PyPSA-Eur-Sec
pypsa_eur: pypsa_eur:
Bus: Bus:
@ -335,7 +335,7 @@ solving:
plotting: plotting:
map: map:
boundaries: [-11, 30, 34, 71] boundaries: [-11, 30, 34, 71]
color_geomap: color_geomap:
ocean: white ocean: white
land: whitesmoke land: whitesmoke
@ -420,6 +420,7 @@ plotting:
lines: k lines: k
transmission lines: k transmission lines: k
H2: m H2: m
H2 liquefaction: m
hydrogen storage: m hydrogen storage: m
battery: slategray battery: slategray
battery storage: slategray battery storage: slategray

View File

@ -28,7 +28,7 @@ def add_build_year_to_new_assets(n, baseyear):
# Give assets with lifetimes and no build year the build year baseyear # Give assets with lifetimes and no build year the build year baseyear
for c in n.iterate_components(["Link", "Generator", "Store"]): for c in n.iterate_components(["Link", "Generator", "Store"]):
assets = c.df.index[~c.df.lifetime.isna() & c.df.build_year.isna()] assets = c.df.index[~c.df.lifetime.isna() & c.df.build_year==0]
c.df.loc[assets, "build_year"] = baseyear c.df.loc[assets, "build_year"] = baseyear
# add -baseyear to name # add -baseyear to name
@ -60,7 +60,7 @@ def add_existing_renewables(df_agg):
} }
for tech in ['solar', 'onwind', 'offwind']: for tech in ['solar', 'onwind', 'offwind']:
carrier = carriers[tech] carrier = carriers[tech]
df = pd.read_csv(snakemake.input[f"existing_{tech}"], index_col=0).fillna(0.) df = pd.read_csv(snakemake.input[f"existing_{tech}"], index_col=0).fillna(0.)
@ -112,9 +112,9 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
Parameters Parameters
---------- ----------
n : pypsa.Network n : pypsa.Network
grouping_years : grouping_years :
intervals to group existing capacities intervals to group existing capacities
costs : costs :
to read lifetime to estimate YearDecomissioning to read lifetime to estimate YearDecomissioning
baseyear : int baseyear : int
""" """
@ -209,7 +209,7 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
build_year=grouping_year, build_year=grouping_year,
lifetime=costs.at[generator, 'lifetime'] lifetime=costs.at[generator, 'lifetime']
) )
else: else:
n.madd("Link", n.madd("Link",
@ -268,7 +268,7 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
df.fillna(0., inplace=True) df.fillna(0., inplace=True)
# convert GW to MW # convert GW to MW
df *= 1e3 df *= 1e3
cc = pd.read_csv(snakemake.input.country_codes, index_col=0) cc = pd.read_csv(snakemake.input.country_codes, index_col=0)
@ -327,7 +327,7 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
efficiency = cop[heat_pump_type][nodes[name]] efficiency = cop[heat_pump_type][nodes[name]]
else: else:
efficiency = costs.at[costs_name, 'efficiency'] efficiency = costs.at[costs_name, 'efficiency']
for i, grouping_year in enumerate(grouping_years): for i, grouping_year in enumerate(grouping_years):
if int(grouping_year) + default_lifetime <= int(baseyear): if int(grouping_year) + default_lifetime <= int(baseyear):
@ -378,7 +378,7 @@ def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years
build_year=int(grouping_year), build_year=int(grouping_year),
lifetime=costs.at[name_type + ' gas boiler', 'lifetime'] lifetime=costs.at[name_type + ' gas boiler', 'lifetime']
) )
n.madd("Link", n.madd("Link",
nodes[name], nodes[name],
suffix=f" {name} oil boiler-{grouping_year}", suffix=f" {name} oil boiler-{grouping_year}",
@ -410,7 +410,8 @@ if __name__ == "__main__":
simpl='', simpl='',
clusters=45, clusters=45,
lv=1.0, lv=1.0,
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', opts='',
sector_opts='Co2L0-168H-T-H-B-I-solar+p3-dist1',
planning_horizons=2020, planning_horizons=2020,
) )

View File

@ -289,7 +289,7 @@ def plot_h2_map(network):
title='Electrolyzer capacity', title='Electrolyzer capacity',
handler_map=make_handler_map_to_scale_circles_as_in(ax) handler_map=make_handler_map_to_scale_circles_as_in(ax)
) )
ax.add_artist(l2) ax.add_artist(l2)
handles = [] handles = []
@ -523,10 +523,11 @@ if __name__ == "__main__":
snakemake = mock_snakemake( snakemake = mock_snakemake(
'plot_network', 'plot_network',
simpl='', simpl='',
clusters=48, clusters=45,
lv=1.0, lv=1.5,
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', opts='',
planning_horizons=2050, sector_opts='Co2L0-168H-T-H-B-I-solar+p3-dist1',
planning_horizons=2030,
) )
overrides = override_component_attrs(snakemake.input.overrides) overrides = override_component_attrs(snakemake.input.overrides)

View File

@ -75,7 +75,7 @@ def co2_emissions_year(countries, opts, year):
co2_emissions = co2_totals.loc[countries, sectors].sum().sum() co2_emissions = co2_totals.loc[countries, sectors].sum().sum()
# convert MtCO2 to GtCO2 # convert MtCO2 to GtCO2
co2_emissions *= 0.001 co2_emissions *= 0.001
return co2_emissions return co2_emissions
@ -102,14 +102,14 @@ def build_carbon_budget(o, fn):
#emissions at the beginning of the path (last year available 2018) #emissions at the beginning of the path (last year available 2018)
e_0 = co2_emissions_year(countries, opts, year=2018) e_0 = co2_emissions_year(countries, opts, year=2018)
planning_horizons = snakemake.config['scenario']['planning_horizons'] planning_horizons = snakemake.config['scenario']['planning_horizons']
t_0 = planning_horizons[0] t_0 = planning_horizons[0]
if "be" in o: if "be" in o:
# final year in the path # final year in the path
t_f = t_0 + (2 * carbon_budget / e_0).round(0) t_f = t_0 + (2 * carbon_budget / e_0).round(0)
def beta_decay(t): def beta_decay(t):
cdf_term = (t - t_0) / (t_f - t_0) cdf_term = (t - t_0) / (t_f - t_0)
@ -270,6 +270,9 @@ def patch_electricity_network(n):
update_wind_solar_costs(n, costs) update_wind_solar_costs(n, costs)
n.loads["carrier"] = "electricity" n.loads["carrier"] = "electricity"
n.buses["location"] = n.buses.index n.buses["location"] = n.buses.index
# remove trailing white space of load index until new PyPSA version after v0.18.
n.loads.rename(lambda x: x.strip(), inplace=True)
n.loads_t.p_set.rename(lambda x: x.strip(), axis=1, inplace=True)
def add_co2_tracking(n, options): def add_co2_tracking(n, options):
@ -768,7 +771,7 @@ def insert_electricity_distribution_grid(n, costs):
capital_cost=costs.at['solar-rooftop', 'fixed'], capital_cost=costs.at['solar-rooftop', 'fixed'],
efficiency=n.generators.loc[solar, 'efficiency'], efficiency=n.generators.loc[solar, 'efficiency'],
p_max_pu=n.generators_t.p_max_pu[solar], p_max_pu=n.generators_t.p_max_pu[solar],
lifetime=costs.at['solar-rooftop', 'lifetime'] lifetime=costs.at['solar-rooftop', 'lifetime']
) )
n.add("Carrier", "home battery") n.add("Carrier", "home battery")
@ -816,7 +819,7 @@ def insert_gas_distribution_costs(n, costs):
# TODO options? # TODO options?
f_costs = options['gas_distribution_grid_cost_factor'] f_costs = options['gas_distribution_grid_cost_factor']
print("Inserting gas distribution grid with investment cost factor of", f_costs) print("Inserting gas distribution grid with investment cost factor of", f_costs)
capital_cost = costs.loc['electricity distribution grid']["fixed"] * f_costs capital_cost = costs.loc['electricity distribution grid']["fixed"] * f_costs
@ -825,7 +828,7 @@ def insert_gas_distribution_costs(n, costs):
gas_b = n.links.index[n.links.carrier.str.contains("gas boiler") & gas_b = n.links.index[n.links.carrier.str.contains("gas boiler") &
(~n.links.carrier.str.contains("urban central"))] (~n.links.carrier.str.contains("urban central"))]
n.links.loc[gas_b, "capital_cost"] += capital_cost n.links.loc[gas_b, "capital_cost"] += capital_cost
# micro CHPs # micro CHPs
mchp = n.links.index[n.links.carrier.str.contains("micro gas")] mchp = n.links.index[n.links.carrier.str.contains("micro gas")]
n.links.loc[mchp, "capital_cost"] += capital_cost n.links.loc[mchp, "capital_cost"] += capital_cost
@ -1073,7 +1076,7 @@ def add_land_transport(n, costs):
suffix=" EV battery", suffix=" EV battery",
carrier="Li ion" carrier="Li ion"
) )
p_set = electric_share * (transport[nodes] + cycling_shift(transport[nodes], 1) + cycling_shift(transport[nodes], 2)) / 3 p_set = electric_share * (transport[nodes] + cycling_shift(transport[nodes], 1) + cycling_shift(transport[nodes], 2)) / 3
n.madd("Load", n.madd("Load",
@ -1084,8 +1087,8 @@ def add_land_transport(n, costs):
p_set=p_set p_set=p_set
) )
p_nom = nodal_transport_data["number cars"] * options.get("bev_charge_rate", 0.011) * electric_share p_nom = nodal_transport_data["number cars"] * options.get("bev_charge_rate", 0.011) * electric_share
n.madd("Link", n.madd("Link",
nodes, nodes,
@ -1117,7 +1120,7 @@ def add_land_transport(n, costs):
if electric_share > 0 and options["bev_dsm"]: if electric_share > 0 and options["bev_dsm"]:
e_nom = nodal_transport_data["number cars"] * options.get("bev_energy", 0.05) * options["bev_availability"] * electric_share e_nom = nodal_transport_data["number cars"] * options.get("bev_energy", 0.05) * options["bev_availability"] * electric_share
n.madd("Store", n.madd("Store",
nodes, nodes,
@ -1197,7 +1200,7 @@ def add_heat(n, costs):
"services urban decentral", "services urban decentral",
"urban central" "urban central"
] ]
for name in heat_systems: for name in heat_systems:
name_type = "central" if name == "urban central" else "decentral" name_type = "central" if name == "urban central" else "decentral"
@ -1279,16 +1282,16 @@ def add_heat(n, costs):
p_nom_extendable=True p_nom_extendable=True
) )
if isinstance(options["tes_tau"], dict): if isinstance(options["tes_tau"], dict):
tes_time_constant_days = options["tes_tau"][name_type] tes_time_constant_days = options["tes_tau"][name_type]
else: else:
logger.warning("Deprecated: a future version will require you to specify 'tes_tau' ", logger.warning("Deprecated: a future version will require you to specify 'tes_tau' ",
"for 'decentral' and 'central' separately.") "for 'decentral' and 'central' separately.")
tes_time_constant_days = options["tes_tau"] if name_type == "decentral" else 180. tes_time_constant_days = options["tes_tau"] if name_type == "decentral" else 180.
# conversion from EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K # conversion from EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K
capital_cost = costs.at[name_type + ' water tank storage', 'fixed'] / 0.00117 / 40 capital_cost = costs.at[name_type + ' water tank storage', 'fixed'] / 0.00117 / 40
n.madd("Store", n.madd("Store",
nodes[name] + f" {name} water tanks", nodes[name] + f" {name} water tanks",
@ -1501,9 +1504,9 @@ def create_nodes_for_heat_sector():
# rural are areas with low heating density and individual heating # rural are areas with low heating density and individual heating
# urban are areas with high heating density # urban are areas with high heating density
# urban can be split into district heating (central) and individual heating (decentral) # urban can be split into district heating (central) and individual heating (decentral)
sectors = ["residential", "services"] sectors = ["residential", "services"]
nodes = {} nodes = {}
for sector in sectors: for sector in sectors:
nodes[sector + " rural"] = pop_layout.index nodes[sector + " rural"] = pop_layout.index
@ -1514,10 +1517,10 @@ def create_nodes_for_heat_sector():
nodes[sector + " urban decentral"] = pop_layout.index[pop_layout.ct.isin(urban_decentral_ct)] nodes[sector + " urban decentral"] = pop_layout.index[pop_layout.ct.isin(urban_decentral_ct)]
else: else:
nodes[sector + " urban decentral"] = pop_layout.index nodes[sector + " urban decentral"] = pop_layout.index
# for central nodes, residential and services are aggregated # for central nodes, residential and services are aggregated
nodes["urban central"] = pop_layout.index.symmetric_difference(nodes["residential urban decentral"]) nodes["urban central"] = pop_layout.index.symmetric_difference(nodes["residential urban decentral"])
return nodes return nodes
@ -1752,9 +1755,9 @@ def add_industry(n, costs):
if shipping_hydrogen_share < 1: if shipping_hydrogen_share < 1:
shipping_oil_share = 1 - shipping_hydrogen_share shipping_oil_share = 1 - shipping_hydrogen_share
p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760. p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760.
n.madd("Load", n.madd("Load",
nodes, nodes,
suffix=" shipping oil", suffix=" shipping oil",
@ -1762,7 +1765,7 @@ def add_industry(n, costs):
carrier="shipping oil", carrier="shipping oil",
p_set=p_set p_set=p_set
) )
co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"] co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"]
n.add("Load", n.add("Load",
@ -1781,7 +1784,7 @@ def add_industry(n, costs):
) )
if "EU oil Store" not in n.stores.index: if "EU oil Store" not in n.stores.index:
#could correct to e.g. 0.001 EUR/kWh * annuity and O&M #could correct to e.g. 0.001 EUR/kWh * annuity and O&M
n.add("Store", n.add("Store",
"EU oil Store", "EU oil Store",
@ -1948,7 +1951,7 @@ def add_waste_heat(n):
def decentral(n): def decentral(n):
"""Removes the electricity transmission system.""" """Removes the electricity transmission system."""
n.lines.drop(n.lines.index, inplace=True) n.lines.drop(n.lines.index, inplace=True)
n.links.drop(n.links.index[n.links.carrier.isin(["DC", "B2B"])], inplace=True) n.links.drop(n.links.index[n.links.carrier.isin(["DC", "B2B"])], inplace=True)
@ -1981,7 +1984,7 @@ def maybe_adjust_costs_and_potentials(n, opts):
if attr == 'p_nom_max': if attr == 'p_nom_max':
comps = {"Generator", "Link", "StorageUnit"} comps = {"Generator", "Link", "StorageUnit"}
elif attr == 'e_nom_max': elif attr == 'e_nom_max':
comps = {"Store"} comps = {"Store"}
else: else:
comps = {"Generator", "Link", "StorageUnit", "Store"} comps = {"Generator", "Link", "StorageUnit", "Store"}
for c in n.iterate_components(comps): for c in n.iterate_components(comps):
@ -2007,10 +2010,11 @@ if __name__ == "__main__":
snakemake = mock_snakemake( snakemake = mock_snakemake(
'prepare_sector_network', 'prepare_sector_network',
simpl='', simpl='',
clusters=48, clusters=45,
lv=1.0, lv=1.0,
opts='',
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1',
planning_horizons=2020, planning_horizons=2030,
) )
logging.basicConfig(level=snakemake.config['logging_level']) logging.basicConfig(level=snakemake.config['logging_level'])
@ -2036,7 +2040,7 @@ if __name__ == "__main__":
patch_electricity_network(n) patch_electricity_network(n)
if snakemake.config["foresight"] == 'myopic': if snakemake.config["foresight"] == 'myopic':
add_lifetime_wind_solar(n, costs) add_lifetime_wind_solar(n, costs)
conventional = snakemake.config['existing_capacities']['conventional_carriers'] conventional = snakemake.config['existing_capacities']['conventional_carriers']