From 49a68bdd35cc93417edf690f40977f8d36dd1a13 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Thu, 12 Dec 2019 15:03:51 +0100 Subject: [PATCH] Separate CHP gas/solid biomass, with/without CCS Also fix CHP p_nom_ratio constraint, and battery charger/discharger constraint. --- config.yaml | 9 +-- data/costs.csv | 35 +++++++- scripts/prepare_sector_network.py | 128 ++++++++++++++++++++++-------- scripts/solve_network.py | 46 +++++------ 4 files changed, 149 insertions(+), 69 deletions(-) diff --git a/config.yaml b/config.yaml index 9e413493..dc5f1bda 100644 --- a/config.yaml +++ b/config.yaml @@ -2,12 +2,12 @@ logging_level: INFO results_dir: 'results/' summary_dir: results -run: '191202-nomopyomo' +run: '191212-chp' scenario: sectors: [E] # ,E+EV,E+BEV,E+BEV+V2G] # [ E+EV, E+BEV, E+BEV+V2G ] simpl: [''] - lv: [1.0,1.25]#, 1.125, 1.25, 1.5, 2.0]# or opt + lv: [1.0]#, 1.125, 1.25, 1.5, 2.0]# or opt clusters: [50] #[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]#,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] @@ -73,11 +73,6 @@ sector: 'tes_tau' : 3. 'boilers' : True 'chp' : True - 'chp_parameters': - 'eta_elec' : 0.468 #electrical efficiency with no heat output - 'c_v' : 0.15 #loss of fuel for each addition of heat - 'c_m' : 0.75 #backpressure ratio - 'p_nom_ratio' : 1. #ratio of max heat output to max electrical output 'solar_thermal' : True 'solar_cf_correction': 0.788457 # = >>> 1/1.2683 'marginal_cost_storage' : 0. #1e-4 diff --git a/data/costs.csv b/data/costs.csv index 9daca579..dd6571e0 100644 --- a/data/costs.csv +++ b/data/costs.csv @@ -175,9 +175,38 @@ decentral CHP,2030,lifetime,25,years,HP decentral CHP,2030,investment,1400,EUR/kWel,HP decentral CHP,2030,FOM,3,%/year,HP decentral CHP,2030,discount rate,0.04,per unit,Palzer thesis -central CHP,2030,lifetime,25,years,HP -central CHP,2030,investment,650,EUR/kWel,HP -central CHP,2030,FOM,3,%/year,HP +central gas CHP,2030,lifetime,30,years,DEA +central gas CHP,2030,investment,1300,EUR/kWel,DEA +central gas CHP,2030,FOM,3,%/year,DEA +central gas CHP,2030,efficiency,0.45,per unit,DEA (condensation mode) +central gas CHP,2030,c_b,0.7,per unit,DEA (backpressure ratio) +central gas CHP,2030,c_v,0.17,per unit,DEA (loss of fuel for additional heat) +central gas CHP,2030,p_nom_ratio,1.,per unit, +central gas CHP,2030,VOM,0.82,EUR/MWh,DEA +central gas CHP CCS,2030,lifetime,30,years,DEA +central gas CHP CCS,2030,investment,1900,EUR/kWel,DEA + DIW extra for CCS on gas plant +central gas CHP CCS,2030,FOM,3,%/year,DEA +central gas CHP CCS,2030,efficiency,0.405,per unit,DEA (condensation mode + efficiency loss due to capture) +central gas CHP CCS,2030,c_b,0.7,per unit,DEA (backpressure ratio) +central gas CHP CCS,2030,c_v,0.17,per unit,DEA (loss of fuel for additional heat) +central gas CHP CCS,2030,p_nom_ratio,1.,per unit, +central gas CHP CCS,2030,VOM,0.82,EUR/MWh,DEA +central solid biomass CHP,2030,lifetime,40,years,DEA +central solid biomass CHP,2030,investment,1990,EUR/kWel,DEA +central solid biomass CHP,2030,FOM,3,%/year,DEA +central solid biomass CHP,2030,efficiency,0.52,per unit,DEA (condensation mode) +central solid biomass CHP,2030,c_b,1.01,per unit,DEA (backpressure ratio) +central solid biomass CHP,2030,c_v,0.15,per unit,DEA (loss of fuel for additional heat) +central solid biomass CHP,2030,p_nom_ratio,1.,per unit, +central solid biomass CHP,2030,VOM,2.2,EUR/MWh,DEA +central solid biomass CHP CCS,2030,lifetime,40,years,DEA +central solid biomass CHP CCS,2030,investment,2590,EUR/kWel,DEA + DIW extra for CCS on gas plant +central solid biomass CHP CCS,2030,FOM,3,%/year,DEA +central solid biomass CHP CCS,2030,efficiency,0.468,per unit,DEA (condensation mode + efficiency loss due to capture) +central solid biomass CHP CCS,2030,c_b,1.01,per unit,DEA (backpressure ratio) +central solid biomass CHP CCS,2030,c_v,0.15,per unit,DEA (loss of fuel for additional heat) +central solid biomass CHP CCS,2030,p_nom_ratio,1.,per unit, +central solid biomass CHP CCS,2030,VOM,2.2,EUR/MWh,DEA micro CHP,2030,lifetime,20,years,DEA for PEMFC with methane (for unit consuming 2kW CH4) micro CHP,2030,investment,4500,EUR/kWCH4,DEA for PEMFC with methane (for unit consuming 2kW CH4) micro CHP,2030,FOM,6,%/year,DEA for PEMFC with methane (for unit consuming 2kW CH4) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 11a1d965..b7233be8 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -765,7 +765,7 @@ def add_heat(network): network.madd("Load", nodes[name], - suffix=" " + name + "heat", + suffix=" " + name + " heat", bus=nodes[name] + " " + name + " heat", carrier=name + " heat", p_set=heat_load) @@ -868,47 +868,72 @@ def add_heat(network): if options["chp"]: if name == "urban central": - #additional bus, to which we can also connect biomass - network.madd("Bus", - nodes[name] + " urban central CHP", - carrier="urban central CHP") + #add gas CHP; biomass CHP is added in biomass section + network.madd("Link", + nodes[name] + " urban central gas CHP electric", + bus0="EU gas", + bus1=nodes[name], + bus2="co2 atmosphere", + carrier="urban central gas CHP electric", + p_nom_extendable=True, + capital_cost=costs.at['central gas CHP','fixed']*costs.at['central gas CHP','efficiency'], + marginal_cost=costs.at['central gas CHP','VOM'], + efficiency=costs.at['central gas CHP','efficiency'], + efficiency2=costs.at['gas','CO2 intensity'], + c_b=costs.at['central gas CHP','c_b'], + c_v=costs.at['central gas CHP','c_v'], + p_nom_ratio=costs.at['central gas CHP','p_nom_ratio']) network.madd("Link", - nodes[name] + " gas to urban central CHP", + nodes[name] + " urban central gas CHP heat", bus0="EU gas", - bus1=nodes[name] + " urban central CHP", + bus1=nodes[name] + " urban central heat", + bus2="co2 atmosphere", + carrier="urban central gas CHP heat", + p_nom_extendable=True, + marginal_cost=costs.at['central gas CHP','VOM'], + efficiency=costs.at['central gas CHP','efficiency']/costs.at['central gas CHP','c_v'], + efficiency2=costs.at['gas','CO2 intensity']) + + network.madd("Link", + nodes[name] + " urban central gas CHP CCS electric", + bus0="EU gas", + bus1=nodes[name], bus2="co2 atmosphere", bus3="co2 stored", + carrier="urban central gas CHP CCS electric", + p_nom_extendable=True, + capital_cost=costs.at['central gas CHP CCS','fixed']*costs.at['central gas CHP CCS','efficiency'], + marginal_cost=costs.at['central gas CHP CCS','VOM'], + efficiency=costs.at['central gas CHP CCS','efficiency'], efficiency2=costs.at['gas','CO2 intensity']*(1-options["ccs_fraction"]), efficiency3=costs.at['gas','CO2 intensity']*options["ccs_fraction"], - carrier="gas to central CHP", - p_nom_extendable=True) + c_b=costs.at['central gas CHP CCS','c_b'], + c_v=costs.at['central gas CHP CCS','c_v'], + p_nom_ratio=costs.at['central gas CHP CCS','p_nom_ratio']) network.madd("Link", - nodes[name] + " urban central CHP electric", - bus0=nodes[name] + " urban central CHP", - bus1=nodes[name], - 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", - nodes[name] + " urban central CHP heat", - bus0=nodes[name] + " urban central CHP", + nodes[name] + " urban central gas CHP CCS heat", + bus0="EU gas", bus1=nodes[name] + " urban central heat", - carrier="urban central CHP heat", + bus2="co2 atmosphere", + bus3="co2 stored", + carrier="urban central gas CHP CCS heat", p_nom_extendable=True, - efficiency=options['chp_parameters']['eta_elec']/options['chp_parameters']['c_v']) + marginal_cost=costs.at['central gas CHP CCS','VOM'], + efficiency=costs.at['central gas CHP CCS','efficiency']/costs.at['central gas CHP CCS','c_v'], + efficiency2=costs.at['gas','CO2 intensity']*(1-options["ccs_fraction"]), + efficiency3=costs.at['gas','CO2 intensity']*options["ccs_fraction"]) + else: network.madd("Link", - nodes[name] + " " + name + " micro CHP", + nodes[name] + " " + name + " micro gas CHP", p_nom_extendable=True, - bus0=["EU gas"]*len(nodes[name]), + bus0="EU gas", bus1=nodes[name], bus2=nodes[name] + " " + name + " heat", bus3="co2 atmosphere", - carrier=name + " micro CHP", + carrier=name + " micro gas CHP", efficiency=costs.at['micro CHP','efficiency'], efficiency2=costs.at['micro CHP','efficiency-heat'], efficiency3=costs.at['gas','CO2 intensity'], @@ -1028,20 +1053,61 @@ def add_biomass(network): #AC buses with district heating urban_central = n.buses.index[n.buses.carrier == "urban central heat"] - if not urban_central.empty: + if not urban_central.empty and options["chp"]: urban_central = urban_central.str[:-len(" urban central heat")] - #with BECCS network.madd("Link", - urban_central + " solid biomass to urban central CHP", + urban_central + " urban central solid biomass CHP electric", bus0="EU solid biomass", - bus1=urban_central + " urban central CHP", + bus1=urban_central, + carrier="urban central solid biomass CHP electric", + p_nom_extendable=True, + capital_cost=costs.at['central solid biomass CHP','fixed']*costs.at['central solid biomass CHP','efficiency'], + marginal_cost=costs.at['central solid biomass CHP','VOM'], + efficiency=costs.at['central solid biomass CHP','efficiency'], + c_b=costs.at['central solid biomass CHP','c_b'], + c_v=costs.at['central solid biomass CHP','c_v'], + p_nom_ratio=costs.at['central solid biomass CHP','p_nom_ratio']) + + + network.madd("Link", + urban_central + " urban central solid biomass CHP heat", + bus0="EU solid biomass", + bus1=urban_central + " urban central heat", + carrier="urban central solid biomass CHP heat", + p_nom_extendable=True, + marginal_cost=costs.at['central solid biomass CHP','VOM'], + efficiency=costs.at['central solid biomass CHP','efficiency']/costs.at['central solid biomass CHP','c_v']) + + network.madd("Link", + urban_central + " urban central solid biomass CHP CCS electric", + bus0="EU solid biomass", + bus1=urban_central, bus2="co2 atmosphere", bus3="co2 stored", + carrier="urban central solid biomass CHP CCS electric", + p_nom_extendable=True, + capital_cost=costs.at['central solid biomass CHP CCS','fixed']*costs.at['central solid biomass CHP CCS','efficiency'], + marginal_cost=costs.at['central solid biomass CHP CCS','VOM'], + efficiency=costs.at['central solid biomass CHP CCS','efficiency'], 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) + c_b=costs.at['central solid biomass CHP','c_b'], + c_v=costs.at['central solid biomass CHP','c_v'], + p_nom_ratio=costs.at['central solid biomass CHP','p_nom_ratio']) + + network.madd("Link", + urban_central + " urban central solid biomass CHP CCS heat", + bus0="EU solid biomass", + bus1=urban_central + " urban central heat", + bus2="co2 atmosphere", + bus3="co2 stored", + carrier="urban central solid biomass CHP CCS heat", + p_nom_extendable=True, + marginal_cost=costs.at['central solid biomass CHP CCS','VOM'], + efficiency=costs.at['central solid biomass CHP CCS','efficiency']/costs.at['central solid biomass CHP CCS','c_v'], + efficiency2=-costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"], + efficiency3=costs.at['solid biomass','CO2 intensity']*options["ccs_fraction"]) def add_industry(network): diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 88f5cabc..512e4fc7 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -126,53 +126,43 @@ def add_battery_constraints(n): link_p_nom = get_var(n, "Link", "p_nom") lhs = linexpr((1,link_p_nom[nodes + " charger"]), - (-n.links.loc[nodes + " charger", "efficiency"], + (-n.links.loc[nodes + " discharger", "efficiency"], link_p_nom[nodes + " discharger"].values)) define_constraints(n, lhs, "=", 0, 'Link', 'charger_ratio') def add_chp_constraints(n): + electric = n.links.index[n.links.index.str.contains("urban central") & n.links.index.str.contains("CHP") & n.links.index.str.contains("electric")] + heat = n.links.index[n.links.index.str.contains("urban central") & n.links.index.str.contains("CHP") & n.links.index.str.contains("heat")] - options = { "chp_parameters" : { 'eta_elec' : 0.468, #electrical efficiency with no heat output - 'c_v' : 0.15, #loss of fuel for each addition of heat - 'c_m' : 0.75, #backpressure ratio - 'p_nom_ratio' : 1., #ratio of max heat output to max electrical output - }} - - if hasattr(n.links.index,"str") and n.links.index.str.contains("CHP").any(): - - #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")] + if not electric.empty: link_p_nom = get_var(n, "Link", "p_nom") - #chp_nom - lhs = linexpr((n.links.loc[urban_central + " urban central CHP electric","efficiency"] - *options['chp_parameters']['p_nom_ratio'], - link_p_nom[urban_central + " urban central CHP electric"]), - (-n.links.loc[urban_central + " urban central CHP heat","efficiency"].values - *options['chp_parameters']['p_nom_ratio'], - link_p_nom[urban_central + " urban central CHP heat"].values)) + #ratio of output heat to electricity set by p_nom_ratio + lhs = linexpr((n.links.loc[electric,"efficiency"] + *n.links.loc[electric,'p_nom_ratio'], + link_p_nom[electric]), + (-n.links.loc[heat,"efficiency"].values, + link_p_nom[heat].values)) define_constraints(n, lhs, "=", 0, 'chplink', 'fix_p_nom_ratio') link_p = get_var(n, "Link", "p") #backpressure - lhs = linexpr((options['chp_parameters']['c_m'] - *n.links.loc[urban_central + " urban central CHP heat","efficiency"], - link_p[urban_central + " urban central CHP heat"]), - (-n.links.loc[urban_central + " urban central CHP electric","efficiency"].values, - link_p[urban_central + " urban central CHP electric"].values)) + lhs = linexpr((n.links.loc[electric,'c_b'].values + *n.links.loc[heat,"efficiency"], + link_p[heat]), + (-n.links.loc[electric,"efficiency"].values, + link_p[electric].values)) define_constraints(n, lhs, "<=", 0, 'chplink', 'backpressure') #top_iso_fuel_line - lhs = linexpr((1,link_p[urban_central + " urban central CHP heat"]), - (1,link_p[urban_central + " urban central CHP electric"].values), - (-1,link_p_nom[urban_central + " urban central CHP electric"].values)) + lhs = linexpr((1,link_p[heat]), + (1,link_p[electric].values), + (-1,link_p_nom[electric].values)) define_constraints(n, lhs, "<=", 0, 'chplink', 'top_iso_fuel_line')