|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
|
|
from ecologits.impacts.modeling import Impacts, Energy, GWP, ADPe, PE
|
|
|
|
|
|
from pint import UnitRegistry, Quantity
|
|
|
|
|
|
|
|
|
|
|
|
u = UnitRegistry()
|
|
u.define("Wh = watt_hour")
|
|
u.define("kWh = kilowatt_hour")
|
|
u.define("MWh = megawatt_hour")
|
|
u.define("GWh = gigawatt_hour")
|
|
u.define("TWh = terawatt_hour")
|
|
u.define("gCO2eq = gram")
|
|
u.define("kgCO2eq = kilogram")
|
|
u.define("tCO2eq = metricton")
|
|
u.define("kgSbeq = kilogram")
|
|
u.define("kJ = kilojoule")
|
|
u.define("MJ = megajoule")
|
|
u.define("m = meter")
|
|
u.define("km = kilometer")
|
|
u.define("s = second")
|
|
u.define("min = minute")
|
|
u.define("h = hour")
|
|
q = u.Quantity
|
|
|
|
|
|
@dataclass
|
|
class QImpacts:
|
|
energy: Quantity
|
|
gwp: Quantity
|
|
adpe: Quantity
|
|
pe: Quantity
|
|
|
|
|
|
class PhysicalActivity(str, Enum):
|
|
RUNNING = "running"
|
|
WALKING = "walking"
|
|
|
|
|
|
class EnergyProduction(str, Enum):
|
|
NUCLEAR = "nuclear"
|
|
WIND = "wind"
|
|
|
|
|
|
COUNTRIES = [
|
|
("cook_islands", 38.81, 9_556),
|
|
("tonga", 51.15, 104_490),
|
|
("comoros", 100, 821_632),
|
|
("samoa", 100, 821_632),
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RUNNING_ENERGY_EQ = q("294 kJ / km")
|
|
WALKING_ENERGY_EQ = q("196 kJ / km")
|
|
|
|
|
|
|
|
EV_ENERGY_EQ = q("0.17 kWh / km")
|
|
|
|
|
|
STREAMING_GWP_EQ = q("15.6 h / kgCO2eq")
|
|
|
|
|
|
ONE_PERCENT_WORLD_POPULATION = 80_000_000
|
|
|
|
DAYS_IN_YEAR = 365
|
|
|
|
|
|
|
|
YEARLY_NUCLEAR_ENERGY_EQ = q("6 TWh")
|
|
|
|
|
|
|
|
YEARLY_WIND_ENERGY_EQ = q("4.2 GWh")
|
|
|
|
|
|
|
|
YEARLY_IRELAND_ELECTRICITY_CONSUMPTION = q("33 TWh")
|
|
IRELAND_POPULATION_MILLION = 5
|
|
|
|
|
|
AIRPLANE_PARIS_NYC_GWP_EQ = q("177000 kgCO2eq")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_energy(energy: Energy) -> Quantity:
|
|
val = q(energy.value, energy.unit)
|
|
if val < q("1 kWh"):
|
|
val = val.to("Wh")
|
|
return val
|
|
|
|
|
|
def format_gwp(gwp: GWP) -> Quantity:
|
|
val = q(gwp.value, gwp.unit)
|
|
if val < q("1 kgCO2eq"):
|
|
val = val.to("gCO2eq")
|
|
return val
|
|
|
|
|
|
def format_adpe(adpe: ADPe) -> Quantity:
|
|
return q(adpe.value, adpe.unit)
|
|
|
|
|
|
def format_pe(pe: PE) -> Quantity:
|
|
val = q(pe.value, pe.unit)
|
|
if val < q("1 MJ"):
|
|
val = val.to("kJ")
|
|
return val
|
|
|
|
|
|
def format_impacts(impacts: Impacts) -> QImpacts:
|
|
try:
|
|
impacts.energy.value = (impacts.energy.value.max + impacts.energy.value.min) / 2
|
|
impacts.gwp.value = (impacts.gwp.value.max + impacts.gwp.value.min) / 2
|
|
impacts.adpe.value = (impacts.adpe.value.max + impacts.adpe.value.min) / 2
|
|
impacts.pe.value = (impacts.pe.value.max + impacts.pe.value.min) / 2
|
|
return (
|
|
QImpacts(
|
|
energy=format_energy(impacts.energy),
|
|
gwp=format_gwp(impacts.gwp),
|
|
adpe=format_adpe(impacts.adpe),
|
|
pe=format_pe(impacts.pe),
|
|
),
|
|
impacts.usage,
|
|
impacts.embodied,
|
|
)
|
|
except:
|
|
return (
|
|
QImpacts(
|
|
energy=format_energy(impacts.energy),
|
|
gwp=format_gwp(impacts.gwp),
|
|
adpe=format_adpe(impacts.adpe),
|
|
pe=format_pe(impacts.pe),
|
|
),
|
|
impacts.usage,
|
|
impacts.embodied,
|
|
)
|
|
|
|
|
|
def split_impacts_u_e(impacts: Impacts) -> QImpacts:
|
|
return impacts.usage, impacts.embodied
|
|
|
|
|
|
def average_range_impacts(x):
|
|
if isinstance(x, float):
|
|
return x
|
|
else:
|
|
return (x.max + x.min) / 2
|
|
|
|
|
|
def format_impacts_expert(impacts: Impacts, display_range: bool) -> QImpacts:
|
|
if display_range:
|
|
return (
|
|
QImpacts(
|
|
energy=format_energy(impacts.energy),
|
|
gwp=format_gwp(impacts.gwp),
|
|
adpe=format_adpe(impacts.adpe),
|
|
pe=format_pe(impacts.pe),
|
|
),
|
|
impacts.usage,
|
|
impacts.embodied,
|
|
)
|
|
|
|
else:
|
|
energy = {
|
|
"value": (impacts.energy.value.max + impacts.energy.value.min) / 2,
|
|
"unit": impacts.energy.unit,
|
|
}
|
|
gwp = (impacts.gwp.value.max + impacts.gwp.value.min) / 2
|
|
adpe = (impacts.adpe.value.max + impacts.adpe.value.min) / 2
|
|
pe = (impacts.pe.value.max + impacts.pe.value.min) / 2
|
|
return (
|
|
QImpacts(
|
|
energy=format_energy(energy),
|
|
gwp=format_gwp(gwp),
|
|
adpe=format_adpe(adpe),
|
|
pe=format_pe(pe),
|
|
),
|
|
impacts.usage,
|
|
impacts.embodied,
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_energy_eq_physical_activity(
|
|
energy: Quantity,
|
|
) -> tuple[PhysicalActivity, Quantity]:
|
|
energy = energy.to("kJ")
|
|
running_eq = energy / RUNNING_ENERGY_EQ
|
|
if running_eq > q("1 km"):
|
|
return PhysicalActivity.RUNNING, running_eq
|
|
|
|
walking_eq = energy / WALKING_ENERGY_EQ
|
|
if walking_eq < q("1 km"):
|
|
walking_eq = walking_eq.to("meter")
|
|
return PhysicalActivity.WALKING, walking_eq
|
|
|
|
|
|
def format_energy_eq_electric_vehicle(energy: Quantity) -> Quantity:
|
|
energy = energy.to("kWh")
|
|
ev_eq = energy / EV_ENERGY_EQ
|
|
if ev_eq < q("1 km"):
|
|
ev_eq = ev_eq.to("meter")
|
|
return ev_eq
|
|
|
|
|
|
def format_gwp_eq_streaming(gwp: Quantity) -> Quantity:
|
|
gwp = gwp.to("kgCO2eq")
|
|
streaming_eq = gwp * STREAMING_GWP_EQ
|
|
if streaming_eq < q("1 h"):
|
|
streaming_eq = streaming_eq.to("min")
|
|
if streaming_eq < q("1 min"):
|
|
streaming_eq = streaming_eq.to("s")
|
|
return streaming_eq
|
|
|
|
|
|
def format_energy_eq_electricity_production(
|
|
energy: Quantity,
|
|
) -> tuple[EnergyProduction, Quantity]:
|
|
electricity_eq = energy * ONE_PERCENT_WORLD_POPULATION * DAYS_IN_YEAR
|
|
electricity_eq = electricity_eq.to("TWh")
|
|
if electricity_eq > YEARLY_NUCLEAR_ENERGY_EQ:
|
|
return EnergyProduction.NUCLEAR, electricity_eq / YEARLY_NUCLEAR_ENERGY_EQ
|
|
electricity_eq = electricity_eq.to("GWh")
|
|
return EnergyProduction.WIND, electricity_eq / YEARLY_WIND_ENERGY_EQ
|
|
|
|
|
|
def format_energy_eq_electricity_consumption_ireland(energy: Quantity) -> Quantity:
|
|
electricity_eq = energy * ONE_PERCENT_WORLD_POPULATION * DAYS_IN_YEAR
|
|
electricity_eq = electricity_eq.to("TWh")
|
|
return electricity_eq / YEARLY_IRELAND_ELECTRICITY_CONSUMPTION
|
|
|
|
|
|
def format_gwp_eq_airplane_paris_nyc(gwp: Quantity) -> Quantity:
|
|
gwp_eq = gwp * ONE_PERCENT_WORLD_POPULATION * DAYS_IN_YEAR
|
|
gwp_eq = gwp_eq.to("kgCO2eq")
|
|
return (
|
|
gwp_eq / AIRPLANE_PARIS_NYC_GWP_EQ
|
|
)
|
|
|