EDIT: I had to repost my answer as there was a typo in my MWE.
Hi Timon,
I myself am quite new to using
PyPSA but I have dealt with this issue recently. However, please take my
solution with a grain of salt - there may be better ways. :)
Assuming
you have one bus for biomass in any node, you can define a variety of
carriers and assign individual emission factors to each of them. In your
model, you can then define the different generators that use these
different carriers and connect them all to the same biomass bus. PyPSA
then sorts out the usage of the individual carriers and the resulting
CO2 emissions according to your model constraints internally.
I
adjusted a MWE for you to try out. It uses a cheaper biomass carrier
with CO2 emissions and a more expensive one that has zero emissions. By
calling "n.generators_t.p" after optimisation, you can see that PyPSA
uses exactly as much of the cheaper carrier as the CO2 emission
constraints allows for.
Hope it helps! Kind regards,
Hannes
--------------------------------------------
import pypsa
import numpy as np
n = pypsa.Network()
n.set_snapshots(np.arange(10))
# note: although you define a specific carrier here,
# pyPSA can handle other carriers on this bus
n.add("Bus", name = "biomass", carrier = "biomass_1")
n.add("Bus", name = "district_heating")
n.add("Carrier",
"biomass_1",
co2_emissions = 0.2
)
n.add("Carrier",
"biomass_2",
co2_emissions = 0
)
n.add("Generator",
"source_biomass_1",
bus="biomass",
carrier="biomass_1",
marginal_cost = 1,
p_nom_extendable = True,
)
n.add("Generator",
"source_biomass_2",
bus="biomass",
carrier="biomass_2",
marginal_cost = 2,
p_nom_extendable = True,
)
# n.add("Load",
# "biomass_demand",
# bus="biomass",
# p_set = 10)
n.add("Load",
"district heating demand",
bus = "district_heating",
p_set = 5)
n.add("Link",
name = "bm_boiler",
carrier = "biomass_1",
bus0 = "biomass",
bus1 = "district_heating",
efficiency = 0.8,
capital_cost = 0,
marginal_cost = 0,
p_nom_extendable = True
)
n.add("GlobalConstraint",
name = "co2 limit",
carrier_attribute = "co2_emissions",
sense = "<=",
constant = 2
)
def calculate_co2_emissions(n):
return n.generators_t.p["source_biomass_2"].sum() * 0.0 + n.generators_t.p["source_biomass_1"].sum() * 0.2
n.optimize()
print("CO2 Emissions: ", calculate_co2_emissions(n))
print(n.generators_t.p)