diff --git a/config.yaml b/config.yaml index aebcb986..ca93a08c 100644 --- a/config.yaml +++ b/config.yaml @@ -2,15 +2,15 @@ logging_level: INFO results_dir: 'results/' summary_dir: results -run: '190516-decentral-noH2network' +run: '190712-test_district' scenario: sectors: [E] # ,E+EV,E+BEV,E+BEV+V2G] # [ E+EV, E+BEV, E+BEV+V2G ] simpl: [''] - lv: [1.0]#, 1.125, 1.25, 1.5, 2.0]# or opt + lv: [1.0,1.25,2.0]#, 1.125, 1.25, 1.5, 2.0]# or opt clusters: [128] #[90, 128, 181] #[45, 64, 90, 128, 181, 256] #, 362] # (2**np.r_[5.5:9:.5]).astype(int) minimum is 37 opts: [''] #for pypsa-eur - sector_opts: [Co2L0-3H-T-H-B-I-decentral-noH2network-solar100,Co2L0p1-3H-T-H-B-I-decentral-noH2network-solar100,Co2L0p2-3H-T-H-B-I-decentral-noH2network-solar100,Co2L0p3-3H-T-H-B-I-decentral-noH2network-solar100,Co2L0p4-3H-T-H-B-I-decentral-noH2network-solar100]#,Co2L0p1-3H-T-H-B-I,Co2L0p25-3H-T-H-B-I,Co2L0p5-3H-T-H-B-I]#[Co2L0-3H-T-H-B-I-onwind0-solar3,Co2L0-3H-T-H-B-I-onwind0p125-solar3,Co2L0-3H-T-H-B-I-onwind0p25-solar3,Co2L0-3H-T-H-B-I-onwind0p50-solar3,Co2L0-3H-T-H-B-I-solar3]#,Co2L0-3H-T-H-B-I-onwind0p25-solar3]#,Co2L0p05-3H-T-H-B-I,Co2L0p10-3H-T-H-B-I,Co2L0p20-3H-T-H-B-I,Co2L0p30-3H-T-H-B-I,Co2L0p50-3H-T-H-B-I]#[Co2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0-3H-T-H,Co2L0p20-3H-T-H] #Co2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0p20-3H-T-HCo2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0p30-3H-T-H,Co2L0p50-3H-T-H] #Co2L-3H,Co2L-3H-T,, LC-FL, LC-T, Ep-T, Co2L-T] + sector_opts: [Co2L0-3H-T-H-B-I,Co2L0-3H-T-H-B-I-nodistrict]#,Co2L0p1-3H-T-H-B-I,Co2L0p25-3H-T-H-B-I,Co2L0p5-3H-T-H-B-I]#[Co2L0-3H-T-H-B-I-onwind0-solar3,Co2L0-3H-T-H-B-I-onwind0p125-solar3,Co2L0-3H-T-H-B-I-onwind0p25-solar3,Co2L0-3H-T-H-B-I-onwind0p50-solar3,Co2L0-3H-T-H-B-I-solar3]#,Co2L0-3H-T-H-B-I-onwind0p25-solar3]#,Co2L0p05-3H-T-H-B-I,Co2L0p10-3H-T-H-B-I,Co2L0p20-3H-T-H-B-I,Co2L0p30-3H-T-H-B-I,Co2L0p50-3H-T-H-B-I]#[Co2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0-3H-T-H,Co2L0p20-3H-T-H] #Co2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0p20-3H-T-HCo2L-3H-T-H,Co2L0p10-3H-T-H,Co2L0p30-3H-T-H,Co2L0p50-3H-T-H] #Co2L-3H,Co2L-3H-T,, LC-FL, LC-T, Ep-T, Co2L-T] # Co2L will give default (5%); Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions @@ -57,7 +57,7 @@ sector: 'ICE_upper_degree_factor' : 1.6 'EV_lower_degree_factor' : 0.98 'EV_upper_degree_factor' : 0.63 - 'district_heating_loss' : 0.1 + 'district_heating_loss' : 0.15 'bev' : True #turns on EV battery 'bev_availability' : 0.5 #How many cars do smart charging 'v2g' : True #allows feed-in to grid from EV battery @@ -242,6 +242,10 @@ plotting: "Heat load" : "r" "Transport load" : "grey" "heat" : "darkred" + "rural heat" : "#880000" + "central heat" : "#b22222" + "decentral heat" : "#800000" + "process heat" : "#FF3333" "heat demand" : "darkred" "electric demand" : "k" "Li ion" : "grey" @@ -252,10 +256,14 @@ plotting: "V2G" : "grey" "transport" : "grey" "electricity" : "k" + "industry new electricity" : "#222222" + "process emissions to stored" : "#444444" + "process emissions to atmosphere" : "#888888" "transport fuel cell" : "#AAAAAA" "biogas" : "#800000" "solid biomass" : "#DAA520" "today" : "#D2691E" + "shipping" : "#6495ED" nice_names: # OCGT: "Gas" # OCGT marginal: "Gas (marginal)" diff --git a/scripts/make_summary.py b/scripts/make_summary.py index 5d1db38d..267da708 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -41,17 +41,9 @@ override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output", def assign_carriers(n): - - if "carrier" not in n.loads: - n.loads["carrier"] = "electricity" - for carrier in ["transport","heat","urban heat"]: - n.loads.loc[n.loads.index.str.contains(carrier),"carrier"] = carrier - if "carrier" not in n.lines: n.lines["carrier"] = "AC" - if n.stores.loc["EU gas Store","carrier"] == "": - n.stores.loc["EU gas Store","carrier"] = "gas Store" def assign_locations(n): for c in n.iterate_components(n.one_port_components|n.branch_components): diff --git a/scripts/plot_summary.py b/scripts/plot_summary.py index 2297bf56..d265d76f 100644 --- a/scripts/plot_summary.py +++ b/scripts/plot_summary.py @@ -13,53 +13,46 @@ import matplotlib.pyplot as plt #consolidate and rename def rename_techs(label): - if label[:8] == "central ": - label = label[8:] - if label[:6] == "urban ": - label = label[6:] - if "retrofitting" in label: - label = "building retrofitting" - if "H2" in label: - label = "hydrogen storage" - if "CHP" in label: - label = "CHP" - if "water tank" in label: - label = "water tanks" - if label=="water tanks": - label = "hot water storage" - if "gas" in label and label not in ["gas boiler","biogas"]: - label = "natural gas" - if "solar thermal" in label: - label = "solar thermal" - if label == "solar": - label = "solar PV" - if label == "heat pump": - label = "air heat pump" - if label == "Sabatier": - label = "methanation" - if label == "offwind": - label = "offshore wind" - if label == "offwind-ac": - label = "offshore wind (AC)" - if label == "offwind-dc": - label = "offshore wind (DC)" - if label == "onwind": - label = "onshore wind" - if label == "ror": - label = "hydroelectricity" - if label == "hydro": - label = "hydroelectricity" - if label == "PHS": - label = "hydroelectricity" - if label == "co2 Store": - label = "DAC" - if label == "co2 stored": - label = "CO2 sequestration" - if "battery" in label: - label = "battery storage" - if label in ["AC","DC","B2B"]: - label = "transmission lines" + prefix_to_remove = ["central ","urban "] + + rename_if_contains = ["CHP","gas boiler","biogas","solar thermal","air heat pump","ground heat pump","resistive heater"] + + rename_if_contains_dict = {"water tanks" : "hot water storage", + "retrofitting" : "building retrofitting", + "H2" : "hydrogen storage", + "battery" : "battery storage"} + + rename = {"solar" : "solar PV", + "Sabatier" : "methanation", + "offwind" : "offshore wind", + "offwind-ac" : "offshore wind (AC)", + "offwind-dc" : "offshore wind (DC)", + "onwind" : "onshore wind", + "ror" : "hydroelectricity", + "hydro" : "hydroelectricity", + "PHS" : "hydroelectricity", + "co2 Store" : "DAC", + "co2 stored" : "CO2 sequestration", + "AC" : "transmission lines", + "DC" : "transmission lines", + "B2B" : "transmission lines"} + + for ptr in prefix_to_remove: + if label[:len(ptr)] == ptr: + label = label[len(ptr):] + + for rif in rename_if_contains: + if rif in label: + label = rif + + for old,new in rename_if_contains_dict.items(): + if old in label: + label = new + + for old,new in rename.items(): + if old == label: + label = new return label diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index c93204af..757be2d2 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -632,6 +632,7 @@ def add_transport(network): nodes, suffix=" transport", bus=nodes + " EV battery", + carrier="transport", p_set=(1-options['transport_fuel_cell_share'])*(transport[nodes]+shift_df(transport[nodes],1)+shift_df(transport[nodes],2))/3.) p_nom = nodal_transport_data["number cars"]*0.011*(1-options['transport_fuel_cell_share']) #3-phase charger with 11 kW * x% of time grid-connected @@ -684,6 +685,7 @@ def add_transport(network): nodes, suffix=" transport fuel cell", bus=nodes + " H2", + carrier="transport fuel cell", p_set=options['transport_fuel_cell_share']/0.58*transport[nodes]) @@ -692,78 +694,102 @@ def add_transport(network): def add_heat(network): print("adding heat") - nodes = pop_layout.index - network.add("Carrier","heat") - network.add("Carrier","water tanks") + #rural are areas with low heating density + #urban are areas with high heating density + #urban can be split into district heating (central) and individual heating (decentral) + rural = pop_layout.index + urban = pop_layout.index + + network.add("Carrier","rural heat") + network.add("Carrier","urban central heat") + network.add("Carrier","urban decentral heat") + network.add("Carrier","rural water tanks") + network.add("Carrier","urban central water tanks") + network.add("Carrier","urban decentral water tanks") + #urban are high density locations if options["central"]: - urban_ct = pd.Index(["ES","GR","PT","IT","BG"]) - urban = pop_layout.index[pop_layout.ct.isin(urban_ct)] + urban_decentral_ct = pd.Index(["ES","GR","PT","IT","BG"]) + urban_decentral = pop_layout.index[pop_layout.ct.isin(urban_decentral_ct)] else: - urban = nodes + urban_decentral = urban #NB: must add costs of central heating afterwards (EUR 400 / kWpeak, 50a, 1% FOM from Fraunhofer ISE) - #central are urban nodes with district heating - central = nodes ^ urban + urban_central = urban ^ urban_decentral urban_fraction = options['central_fraction']*pop_layout["urban"]/(pop_layout[["urban","rural"]].sum(axis=1)) network.madd("Bus", - nodes + " heat", - carrier="heat") + rural + " rural heat", + carrier="rural heat") network.madd("Bus", - nodes + " urban heat", - carrier="heat") + urban_central + " urban central heat", + carrier="urban central heat") + + network.madd("Bus", + urban_decentral + " urban decentral heat", + carrier="urban decentral heat") + network.madd("Load", - nodes, - suffix=" heat", - bus=nodes + " heat", - p_set= heat_demand[nodes].multiply((1-urban_fraction))) + rural, + suffix=" rural heat", + bus=rural + " rural heat", + carrier="rural heat", + p_set= heat_demand[rural].multiply((1-urban_fraction[rural]))) network.madd("Load", - nodes, - suffix=" urban heat", - bus=nodes + " urban heat", - p_set= heat_demand[nodes].multiply(urban_fraction).divide((1-options['district_heating_loss']))) + urban_central, + suffix=" urban central heat", + bus=urban_central + " urban central heat", + carrier="urban central heat", + p_set= heat_demand[urban_central].multiply(urban_fraction[urban_central]*(1+options['district_heating_loss']))) + + network.madd("Load", + urban_decentral, + suffix=" urban decentral heat", + bus=urban_decentral + " urban decentral heat", + carrier="urban decentral heat", + p_set= heat_demand[urban_decentral].multiply(urban_fraction[urban_decentral])) network.madd("Link", - urban, - suffix=" urban heat pump", - bus0=urban, - bus1=urban + " urban heat", - carrier="urban heat pump", - efficiency=ashp_cop[urban] if options["time_dep_hp_cop"] else costs.at['decentral air-sourced heat pump','efficiency'], + urban_decentral, + suffix=" urban decentral air heat pump", + bus0=urban_decentral, + bus1=urban_decentral + " urban decentral heat", + carrier="urban decentral air heat pump", + efficiency=ashp_cop[urban_decentral] if options["time_dep_hp_cop"] else costs.at['decentral air-sourced heat pump','efficiency'], capital_cost=costs.at['decentral air-sourced heat pump','efficiency']*costs.at['decentral air-sourced heat pump','fixed'], p_nom_extendable=True) network.madd("Link", - central, - suffix=" central heat pump", - bus0=central, - bus1=central + " urban heat", - carrier="central heat pump", - efficiency=ashp_cop[central] if options["time_dep_hp_cop"] else costs.at['central air-sourced heat pump','efficiency'], + urban_central, + suffix=" urban central air heat pump", + bus0=urban_central, + bus1=urban_central + " urban central heat", + carrier="urban central air heat pump", + efficiency=ashp_cop[urban_central] if options["time_dep_hp_cop"] else costs.at['central air-sourced heat pump','efficiency'], capital_cost=costs.at['central air-sourced heat pump','efficiency']*costs.at['central air-sourced heat pump','fixed'], p_nom_extendable=True) network.madd("Link", - nodes, - suffix=" ground heat pump", - bus0=nodes, - bus1=nodes + " heat", - carrier="ground heat pump", - efficiency=gshp_cop[nodes] if options["time_dep_hp_cop"] else costs.at['decentral ground-sourced heat pump','efficiency'], + rural, + suffix=" rural ground heat pump", + bus0=rural, + bus1=rural + " rural heat", + carrier="rural ground heat pump", + efficiency=gshp_cop[rural] if options["time_dep_hp_cop"] else costs.at['decentral ground-sourced heat pump','efficiency'], capital_cost=costs.at['decentral ground-sourced heat pump','efficiency']*costs.at['decentral ground-sourced heat pump','fixed'], p_nom_extendable=True) + #NB: this currently doesn't work for pypsa-eur model if options['retrofitting']: retro_nodes = pd.Index(["DE"]) @@ -827,94 +853,94 @@ def add_heat(network): if options["tes"]: network.madd("Bus", - nodes + " water tanks", - carrier="water tanks") + rural + " rural water tanks", + carrier="rural water tanks") network.madd("Link", - nodes + " water tanks charger", - bus0=nodes + " heat", - bus1=nodes + " water tanks", + rural + " rural water tanks charger", + bus0=rural + " rural heat", + bus1=rural + " rural water tanks", efficiency=costs.at['water tank charger','efficiency'], - carrier="water tanks charger", + carrier="rural water tanks charger", p_nom_extendable=True) network.madd("Link", - nodes + " water tanks discharger", - bus0=nodes + " water tanks", - bus1=nodes + " heat", - carrier="water tanks discharger", + rural + " rural water tanks discharger", + bus0=rural + " rural water tanks", + bus1=rural + " rural heat", + carrier="rural water tanks discharger", efficiency=costs.at['water tank discharger','efficiency'], p_nom_extendable=True) network.madd("Store", - nodes + " water tank", - bus=nodes + " water tanks", + rural + " rural water tanks", + bus=rural + " rural water tanks", e_cyclic=True, e_nom_extendable=True, - carrier="water tank", + carrier="rural water tanks", standing_loss=1-np.exp(-1/(24.*options["tes_tau"])), # [HP] 180 day time constant for centralised, 3 day for decentralised capital_cost=costs.at['decentral water tank storage','fixed']/(1.17e-3*40)) #conversion from EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K network.madd("Bus", - urban + " urban water tanks", - carrier="water tanks") + urban_decentral + " urban decentral water tanks", + carrier="urban decentral water tanks") network.madd("Link", - urban + " urban water tanks charger", - bus0=urban + " urban heat", - bus1=urban + " urban water tanks", - carrier="urban water tanks charger", + urban_decentral + " urban decentral water tanks charger", + bus0=urban_decentral + " urban decentral heat", + bus1=urban_decentral + " urban decentral water tanks", + carrier="urban decentral water tanks charger", efficiency=costs.at['water tank charger','efficiency'], p_nom_extendable=True) network.madd("Link", - urban + " urban water tanks discharger", - bus0=urban + " urban water tanks", - bus1=urban + " urban heat", - carrier="urban water tanks discharger", + urban_decentral + " urban decentral water tanks discharger", + bus0=urban_decentral + " urban decentral water tanks", + bus1=urban_decentral + " urban decentral heat", + carrier="urban decentral water tanks discharger", efficiency=costs.at['water tank discharger','efficiency'], p_nom_extendable=True) network.madd("Store", - urban + " urban water tank", - bus=urban + " urban water tanks", + urban_decentral + " urban decentral water tanks", + bus=urban_decentral + " urban decentral water tanks", e_cyclic=True, e_nom_extendable=True, - carrier="urban water tank", + carrier="urban decentral water tanks", standing_loss=1-np.exp(-1/(24.*options["tes_tau"])), # [HP] 180 day time constant for centralised, 3 day for decentralised capital_cost=costs.at['decentral water tank storage','fixed']/(1.17e-3*40)) #conversion from EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K network.madd("Bus", - central + " central water tanks", - carrier="water tanks") + urban_central + " urban central water tanks", + carrier="urban central water tanks") network.madd("Link", - central + " central water tanks charger", - bus0=central + " urban heat", - bus1=central + " central water tanks", + urban_central + " urban central water tanks charger", + bus0=urban_central + " urban central heat", + bus1=urban_central + " urban central water tanks", p_nom_extendable=True, - carrier="central water tanks charger", + carrier="urban central water tanks charger", efficiency=costs.at['water tank charger','efficiency']) network.madd("Link", - central + " central water tanks discharger", - bus0=central + " central water tanks", - bus1=central + " urban heat", - carrier="central water tanks discharger", + urban_central + " urban central water tanks discharger", + bus0=urban_central + " urban central water tanks", + bus1=urban_central + " urban central heat", + carrier="urban central water tanks discharger", p_nom_extendable=True, efficiency=costs.at['water tank discharger','efficiency']) network.madd("Store", - central, - suffix=" central water tank", - bus=central + " central water tanks", + urban_central, + suffix=" urban central water tanks", + bus=urban_central + " urban central water tanks", e_cyclic=True, - carrier="central water tank", + carrier="urban central water tanks", e_nom_extendable=True, standing_loss=1-np.exp(-1/(24.*180.)), # [HP] 180 day time constant for centralised, 3 day for decentralised capital_cost=costs.at['central water tank storage','fixed']/(1.17e-3*40)) #convert EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K @@ -924,61 +950,61 @@ def add_heat(network): if options["boilers"]: network.madd("Link", - nodes + " resistive heater", - bus0=nodes, - bus1=nodes + " heat", - carrier="resistive heater", + rural + " rural resistive heater", + bus0=rural, + bus1=rural + " rural heat", + carrier="rural resistive heater", efficiency=costs.at['decentral resistive heater','efficiency'], capital_cost=costs.at['decentral resistive heater','efficiency']*costs.at['decentral resistive heater','fixed'], p_nom_extendable=True) network.madd("Link", - urban + " urban resistive heater", - bus0=urban, - bus1=urban + " urban heat", - carrier="urban resistive heater", + urban_decentral + " urban decentral resistive heater", + bus0=urban_decentral, + bus1=urban_decentral + " urban decentral heat", + carrier="urban decentral resistive heater", efficiency=costs.at['decentral resistive heater','efficiency'], capital_cost=costs.at['decentral resistive heater','efficiency']*costs.at['decentral resistive heater','fixed'], p_nom_extendable=True) network.madd("Link", - central + " central resistive heater", - bus0=central, - bus1=central + " urban heat", + urban_central + " urban central resistive heater", + bus0=urban_central, + bus1=urban_central + " urban central heat", p_nom_extendable=True, - carrier="central resistive heater", + carrier="urban central resistive heater", capital_cost=costs.at['central resistive heater','efficiency']*costs.at['central resistive heater','fixed'], efficiency=costs.at['central resistive heater','efficiency']) network.madd("Link", - nodes + " gas boiler", + rural + " gas boiler", p_nom_extendable=True, - bus0=["EU gas"]*len(nodes), - bus1=nodes + " heat", + bus0=["EU gas"]*len(rural), + bus1=rural + " rural heat", bus2="co2 atmosphere", - carrier="gas boiler", + carrier="rural gas boiler", efficiency=costs.at['decentral gas boiler','efficiency'], efficiency2=costs.at['gas','CO2 intensity'], capital_cost=costs.at['decentral gas boiler','efficiency']*costs.at['decentral gas boiler','fixed']) network.madd("Link", - urban + " urban gas boiler", + urban_decentral + " urban decentral gas boiler", p_nom_extendable=True, - bus0=["EU gas"]*len(urban), - bus1=urban + " urban heat", + bus0=["EU gas"]*len(urban_decentral), + bus1=urban_decentral + " urban decentral heat", bus2="co2 atmosphere", - carrier="urban gas boiler", + carrier="urban decentral gas boiler", efficiency=costs.at['decentral gas boiler','efficiency'], efficiency2=costs.at['gas','CO2 intensity'], capital_cost=costs.at['decentral gas boiler','efficiency']*costs.at['decentral gas boiler','fixed']) network.madd("Link", - central + " central gas boiler", - bus0=["EU gas"]*len(central), - bus1=central + " urban heat", + urban_central + " urban central gas boiler", + bus0=["EU gas"]*len(urban_central), + bus1=urban_central + " urban central heat", bus2="co2 atmosphere", - carrier="central gas boiler", + carrier="urban central gas boiler", p_nom_extendable=True, capital_cost=costs.at['central gas boiler','efficiency']*costs.at['central gas boiler','fixed'], efficiency2=costs.at['gas','CO2 intensity'], @@ -988,13 +1014,13 @@ def add_heat(network): #additional bus, to which we can also connect biomass network.madd("Bus", - central + " central CHP", - carrier="chp") + urban_central + " urban central CHP", + carrier="urban central CHP") network.madd("Link", - central + " gas to central CHP", + urban_central + " gas to urban central CHP", bus0="EU gas", - bus1=central + " central CHP", + bus1=urban_central + " urban central CHP", bus2="co2 atmosphere", bus3="co2 stored", efficiency2=costs.at['gas','CO2 intensity']*(1-options["ccs_fraction"]), @@ -1003,19 +1029,19 @@ def add_heat(network): p_nom_extendable=True) network.madd("Link", - central + " central CHP electric", - bus0=central + " central CHP", - bus1=central, - carrier="central CHP electric", + urban_central + " urban central CHP electric", + bus0=urban_central + " urban central CHP", + bus1=urban_central, + carrier="urban central CHP electric", p_nom_extendable=True, capital_cost=costs.at['central CHP','fixed']*options['chp_parameters']['eta_elec'], efficiency=options['chp_parameters']['eta_elec']) network.madd("Link", - central + " central CHP heat", - bus0=central + " central CHP", - bus1=central + " urban heat", - carrier="central CHP heat", + urban_central + " urban central CHP heat", + bus0=urban_central + " urban central CHP", + bus1=urban_central + " urban central heat", + carrier="urban central CHP heat", p_nom_extendable=True, efficiency=options['chp_parameters']['eta_elec']/options['chp_parameters']['c_v']) @@ -1025,32 +1051,32 @@ def add_heat(network): network.add("Carrier","solar thermal") network.madd("Generator", - nodes, - suffix=" solar thermal collector", - bus=nodes + " heat", - carrier="solar thermal", + rural, + suffix=" rural solar thermal collector", + bus=rural + " rural heat", + carrier="rural solar thermal", p_nom_extendable=True, capital_cost=costs.at['decentral solar thermal','fixed'], - p_max_pu=solar_thermal[nodes]) + p_max_pu=solar_thermal[rural]) network.madd("Generator", - urban, - suffix=" urban solar thermal collector", - bus=urban + " urban heat", - carrier="solar thermal", + urban_decentral, + suffix=" urban decentral solar thermal collector", + bus=urban_decentral + " urban decentral heat", + carrier="urban decentral solar thermal", p_nom_extendable=True, capital_cost=costs.at['decentral solar thermal','fixed'], - p_max_pu=solar_thermal[urban]) + p_max_pu=solar_thermal[urban_decentral]) network.madd("Generator", - central, - suffix=" central solar thermal collector", - bus=central + " urban heat", - carrier="solar thermal", + urban_central, + suffix=" urban central solar thermal collector", + bus=urban_central + " urban central heat", + carrier="urban central solar thermal", p_nom_extendable=True, capital_cost=costs.at['central solar thermal','fixed'], - p_max_pu=solar_thermal[central]) + p_max_pu=solar_thermal[urban_central]) def add_biomass(network): @@ -1061,20 +1087,6 @@ def add_biomass(network): #biomass distributed at country level - i.e. transport within country allowed cts = pop_layout.ct.value_counts().index - #urban are high density locations - if options["central"]: - urban_cts = pd.Index(["ES","GR","PT","IT","BG"]) - urban = pop_layout.index[pop_layout.ct.isin(urban_cts)] - else: - urban_cts = cts - urban = nodes - - #central are urban nodes with district heating - central = nodes ^ urban - - #central_cts are urban countries with district heating - central_cts = cts ^ urban_cts - biomass_potentials = pd.read_csv(snakemake.input.biomass_potentials, index_col=0) @@ -1112,21 +1124,27 @@ def add_biomass(network): bus0=cts + " biogas", bus1="EU gas", bus2="co2 atmosphere", - carrier="biogas", + carrier="biogas to gas", efficiency2=-costs.at['gas','CO2 intensity'], p_nom_extendable=True) - #with BECCS - network.madd("Link", - central + " solid biomass to CHP", - bus0=central.str[:2] + " solid biomass", - bus1=central + " central CHP", - bus2="co2 atmosphere", - bus3="co2 stored", - efficiency2=-costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"], - efficiency3=costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"], - carrier="solid biomass", - p_nom_extendable=True) + + #AC buses with district heating + urban_central = n.buses.index[n.buses.carrier == "urban central heat"] + if not urban_central.empty: + urban_central = urban_central.str[:-len(" urban central heat")] + + #with BECCS + network.madd("Link", + urban_central + " solid biomass to urban central CHP", + bus0=urban_central.str[:2] + " solid biomass", + bus1=urban_central + " urban central CHP", + bus2="co2 atmosphere", + bus3="co2 stored", + efficiency2=-costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"], + efficiency3=costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"], + carrier="solid biomass to urban central CHP", + p_nom_extendable=True) def add_industry(network): @@ -1146,6 +1164,7 @@ def add_industry(network): nodes, suffix=" process heat", bus=nodes + " process heat", + carrier="process heat", p_set = industrial_demand.loc[nodes,"industry process heat"]/8760.) #with BECCS @@ -1182,6 +1201,7 @@ def add_industry(network): nodes, suffix=" shipping", bus=nodes + " H2", + carrier="shipping", p_set = industrial_demand.loc[nodes,"shipping H2"]/8760.) network.add("Bus", @@ -1231,41 +1251,47 @@ def add_industry(network): efficiency2=costs.at["oil",'CO2 intensity'], p_nom_extendable=True) - network.add("Load", - "Fischer-Tropsch", - bus="Fischer-Tropsch-demand", - p_set = industrial_demand.loc[nodes,["aviation kerosene","naphtha feedstock"]].sum().sum()/8760.) + network.madd("Load", + ["Fischer-Tropsch"], + bus="Fischer-Tropsch-demand", + carrier="Fischer-Tropsch", + p_set = industrial_demand.loc[nodes,["aviation kerosene","naphtha feedstock"]].sum().sum()/8760.) network.madd("Load", nodes, suffix=" industry new electricity", bus=nodes, + carrier="industry new electricity", p_set = industrial_demand.loc[nodes,"industry new electricity"]/8760.) - network.add("Load", - "process emissions to atmosphere", - bus="co2 atmosphere", - p_set = -industrial_demand.loc[nodes,"process emissions"].sum()*(1-options["ccs_fraction"])/8760.) + network.madd("Load", + ["process emissions to atmosphere"], + bus="co2 atmosphere", + carrier="process emissions to atmosphere", + p_set = -industrial_demand.loc[nodes,"process emissions"].sum()*(1-options["ccs_fraction"])/8760.) - network.add("Load", - "process emissions to stored", - bus="co2 stored", - p_set = -industrial_demand.loc[nodes,"process emissions"].sum()*options["ccs_fraction"]/8760.) + network.madd("Load", + ["process emissions to stored"], + bus="co2 stored", + carrier="process emissions to stored", + p_set = -industrial_demand.loc[nodes,"process emissions"].sum()*options["ccs_fraction"]/8760.) def add_waste_heat(network): print("adding possibility to use industrial waste heat in district heating") #AC buses with district heating - central_buses = n.buses.index[n.buses.index.str.contains("central CHP")].str[:-12] + urban_central = n.buses.index[n.buses.carrier == "urban central heat"] + if not urban_central.empty: + urban_central = urban_central.str[:-len(" urban central heat")] - if options['use_fischer_tropsch_waste_heat']: - n.links.loc[central_buses + " Fischer-Tropsch","bus3"] = central_buses + " urban heat" - n.links.loc[central_buses + " Fischer-Tropsch","efficiency3"] = 0.95 - n.links.loc[central_buses + " Fischer-Tropsch","efficiency"] + if options['use_fischer_tropsch_waste_heat']: + n.links.loc[urban_central + " Fischer-Tropsch","bus3"] = urban_central + " urban central heat" + n.links.loc[urban_central + " Fischer-Tropsch","efficiency3"] = 0.95 - n.links.loc[urban_central + " Fischer-Tropsch","efficiency"] - if options['use_fuel_cell_waste_heat']: - n.links.loc[central_buses + " H2 Fuel Cell","bus2"] = central_buses + " urban heat" - n.links.loc[central_buses + " H2 Fuel Cell","efficiency2"] = 0.95 - n.links.loc[central_buses + " H2 Fuel Cell","efficiency"] + if options['use_fuel_cell_waste_heat']: + n.links.loc[urban_central + " H2 Fuel Cell","bus2"] = urban_central + " urban central heat" + n.links.loc[urban_central + " H2 Fuel Cell","efficiency2"] = 0.95 - n.links.loc[urban_central + " H2 Fuel Cell","efficiency"] def restrict_technology_potential(n,tech,limit): @@ -1338,6 +1364,8 @@ if __name__ == "__main__": remove_elec_base_techs(n) + n.loads["carrier"] = "electricity" + add_co2_tracking(n) add_generation(n) @@ -1347,6 +1375,9 @@ if __name__ == "__main__": nodal_energy_totals, heat_demand, space_heat_demand, water_heat_demand, ashp_cop, gshp_cop, solar_thermal, transport, avail_profile, dsm_profile, co2_totals, nodal_transport_data = prepare_data(n) + if "nodistrict" in opts: + options["central"] = False + if "T" in opts: add_transport(n) diff --git a/scripts/solve_network.py b/scripts/solve_network.py index a0f06e34..9a73f918 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -138,26 +138,29 @@ def add_chp_constraints(network): if hasattr(network.links.index,"str") and network.links.index.str.contains("CHP").any(): - #also catches central heat buses for district heating - nodes = list(network.links.index[network.links.index.str.contains("CHP electric")].str[:-len(" CHP electric")]) + #AC buses with district heating + urban_central = n.buses.index[n.buses.carrier == "urban central heat"] + if not urban_central.empty: + urban_central = urban_central.str[:-len(" urban central heat")] + def chp_nom(model,node): - return network.links.at[node + " CHP electric","efficiency"]*options['chp_parameters']['p_nom_ratio']*model.link_p_nom[node + " CHP electric"] == network.links.at[node + " CHP heat","efficiency"]*options['chp_parameters']['p_nom_ratio']*model.link_p_nom[node + " CHP heat"] + return network.links.at[node + " urban central CHP electric","efficiency"]*options['chp_parameters']['p_nom_ratio']*model.link_p_nom[node + " urban central CHP electric"] == network.links.at[node + " urban central CHP heat","efficiency"]*options['chp_parameters']['p_nom_ratio']*model.link_p_nom[node + " urban central CHP heat"] - network.model.chp_nom = pypsa.opt.Constraint(nodes,rule=chp_nom) + network.model.chp_nom = pypsa.opt.Constraint(urban_central,rule=chp_nom) def backpressure(model,node,snapshot): - return options['chp_parameters']['c_m']*network.links.at[node + " CHP heat","efficiency"]*model.link_p[node + " CHP heat",snapshot] <= network.links.at[node + " CHP electric","efficiency"]*model.link_p[node + " CHP electric",snapshot] + return options['chp_parameters']['c_m']*network.links.at[node + " urban central CHP heat","efficiency"]*model.link_p[node + " urban central CHP heat",snapshot] <= network.links.at[node + " urban central CHP electric","efficiency"]*model.link_p[node + " urban central CHP electric",snapshot] - network.model.backpressure = pypsa.opt.Constraint(nodes,list(network.snapshots),rule=backpressure) + network.model.backpressure = pypsa.opt.Constraint(urban_central,list(network.snapshots),rule=backpressure) def top_iso_fuel_line(model,node,snapshot): - return model.link_p[node + " CHP heat",snapshot] + model.link_p[node + " CHP electric",snapshot] <= model.link_p_nom[node + " CHP electric"] + return model.link_p[node + " urban central CHP heat",snapshot] + model.link_p[node + " urban central CHP electric",snapshot] <= model.link_p_nom[node + " urban central CHP electric"] - network.model.top_iso_fuel_line = pypsa.opt.Constraint(nodes,list(network.snapshots),rule=top_iso_fuel_line) + network.model.top_iso_fuel_line = pypsa.opt.Constraint(urban_central,list(network.snapshots),rule=top_iso_fuel_line)