Skip to content

Commit

Permalink
Add battery update function
Browse files Browse the repository at this point in the history
  • Loading branch information
romainsacchi committed Jul 11, 2024
1 parent 9b7ae8f commit 2448ab2
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 47 deletions.
92 changes: 69 additions & 23 deletions dev/Untitled1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,6 @@
"- Extracting source database\n",
"- Extracting inventories\n",
"- Fetching IAM data\n",
"dict_items([('train, electric', 'ES|Transport|Freight|Rail|Electric'), ('train, diesel-electric', ['ES|Transport|Freight|Rail|Liquids|Fossil', 'ES|Transport|Freight|Rail|Liquids|Biomass']), ('train, fuel cell', 'ES|Transport|Freight|Rail|Liquids|Hydrogen')])\n",
"1113 set()\n",
"1113 set()\n",
"1113 set()\n",
"1113 set()\n",
"1113 set()\n",
"1113 set()\n",
"Done!\n"
]
}
Expand All @@ -112,35 +105,83 @@
{
"cell_type": "code",
"execution_count": 5,
"id": "3e88c655-ddb1-409d-b84f-c2c4e1976542",
"id": "0c80994c-cbac-4143-81ee-1de1531a6f95",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Processing scenarios: 100%|█████████████| 1/1 [01:37<00:00, 97.61s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generate scenario report.\n",
"Report saved under /Users/romain/GitHub/premise/dev/export/scenario_report.\n"
"Done!\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"ndb.generate_scenario_report()"
"ndb.update()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0c80994c-cbac-4143-81ee-1de1531a6f95",
"execution_count": 6,
"id": "3b0e71e7-2fbb-4247-abcf-60ebb1909d4a",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"gearbox, for lorry 201.6\n",
"transmission, for lorry 291.2\n",
"treatment of used lorry, 40 metric ton -1\n",
"market for power distribution unit, for electric passenger car 4\n",
"assembly operation, for lorry 29223.50287857302\n",
"market for converter, for electric passenger car 25\n",
"market for inverter, for electric passenger car 41.19999946653843\n",
"suspension, for lorry 3440\n",
"power electronics, for lorry 265\n",
"tires and wheels, for lorry 1422\n",
"market for battery management system, for Li-ion battery 125.73132358067981\n",
"glider lightweighting 268.7599962415552\n",
"cabin, for lorry 1153\n",
"other components, for electric lorry 1059\n",
"maintenance, lorry 40 metric ton 1\n",
"frame, blanks and saddle, for lorry 5539\n",
"market for electric motor, electric passenger car 600\n",
"market for used Li-ion battery -314.32832768712774\n",
"retarder, for lorry 67.2\n",
"market for battery cell, Li-ion, NMC622 188.597004106448\n",
"heavy duty truck, battery electric, NMC-622 battery, 40t gross weight, long haul 1\n"
]
}
],
"source": [
"ndb.update()"
"from premise.utils import load_database\n",
"ndb.scenarios[0] = load_database(ndb.scenarios[0])\n",
"\n",
"for ds in ndb.scenarios[0][\"database\"]:\n",
" if ds[\"name\"] == \"heavy duty truck, battery electric, NMC-622 battery, 40t gross weight, long haul\":\n",
" for e in ds[\"exchanges\"]:\n",
" print(e[\"name\"], e[\"amount\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"id": "dff4efb1-69ab-4bd5-8d52-4038df180a85",
"metadata": {},
"outputs": [
Expand All @@ -159,24 +200,29 @@
"text": [
"Writing activities to SQLite3 database:\n",
"0% [##############################] 100% | ETA: 00:00:00\n",
"Total time elapsed: 00:00:32\n"
"Total time elapsed: 00:00:28\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Title: Writing activities to SQLite3 database:\n",
" Started: 07/01/2024 17:19:47\n",
" Finished: 07/01/2024 17:20:20\n",
" Total time elapsed: 00:00:32\n",
" CPU %: 94.20\n",
" Memory %: 15.94\n"
" Started: 07/11/2024 21:39:26\n",
" Finished: 07/11/2024 21:39:54\n",
" Total time elapsed: 00:00:28\n",
" CPU %: 92.10\n",
" Memory %: 19.69\n",
"Created database: trspt 4\n",
"Generate scenario report.\n",
"Report saved under /Users/romain/GitHub/premise/dev/export/scenario_report.\n",
"Generate change report.\n",
"Report saved under /Users/romain/GitHub/premise/dev.\n"
]
}
],
"source": [
"ndb.write_db_to_brightway()"
"ndb.write_db_to_brightway(\"trspt 4\")"
]
},
{
Expand Down
42 changes: 27 additions & 15 deletions premise/activity_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,54 +275,66 @@ def generate_transport_map(self, transport_type: str) -> dict:
Rerurns a dictionary with transport type as keys (see below) and
a set of related ecoinvent activities' names as values.
"""
mapping = {}
if transport_type == "car":
return self.generate_sets_from_filters(
get_mapping(filepath=PASSENGER_CARS, var="ecoinvent_aliases")
mapping = self.generate_sets_from_filters(
get_mapping(filepath=PASSENGER_CARS, var="ecoinvent_aliases", model=self.model)
)
elif transport_type == "two-wheeler":
return self.generate_sets_from_filters(
get_mapping(filepath=TWO_WHEELERS, var="ecoinvent_aliases")
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TWO_WHEELERS, var="ecoinvent_aliases", model=self.model)
)
elif transport_type == "bus":
return self.generate_sets_from_filters(
get_mapping(filepath=BUSES, var="ecoinvent_aliases")
mapping = self.generate_sets_from_filters(
get_mapping(filepath=BUSES, var="ecoinvent_aliases", model=self.model)
)
elif transport_type == "truck":
return self.generate_sets_from_filters(
get_mapping(filepath=TRUCKS, var="ecoinvent_aliases")
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TRUCKS, var="ecoinvent_aliases", model=self.model)
)
elif transport_type == "train":
return self.generate_sets_from_filters(
get_mapping(filepath=TRAINS, var="ecoinvent_aliases")
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TRAINS, var="ecoinvent_aliases", model=self.model)
)

# remove empty values
mapping = {key: val for key, val in mapping.items() if len(val) > 0}

return mapping

def generate_vehicle_fuel_map(self, transport_type: str) -> dict:
"""
Filter ecoinvent processes related to transport fuels.
Rerurns a dictionary with transport type as keys (see below) and
a set of related ecoinvent activities' names as values.
"""
mapping = {}
if transport_type == "car":
return self.generate_sets_from_filters(
mapping = self.generate_sets_from_filters(
get_mapping(filepath=PASSENGER_CARS, var="ecoinvent_fuel_aliases")
)
elif transport_type == "two-wheeler":
return self.generate_sets_from_filters(
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TWO_WHEELERS, var="ecoinvent_fuel_aliases")
)
elif transport_type == "bus":
return self.generate_sets_from_filters(
mapping = self.generate_sets_from_filters(
get_mapping(filepath=BUSES, var="ecoinvent_fuel_aliases")
)
elif transport_type == "truck":
return self.generate_sets_from_filters(
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TRUCKS, var="ecoinvent_fuel_aliases")
)
elif transport_type == "train":
return self.generate_sets_from_filters(
mapping = self.generate_sets_from_filters(
get_mapping(filepath=TRAINS, var="ecoinvent_fuel_aliases")
)

# remove empty values
mapping = {key: val for key, val in mapping.items() if len(val) > 0}

return mapping

def generate_sets_from_filters(self, filtr: dict, database=None) -> dict:
"""
Generate a dictionary with sets of activity names for
Expand Down
157 changes: 157 additions & 0 deletions premise/battery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""
module to adjust the battery inputs to reflect progress in
terms of cell energy density.
"""

import yaml

from .logger import create_logger
from .transformation import (
BaseTransformation,
IAMDataCollection,
List,
np,
ws,
)
from .filesystem_constants import DATA_DIR

logger = create_logger("battery")


def load_cell_energy_density():
"""
Load cell energy density data.
"""
with open(DATA_DIR / "battery/energy_density.yaml", "r") as file:
data = yaml.load(file, Loader=yaml.FullLoader)

return {x["ecoinvent_aliases"]["name"]: x["target"] for x in data.values()}


def _update_battery(scenario, version, system_model):
battery = Battery(
database=scenario["database"],
iam_data=scenario["iam data"],
model=scenario["model"],
pathway=scenario["pathway"],
year=scenario["year"],
version=version,
system_model=system_model,
cache=scenario.get("cache"),
index=scenario.get("index"),
)

battery.adjust_battery_mass()

scenario["database"] = battery.database
scenario["index"] = battery.index
scenario["cache"] = battery.cache

return scenario


class Battery(BaseTransformation):
"""
Class that modifies the battery market to reflect progress
in terms of cell energy density.
"""

def __init__(
self,
database: List[dict],
iam_data: IAMDataCollection,
model: str,
pathway: str,
year: int,
version: str,
system_model: str,
cache: dict = None,
index: dict = None,
) -> None:
super().__init__(
database,
iam_data,
model,
pathway,
year,
version,
system_model,
cache,
index,
)
self.system_model = system_model

def adjust_battery_mass(self) -> None:
"""
Adjust vehicle components (e.g., battery).
Adjust the battery mass to reflect progress in battery technology.
Specifically, we adjust the battery mass to reflect progress in
terms of cell energy density.
We leave the density unchanged after 2050.
"""

energy_density = load_cell_energy_density()

filters = [
ws.contains("name", x)
for x in energy_density
]

for ds in ws.get_many(
self.database,
ws.exclude(
ws.either(
*[
ws.contains("name", x)
for x in [
"market for battery",
"battery production",
"battery cell production",
"cell module production",
]
]
)
),
):

for exc in ws.technosphere(
ds, ws.either(*filters)
):
name = [x for x in energy_density if x in exc["name"]][0]

scaling_factor = (
energy_density[name][2020] / np.clip(
np.interp(
self.year,
list(energy_density[name].keys()),
list(energy_density[name].values()),
),
0.1,
0.5
)
)

if "log parameters" not in ds:
ds["log parameters"] = {}

ds["log parameters"]["battery input"] = exc["name"]
ds["log parameters"]["old battery mass"] = exc["amount"]
exc["amount"] *= scaling_factor
ds["log parameters"]["new battery mass"] = exc["amount"]

self.write_log(ds, status="modified")

def write_log(self, dataset, status="created"):
"""
Write log file.
"""

logger.info(
f"{status}|{self.model}|{self.scenario}|{self.year}|"
f"{dataset['name']}|{dataset['location']}|"
f"{dataset.get('log parameters', {}).get('battery input', '')}|"
f"{dataset.get('log parameters', {}).get('old battery mass', '')}|"
f"{dataset.get('log parameters', {}).get('new battery mass', '')}"
)
Loading

0 comments on commit 2448ab2

Please sign in to comment.