add geographical resolution to oil and methanol for options['co2_budget_national'] to include all necessary links in national co2 budget constraints

This commit is contained in:
chrstphtrs 2023-10-24 16:46:58 +02:00
parent 7cb677d0e6
commit e2b2eafbc1
2 changed files with 106 additions and 83 deletions

View File

@ -303,7 +303,7 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
else: else:
bus0 = vars(spatial)[carrier[generator]].nodes bus0 = vars(spatial)[carrier[generator]].nodes
if "EU" not in vars(spatial)[carrier[generator]].locations: if "EU" not in vars(spatial)[carrier[generator]].locations:
bus0 = bus0.intersection(capacity.index + " gas") bus0 = bus0.intersection(capacity.index + " " + carrier[generator])
# check for missing bus # check for missing bus
missing_bus = pd.Index(bus0).difference(n.buses.index) missing_bus = pd.Index(bus0).difference(n.buses.index)

View File

@ -128,13 +128,33 @@ def define_spatial(nodes, options):
# methanol # methanol
spatial.methanol = SimpleNamespace() spatial.methanol = SimpleNamespace()
spatial.methanol.nodes = ["EU methanol"]
spatial.methanol.locations = ["EU"] if options["co2_budget_national"]:
spatial.methanol.nodes = nodes + " methanol"
spatial.methanol.locations = nodes
spatial.methanol.shipping = nodes + " shipping methanol"
else:
spatial.methanol.nodes = ["EU methanol"]
spatial.methanol.locations = ["EU"]
spatial.methanol.shipping = ["EU shipping methanol"]
# oil # oil
spatial.oil = SimpleNamespace() spatial.oil = SimpleNamespace()
spatial.oil.nodes = ["EU oil"]
spatial.oil.locations = ["EU"] if options["co2_budget_national"]:
spatial.oil.nodes = nodes + " oil"
spatial.oil.locations = nodes
spatial.oil.naphtha = nodes + " naphtha for industry"
spatial.oil.kerosene = nodes + " kerosene for aviation"
spatial.oil.shipping = nodes + " shipping oil"
spatial.oil.agriculture_machinery = nodes + " agriculture machinery oil"
else:
spatial.oil.nodes = ["EU oil"]
spatial.oil.locations = ["EU"]
spatial.oil.naphtha = ["EU naphtha for industry"]
spatial.oil.kerosene = ["EU kerosene for aviation"]
spatial.oil.shipping = ["EU shipping oil"]
spatial.oil.agriculture_machinery = ["EU agriculture machinery oil"]
spatial.oil.land_transport = nodes + " land transport oil" spatial.oil.land_transport = nodes + " land transport oil"
# uranium # uranium
@ -2613,34 +2633,34 @@ def add_industry(n, costs):
efficiency = ( efficiency = (
options["shipping_oil_efficiency"] / options["shipping_methanol_efficiency"] options["shipping_oil_efficiency"] / options["shipping_methanol_efficiency"]
) )
p_set_methanol = shipping_methanol_share * p_set.sum() * efficiency
n.add( # need to aggregate potentials if methanol not nodally resolved
if options["co2_budget_national"]:
p_set_methanol = shipping_methanol_share * p_set * efficiency
else:
p_set_methanol = shipping_methanol_share * p_set.sum() * efficiency
n.madd(
"Bus", "Bus",
"EU shipping methanol", spatial.methanol.shipping,
location="EU", location=spatial.methanol.locations,
carrier="shipping methanol", carrier="shipping methanol",
unit="MWh_LHV", unit="MWh_LHV",
) )
n.add( n.madd(
"Load", "Load",
"shipping methanol", spatial.methanol.shipping,
bus="EU shipping methanol", bus=spatial.methanol.shipping,
carrier="shipping methanol", carrier="shipping methanol",
p_set=p_set_methanol, p_set=p_set_methanol,
) )
if len(spatial.methanol.nodes) == 1:
link_names = ["EU shipping methanol"]
else:
link_names = nodes + " shipping methanol"
n.madd( n.madd(
"Link", "Link",
link_names, spatial.methanol.shipping,
bus0=spatial.methanol.nodes, bus0=spatial.methanol.nodes,
bus1="EU shipping methanol", bus1=spatial.methanol.shipping,
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier="shipping methanol", carrier="shipping methanol",
p_nom_extendable=True, p_nom_extendable=True,
@ -2678,34 +2698,33 @@ def add_industry(n, costs):
) )
if shipping_oil_share: if shipping_oil_share:
p_set_oil = shipping_oil_share * p_set.sum() # need to aggregate potentials if oil not nodally resolved
if options["co2_budget_national"]:
p_set_oil = shipping_oil_share * p_set
else:
p_set_oil = shipping_oil_share * p_set.sum()
n.add( n.madd(
"Bus", "Bus",
"EU shipping oil", spatial.oil.shipping,
location="EU", location=spatial.oil.locations,
carrier="shipping oil", carrier="shipping oil",
unit="MWh_LHV", unit="MWh_LHV",
) )
n.add( n.madd(
"Load", "Load",
"shipping oil", spatial.oil.shipping,
bus="EU shipping oil", bus=spatial.oil.shipping,
carrier="shipping oil", carrier="shipping oil",
p_set=p_set_oil, p_set=p_set_oil,
) )
if len(spatial.oil.nodes) == 1:
link_names = ["EU shipping oil"]
else:
link_names = nodes + " shipping oil"
n.madd( n.madd(
"Link", "Link",
link_names, spatial.oil.shipping,
bus0=spatial.oil.nodes, bus0=spatial.oil.nodes,
bus1="EU shipping oil", bus1=spatial.oil.shipping,
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier="shipping oil", carrier="shipping oil",
p_nom_extendable=True, p_nom_extendable=True,
@ -2761,34 +2780,33 @@ def add_industry(n, costs):
# NB: CO2 gets released again to atmosphere when plastics decay # NB: CO2 gets released again to atmosphere when plastics decay
# except for the process emissions when naphtha is used for petrochemicals, which can be captured with other industry process emissions # except for the process emissions when naphtha is used for petrochemicals, which can be captured with other industry process emissions
# convert process emissions from feedstock from MtCO2 to energy demand # convert process emissions from feedstock from MtCO2 to energy demand
p_set = demand_factor * (industrial_demand.loc[nodes, "naphtha"] - industrial_demand.loc[nodes, "process emission from feedstock"] / costs.at["oil", "CO2 intensity"]).sum() / nhours # need to aggregate potentials if oil not nodally resolved
if options["co2_budget_national"]:
p_set = demand_factor * (industrial_demand.loc[nodes, "naphtha"] - industrial_demand.loc[nodes, "process emission from feedstock"] / costs.at["oil", "CO2 intensity"]) / nhours
else:
p_set = demand_factor * (industrial_demand.loc[nodes, "naphtha"] - industrial_demand.loc[nodes, "process emission from feedstock"] / costs.at["oil", "CO2 intensity"]).sum() / nhours
n.add( n.madd(
"Bus", "Bus",
"EU naphtha for industry", spatial.oil.naphtha,
location="EU", location=spatial.oil.locations,
carrier="naphtha for industry", carrier="naphtha for industry",
unit="MWh_LHV", unit="MWh_LHV",
) )
n.add( n.madd(
"Load", "Load",
"naphtha for industry", spatial.oil.naphtha,
bus="EU naphtha for industry", bus=spatial.oil.naphtha,
carrier="naphtha for industry", carrier="naphtha for industry",
p_set=p_set, p_set=p_set,
) )
if len(spatial.oil.nodes) == 1:
link_names = ["EU naphtha for industry"]
else:
link_names = nodes + " naphtha for industry"
n.madd( n.madd(
"Link", "Link",
link_names, spatial.oil.naphtha,
bus0=spatial.oil.nodes, bus0=spatial.oil.nodes,
bus1="EU naphtha for industry", bus1=spatial.oil.naphtha,
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier="naphtha for industry", carrier="naphtha for industry",
p_nom_extendable=True, p_nom_extendable=True,
@ -2797,42 +2815,47 @@ def add_industry(n, costs):
# aviation # aviation
demand_factor = options.get("aviation_demand_factor", 1) demand_factor = options.get("aviation_demand_factor", 1)
all_aviation = ["total international aviation", "total domestic aviation"]
p_set = (
demand_factor
* pop_weighted_energy_totals.loc[nodes, all_aviation].sum(axis=1).sum()
* 1e6
/ nhours
)
if demand_factor != 1: if demand_factor != 1:
logger.warning(f"Changing aviation demand by {demand_factor*100-100:+.2f}%.") logger.warning(f"Changing aviation demand by {demand_factor*100-100:+.2f}%.")
n.add( all_aviation = ["total international aviation", "total domestic aviation"]
# need to aggregate potentials if oil not nodally resolved
if options["co2_budget_national"]:
p_set = (
demand_factor
* pop_weighted_energy_totals.loc[nodes, all_aviation].sum(axis=1)
* 1e6
/ nhours
)
else:
p_set = (
demand_factor
* pop_weighted_energy_totals.loc[nodes, all_aviation].sum(axis=1).sum()
* 1e6
/ nhours
)
n.madd(
"Bus", "Bus",
"EU kerosene for aviation", spatial.oil.kerosene,
location="EU", location=spatial.oil.locations,
carrier="kerosene for aviation", carrier="kerosene for aviation",
unit="MWh_LHV", unit="MWh_LHV",
) )
n.add( n.madd(
"Load", "Load",
"kerosene for aviation", spatial.oil.kerosene,
bus="EU kerosene for aviation", bus=spatial.oil.kerosene,
carrier="kerosene for aviation", carrier="kerosene for aviation",
p_set=p_set, p_set=p_set,
) )
if len(spatial.oil.nodes) == 1:
link_names = ["EU kerosene for aviation"]
else:
link_names = nodes + " kerosene for aviation"
n.madd( n.madd(
"Link", "Link",
link_names, spatial.oil.kerosene,
bus0=spatial.oil.nodes, bus0=spatial.oil.nodes,
bus1="EU kerosene for aviation", bus1=spatial.oil.kerosene,
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier="kerosene for aviation", carrier="kerosene for aviation",
p_nom_extendable=True, p_nom_extendable=True,
@ -3062,7 +3085,7 @@ def add_agriculture(n, costs):
machinery_nodal_energy = pop_weighted_energy_totals.loc[ machinery_nodal_energy = pop_weighted_energy_totals.loc[
nodes, "total agriculture machinery" nodes, "total agriculture machinery"
] ] * 1e6
if electric_share > 0: if electric_share > 0:
efficiency_gain = ( efficiency_gain = (
@ -3079,37 +3102,37 @@ def add_agriculture(n, costs):
p_set=electric_share p_set=electric_share
/ efficiency_gain / efficiency_gain
* machinery_nodal_energy * machinery_nodal_energy
* 1e6
/ nhours, / nhours,
) )
if oil_share > 0: if oil_share > 0:
n.add( # need to aggregate potentials if oil not nodally resolved
if options["co2_budget_national"]:
p_set = oil_share * machinery_nodal_energy / nhours
else:
p_set = oil_share * machinery_nodal_energy.sum() / nhours
n.madd(
"Bus", "Bus",
"EU agriculture machinery oil", spatial.oil.agriculture_machinery,
location="EU", location=spatial.oil.locations,
carrier="agriculture machinery oil", carrier="agriculture machinery oil",
unit="MWh_LHV", unit="MWh_LHV",
) )
n.add( n.madd(
"Load", "Load",
"agriculture machinery oil", spatial.oil.agriculture_machinery,
bus="EU agriculture machinery oil", bus=spatial.oil.agriculture_machinery,
carrier="agriculture machinery oil", carrier="agriculture machinery oil",
p_set=oil_share * machinery_nodal_energy.sum() * 1e6 / nhours, p_set=p_set,
) )
if len(spatial.oil.nodes) == 1:
link_names = ["EU agriculture machinery oil"]
else:
link_names = nodes + " agriculture machinery oil"
n.madd( n.madd(
"Link", "Link",
link_names, spatial.oil.agriculture_machinery,
bus0=spatial.oil.nodes, bus0=spatial.oil.nodes,
bus1="EU agriculture machinery oil", bus1=spatial.oil.agriculture_machinery,
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier="agriculture machinery oil", carrier="agriculture machinery oil",
p_nom_extendable=True, p_nom_extendable=True,