From a54517ae4a8d113248b61ee2dffb638424511ded Mon Sep 17 00:00:00 2001 From: romainsacchi Date: Sat, 13 Jul 2024 19:30:46 +0200 Subject: [PATCH] Add cement CCS datasets --- dev/Untitled1.ipynb | 427 +++++++---------- premise/cement.py | 451 +++++++----------- .../lci-carbon-capture.xlsx | Bin 32988 -> 32998 bytes premise/data/utils/logging/reporting.yaml | 4 + 4 files changed, 362 insertions(+), 520 deletions(-) diff --git a/dev/Untitled1.ipynb b/dev/Untitled1.ipynb index e80d539d..d6e9667b 100644 --- a/dev/Untitled1.ipynb +++ b/dev/Untitled1.ipynb @@ -2,63 +2,32 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "id": "5018b7ee-0169-49d7-9455-2f1aea562e9e", - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-12T17:04:00.715857Z", - "start_time": "2024-07-12T17:03:59.205224Z" - } - }, + "metadata": {}, + "outputs": [], "source": [ "from premise import *\n", "from datapackage import Package\n", "import bw2io as bw" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "code", + "execution_count": 2, "id": "0ca27c06-948c-4584-bebe-d505cb72d4f9", - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-12T17:04:01.762440Z", - "start_time": "2024-07-12T17:04:01.531095Z" - } - }, + "metadata": {}, + "outputs": [], "source": [ "import bw2data\n", "bw2data.projects.set_current(\"ei310\")" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "code", + "execution_count": 3, "id": "bee86950-ac96-49e0-8a9c-43920ae26096", - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-12T17:04:06.171795Z", - "start_time": "2024-07-12T17:04:02.324492Z" - } - }, - "source": [ - "ndb = NewDatabase(\n", - " scenarios=[\n", - " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2050},\n", - " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2010},\n", - " #{\"model\":\"image\", \"pathway\":\"SSP2-Base\", \"year\":2020},\n", - " #{\"model\":\"remind\", \"pathway\":\"SSP2-RCP26\", \"year\":2050},\n", - " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2040},\n", - " #{\"model\":\"image\", \"pathway\":\"SSP2-RCP19\", \"year\":2050},\n", - " {\"model\":\"image\", \"pathway\":\"SSP2-RCP26\", \"year\":2050},\n", - " ],\n", - " source_db=\"ecoinvent-3.10-cutoff\", # <-- name of the database in the BW2 project. Must be a string.\n", - " source_version=\"3.10\", # <-- version of ecoinvent. Can be \"3.5\", \"3.6\", \"3.7\" or \"3.8\". Must be a string.\n", - " key=\"tUePmX_S5B8ieZkkM7WUU2CnO8SmShwmAeWK9x2rTFo=\",\n", - " biosphere_name=\"ecoinvent-3.10-biosphere\"\n", - ")" - ], + "metadata": {}, "outputs": [ { "name": "stdout", @@ -105,217 +74,127 @@ ] } ], - "execution_count": 3 + "source": [ + "ndb = NewDatabase(\n", + " scenarios=[\n", + " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2050},\n", + " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2010},\n", + " #{\"model\":\"image\", \"pathway\":\"SSP2-Base\", \"year\":2020},\n", + " #{\"model\":\"remind\", \"pathway\":\"SSP2-Base\", \"year\":2050},\n", + " #{\"model\":\"remind\", \"pathway\":\"SSP2-PkBudg1150\", \"year\":2050},\n", + " {\"model\":\"image\", \"pathway\":\"SSP2-RCP26\", \"year\":2040},\n", + " {\"model\":\"image\", \"pathway\":\"SSP2-RCP26\", \"year\":2060},\n", + " {\"model\":\"image\", \"pathway\":\"SSP2-RCP19\", \"year\":2050},\n", + " #{\"model\":\"image\", \"pathway\":\"SSP2-Base\", \"year\":2050},\n", + " ],\n", + " source_db=\"ecoinvent-3.10-cutoff\", # <-- name of the database in the BW2 project. Must be a string.\n", + " source_version=\"3.10\", # <-- version of ecoinvent. Can be \"3.5\", \"3.6\", \"3.7\" or \"3.8\". Must be a string.\n", + " key=\"tUePmX_S5B8ieZkkM7WUU2CnO8SmShwmAeWK9x2rTFo=\",\n", + " biosphere_name=\"ecoinvent-3.10-biosphere\"\n", + ")" + ] }, { "cell_type": "code", + "execution_count": 4, "id": "0c80994c-cbac-4143-81ee-1de1531a6f95", - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-12T17:04:21.365439Z", - "start_time": "2024-07-12T17:04:06.172553Z" - } - }, - "source": "ndb.update(\"cement\")", + "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Processing scenarios: 0%| | 0/1 [00:00. at 0x3e0545480>,\n", - " {'market for hard coal': {'amount': 0.0354,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 934.56,\n", - " 'fossil CO2': 91.58688},\n", - " 'market for heavy fuel oil': {'amount': 0.0255,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 981.7499999999999,\n", - " 'fossil CO2': 72.55132499999998},\n", - " 'market for light fuel oil': {'amount': 0.000374,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 15.9324,\n", - " 'fossil CO2': 1.0929626399999999},\n", - " 'market for meat and bone meal': {'amount': 0.00961,\n", - " 'biogenic CO2': 11.186232200000003,\n", - " 'energy': 137.42300000000003,\n", - " 'fossil CO2': 0.0},\n", - " 'market for petroleum coke': {'amount': 0.00391,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 122.38300000000001,\n", - " 'fossil CO2': 11.9323425},\n", - " 'market group for natural gas, high pressure': {'amount': 0.00017462,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 6.28632,\n", - " 'fossil CO2': 0.3771792}})\n", - "2832.788501512605\n", - "0.97397502595931\n", - "new 2759.065254297974\n", - "new scaling factor 1.0943280793270356\n", - "WEU 2198.33472\n", - "defaultdict(. at 0x3e0545480>,\n", - " {'market for hard coal': {'amount': 0.0354,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 934.56,\n", - " 'fossil CO2': 91.58688},\n", - " 'market for heavy fuel oil': {'amount': 0.0255,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 981.7499999999999,\n", - " 'fossil CO2': 72.55132499999998},\n", - " 'market for light fuel oil': {'amount': 0.000374,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 15.9324,\n", - " 'fossil CO2': 1.0929626399999999},\n", - " 'market for meat and bone meal': {'amount': 0.00961,\n", - " 'biogenic CO2': 11.186232200000003,\n", - " 'energy': 137.42300000000003,\n", - " 'fossil CO2': 0.0},\n", - " 'market for petroleum coke': {'amount': 0.00391,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 122.38300000000001,\n", - " 'fossil CO2': 11.9323425},\n", - " 'market group for natural gas, high pressure': {'amount': 0.00017462,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 6.28632,\n", - " 'fossil CO2': 0.3771792}})\n", - "2832.788501512605\n", - "0.8335910807752474\n", - "new 2361.3872285835855\n", - "new scaling factor 1.0943280793270356\n", - "WEU 2198.33472\n", - "defaultdict(. at 0x3e05455a0>,\n", - " {'market for hard coal': {'amount': 0.0354,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 934.56,\n", - " 'fossil CO2': 91.58688},\n", - " 'market for heavy fuel oil': {'amount': 0.0255,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 981.7499999999999,\n", - " 'fossil CO2': 72.55132499999998},\n", - " 'market for light fuel oil': {'amount': 0.000374,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 15.9324,\n", - " 'fossil CO2': 1.0929626399999999},\n", - " 'market for meat and bone meal': {'amount': 0.00961,\n", - " 'biogenic CO2': 11.186232200000003,\n", - " 'energy': 137.42300000000003,\n", - " 'fossil CO2': 0.0},\n", - " 'market for petroleum coke': {'amount': 0.00391,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 122.38300000000001,\n", - " 'fossil CO2': 11.9323425},\n", - " 'market group for natural gas, high pressure': {'amount': 0.00017462,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 6.28632,\n", - " 'fossil CO2': 0.3771792}})\n", - "2832.788501512605\n", - "1.0\n", - "new 2832.788501512605\n", - "new scaling factor 1.0943280793270356\n", - "WEU 2198.33472\n", - "defaultdict(. at 0x3a6cb9f30>,\n", - " {'market for hard coal': {'amount': 0.0354,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 934.56,\n", - " 'fossil CO2': 91.58688},\n", - " 'market for heavy fuel oil': {'amount': 0.0255,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 981.7499999999999,\n", - " 'fossil CO2': 72.55132499999998},\n", - " 'market for light fuel oil': {'amount': 0.000374,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 15.9324,\n", - " 'fossil CO2': 1.0929626399999999},\n", - " 'market for meat and bone meal': {'amount': 0.00961,\n", - " 'biogenic CO2': 11.186232200000003,\n", - " 'energy': 137.42300000000003,\n", - " 'fossil CO2': 0.0},\n", - " 'market for petroleum coke': {'amount': 0.00391,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 122.38300000000001,\n", - " 'fossil CO2': 11.9323425},\n", - " 'market group for natural gas, high pressure': {'amount': 0.00017462,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 6.28632,\n", - " 'fossil CO2': 0.3771792}})\n", - "2832.788501512605\n", - "1.0\n", - "new 2832.788501512605\n", - "new scaling factor 1.0943280793270356\n", - "WEU 2198.33472\n", - "defaultdict(. at 0x3e05455a0>,\n", - " {'market for hard coal': {'amount': 0.0354,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 934.56,\n", - " 'fossil CO2': 91.58688},\n", - " 'market for heavy fuel oil': {'amount': 0.0255,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 981.7499999999999,\n", - " 'fossil CO2': 72.55132499999998},\n", - " 'market for light fuel oil': {'amount': 0.000374,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 15.9324,\n", - " 'fossil CO2': 1.0929626399999999},\n", - " 'market for meat and bone meal': {'amount': 0.00961,\n", - " 'biogenic CO2': 11.186232200000003,\n", - " 'energy': 137.42300000000003,\n", - " 'fossil CO2': 0.0},\n", - " 'market for petroleum coke': {'amount': 0.00391,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 122.38300000000001,\n", - " 'fossil CO2': 11.9323425},\n", - " 'market group for natural gas, high pressure': {'amount': 0.00017462,\n", - " 'biogenic CO2': 0.0,\n", - " 'energy': 6.28632,\n", - " 'fossil CO2': 0.3771792}})\n", - "2832.788501512605\n", - "1.0\n", - "new 2832.788501512605\n", - "new scaling factor 1.0943280793270356\n" + "Done!\n", + "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "Processing scenarios: 100%|█████████████| 1/1 [00:15<00:00, 15.19s/it]" + "\n" ] - }, + } + ], + "source": [ + "ndb.update()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d423f5a1-7bd5-4d0e-8e1f-38634dc80d1a", + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Done!\n", - "\n" + "Generate change report.\n", + "Report saved under /Users/romain/GitHub/premise/dev.\n" ] - }, + } + ], + "source": [ + "ndb.generate_change_report()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3b0e71e7-2fbb-4247-abcf-60ebb1909d4a", + "metadata": {}, + "outputs": [ { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "\n" + "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" ] } ], - "execution_count": 4 + "source": [ + "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": 6, "id": "dff4efb1-69ab-4bd5-8d52-4038df180a85", - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-12T15:58:22.511387Z", - "start_time": "2024-07-12T15:44:21.450702Z" - } - }, - "source": "ndb.write_db_to_brightway([\"cement 2050 rcp19\", \"cement 2050 rcp26\"])", + "metadata": {}, "outputs": [ { "name": "stdout", @@ -323,35 +202,87 @@ "text": [ "Write new database(s) to Brightway.\n", "Running all checks...\n", - "Minor anomalies found: check the change report.\n", - "Database cement 2050 rcp19 already exists: it will be overwritten.\n", - "Vacuuming database \n", - "Warning: No valid output stream.\n", + "Minor anomalies found: check the change report.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Writing activities to SQLite3 database:\n", + "0% [##############################] 100% | ETA: 00:00:00\n", + "Total time elapsed: 00:00:41\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Title: Writing activities to SQLite3 database:\n", - " Started: 07/12/2024 17:49:10\n", - " Finished: 07/12/2024 17:49:56\n", - " Total time elapsed: 00:00:45\n", - " CPU %: 94.30\n", - " Memory %: 22.17\n", - "Created database: cement 2050 rcp19\n", + " Started: 07/13/2024 18:54:03\n", + " Finished: 07/13/2024 18:54:45\n", + " Total time elapsed: 00:00:41\n", + " CPU %: 88.20\n", + " Memory %: 12.60\n", + "Created database: cement rcp26 2040\n", "Running all checks...\n", - "Minor anomalies found: check the change report.\n", - "Warning: No valid output stream.\n", + "Minor anomalies found: check the change report.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Writing activities to SQLite3 database:\n", + "0% [##############################] 100% | ETA: 00:00:00\n", + "Total time elapsed: 00:00:52\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Title: Writing activities to SQLite3 database:\n", + " Started: 07/13/2024 19:03:00\n", + " Finished: 07/13/2024 19:03:53\n", + " Total time elapsed: 00:00:52\n", + " CPU %: 89.80\n", + " Memory %: 8.77\n", + "Created database: cement rcp26 2060\n", + "Running all checks...\n", + "Minor anomalies found: check the change report.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Writing activities to SQLite3 database:\n", + "0% [##############################] 100% | ETA: 00:00:00\n", + "Total time elapsed: 00:00:53\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Title: Writing activities to SQLite3 database:\n", - " Started: 07/12/2024 17:54:08\n", - " Finished: 07/12/2024 17:54:56\n", - " Total time elapsed: 00:00:47\n", - " CPU %: 94.60\n", - " Memory %: 22.50\n", - "Created database: cement 2050 rcp26\n", + " Started: 07/13/2024 19:12:37\n", + " Finished: 07/13/2024 19:13:30\n", + " Total time elapsed: 00:00:53\n", + " CPU %: 89.00\n", + " Memory %: 7.57\n", + "Created database: cement rcp19 2\n", "Generate scenario report.\n", - "Report saved under /Users/romain/Github/premise/dev/export/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" + "Report saved under /Users/romain/GitHub/premise/dev.\n" ] } ], - "execution_count": 7 + "source": [ + "ndb.write_db_to_brightway([\"cement rcp26 2040\", \"cement rcp26 2060\", \"cement rcp19 2\"])" + ] }, { "cell_type": "code", @@ -10613,18 +10544,18 @@ "evalue": "Can't pickle local object 'main..'", "output_type": "error", "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[0;32mIn[9], line 31\u001B[0m\n\u001B[1;32m 28\u001B[0m process\u001B[38;5;241m.\u001B[39mjoin()\n\u001B[1;32m 30\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;18m__name__\u001B[39m \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m__main__\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[0;32m---> 31\u001B[0m \u001B[43mmain\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", - "Cell \u001B[0;32mIn[9], line 25\u001B[0m, in \u001B[0;36mmain\u001B[0;34m()\u001B[0m\n\u001B[1;32m 23\u001B[0m process \u001B[38;5;241m=\u001B[39m Process(target\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mlambda\u001B[39;00m: configure_logging(current_process()\u001B[38;5;241m.\u001B[39mpid)\u001B[38;5;241m.\u001B[39minfo(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mThis is an info message from process \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mcurrent_process()\u001B[38;5;241m.\u001B[39mpid\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m.\u001B[39m\u001B[38;5;124m\"\u001B[39m))\n\u001B[1;32m 24\u001B[0m processes\u001B[38;5;241m.\u001B[39mappend(process)\n\u001B[0;32m---> 25\u001B[0m \u001B[43mprocess\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mstart\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 27\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m process \u001B[38;5;129;01min\u001B[39;00m processes:\n\u001B[1;32m 28\u001B[0m process\u001B[38;5;241m.\u001B[39mjoin()\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/process.py:121\u001B[0m, in \u001B[0;36mBaseProcess.start\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 118\u001B[0m \u001B[38;5;28;01massert\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m _current_process\u001B[38;5;241m.\u001B[39m_config\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mdaemon\u001B[39m\u001B[38;5;124m'\u001B[39m), \\\n\u001B[1;32m 119\u001B[0m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mdaemonic processes are not allowed to have children\u001B[39m\u001B[38;5;124m'\u001B[39m\n\u001B[1;32m 120\u001B[0m _cleanup()\n\u001B[0;32m--> 121\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_popen \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_Popen\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 122\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_sentinel \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_popen\u001B[38;5;241m.\u001B[39msentinel\n\u001B[1;32m 123\u001B[0m \u001B[38;5;66;03m# Avoid a refcycle if the target function holds an indirect\u001B[39;00m\n\u001B[1;32m 124\u001B[0m \u001B[38;5;66;03m# reference to the process object (see bpo-30775)\u001B[39;00m\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/context.py:224\u001B[0m, in \u001B[0;36mProcess._Popen\u001B[0;34m(process_obj)\u001B[0m\n\u001B[1;32m 222\u001B[0m \u001B[38;5;129m@staticmethod\u001B[39m\n\u001B[1;32m 223\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_Popen\u001B[39m(process_obj):\n\u001B[0;32m--> 224\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_default_context\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget_context\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mProcess\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_Popen\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprocess_obj\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/context.py:288\u001B[0m, in \u001B[0;36mSpawnProcess._Popen\u001B[0;34m(process_obj)\u001B[0m\n\u001B[1;32m 285\u001B[0m \u001B[38;5;129m@staticmethod\u001B[39m\n\u001B[1;32m 286\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_Popen\u001B[39m(process_obj):\n\u001B[1;32m 287\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mpopen_spawn_posix\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Popen\n\u001B[0;32m--> 288\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mPopen\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprocess_obj\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_spawn_posix.py:32\u001B[0m, in \u001B[0;36mPopen.__init__\u001B[0;34m(self, process_obj)\u001B[0m\n\u001B[1;32m 30\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\u001B[38;5;28mself\u001B[39m, process_obj):\n\u001B[1;32m 31\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_fds \u001B[38;5;241m=\u001B[39m []\n\u001B[0;32m---> 32\u001B[0m \u001B[38;5;28;43msuper\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[38;5;21;43m__init__\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43mprocess_obj\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_fork.py:19\u001B[0m, in \u001B[0;36mPopen.__init__\u001B[0;34m(self, process_obj)\u001B[0m\n\u001B[1;32m 17\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mreturncode \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[1;32m 18\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mfinalizer \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m---> 19\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_launch\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprocess_obj\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_spawn_posix.py:47\u001B[0m, in \u001B[0;36mPopen._launch\u001B[0;34m(self, process_obj)\u001B[0m\n\u001B[1;32m 45\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m 46\u001B[0m reduction\u001B[38;5;241m.\u001B[39mdump(prep_data, fp)\n\u001B[0;32m---> 47\u001B[0m \u001B[43mreduction\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdump\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprocess_obj\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfp\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 48\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n\u001B[1;32m 49\u001B[0m set_spawning_popen(\u001B[38;5;28;01mNone\u001B[39;00m)\n", - "File \u001B[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/reduction.py:60\u001B[0m, in \u001B[0;36mdump\u001B[0;34m(obj, file, protocol)\u001B[0m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mdump\u001B[39m(obj, file, protocol\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[1;32m 59\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m'''Replacement for pickle.dump() using ForkingPickler.'''\u001B[39;00m\n\u001B[0;32m---> 60\u001B[0m \u001B[43mForkingPickler\u001B[49m\u001B[43m(\u001B[49m\u001B[43mfile\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mprotocol\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdump\u001B[49m\u001B[43m(\u001B[49m\u001B[43mobj\u001B[49m\u001B[43m)\u001B[49m\n", - "\u001B[0;31mAttributeError\u001B[0m: Can't pickle local object 'main..'" + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 31\u001b[0m\n\u001b[1;32m 28\u001b[0m process\u001b[38;5;241m.\u001b[39mjoin()\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;18m__name__\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__main__\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m---> 31\u001b[0m \u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[9], line 25\u001b[0m, in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 23\u001b[0m process \u001b[38;5;241m=\u001b[39m Process(target\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mlambda\u001b[39;00m: configure_logging(current_process()\u001b[38;5;241m.\u001b[39mpid)\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThis is an info message from process \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcurrent_process()\u001b[38;5;241m.\u001b[39mpid\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m))\n\u001b[1;32m 24\u001b[0m processes\u001b[38;5;241m.\u001b[39mappend(process)\n\u001b[0;32m---> 25\u001b[0m \u001b[43mprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstart\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m process \u001b[38;5;129;01min\u001b[39;00m processes:\n\u001b[1;32m 28\u001b[0m process\u001b[38;5;241m.\u001b[39mjoin()\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/process.py:121\u001b[0m, in \u001b[0;36mBaseProcess.start\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 118\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m _current_process\u001b[38;5;241m.\u001b[39m_config\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdaemon\u001b[39m\u001b[38;5;124m'\u001b[39m), \\\n\u001b[1;32m 119\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdaemonic processes are not allowed to have children\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 120\u001b[0m _cleanup()\n\u001b[0;32m--> 121\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_popen \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_Popen\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 122\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sentinel \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_popen\u001b[38;5;241m.\u001b[39msentinel\n\u001b[1;32m 123\u001b[0m \u001b[38;5;66;03m# Avoid a refcycle if the target function holds an indirect\u001b[39;00m\n\u001b[1;32m 124\u001b[0m \u001b[38;5;66;03m# reference to the process object (see bpo-30775)\u001b[39;00m\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/context.py:224\u001b[0m, in \u001b[0;36mProcess._Popen\u001b[0;34m(process_obj)\u001b[0m\n\u001b[1;32m 222\u001b[0m \u001b[38;5;129m@staticmethod\u001b[39m\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_Popen\u001b[39m(process_obj):\n\u001b[0;32m--> 224\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_default_context\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_context\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mProcess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_Popen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprocess_obj\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/context.py:288\u001b[0m, in \u001b[0;36mSpawnProcess._Popen\u001b[0;34m(process_obj)\u001b[0m\n\u001b[1;32m 285\u001b[0m \u001b[38;5;129m@staticmethod\u001b[39m\n\u001b[1;32m 286\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_Popen\u001b[39m(process_obj):\n\u001b[1;32m 287\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpopen_spawn_posix\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Popen\n\u001b[0;32m--> 288\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprocess_obj\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_spawn_posix.py:32\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[0;34m(self, process_obj)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, process_obj):\n\u001b[1;32m 31\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_fds \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m---> 32\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mprocess_obj\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_fork.py:19\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[0;34m(self, process_obj)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfinalizer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m---> 19\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_launch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprocess_obj\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/popen_spawn_posix.py:47\u001b[0m, in \u001b[0;36mPopen._launch\u001b[0;34m(self, process_obj)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 46\u001b[0m reduction\u001b[38;5;241m.\u001b[39mdump(prep_data, fp)\n\u001b[0;32m---> 47\u001b[0m \u001b[43mreduction\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdump\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprocess_obj\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfp\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 48\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m 49\u001b[0m set_spawning_popen(\u001b[38;5;28;01mNone\u001b[39;00m)\n", + "File \u001b[0;32m~/anaconda3/envs/premise/lib/python3.10/multiprocessing/reduction.py:60\u001b[0m, in \u001b[0;36mdump\u001b[0;34m(obj, file, protocol)\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdump\u001b[39m(obj, file, protocol\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 59\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m'''Replacement for pickle.dump() using ForkingPickler.'''\u001b[39;00m\n\u001b[0;32m---> 60\u001b[0m \u001b[43mForkingPickler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprotocol\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdump\u001b[49m\u001b[43m(\u001b[49m\u001b[43mobj\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mAttributeError\u001b[0m: Can't pickle local object 'main..'" ] } ], diff --git a/premise/cement.py b/premise/cement.py index 6d04d65d..0343a9b0 100644 --- a/premise/cement.py +++ b/premise/cement.py @@ -9,19 +9,17 @@ import copy import uuid -from collections import defaultdict from .logger import create_logger from .transformation import ( BaseTransformation, - Dict, IAMDataCollection, InventorySet, List, - calculate_input_energy, np, ws, ) +from .export import biosphere_flows_dictionary from .validation import CementValidation logger = create_logger("cement") @@ -121,128 +119,8 @@ def __init__( for v in list(value): self.fuel_map_reverse[v] = key - def fetch_current_energy_details(self, dataset): - # Fetches the current energy consumption per ton of clinker + self.biosphere_dict = biosphere_flows_dictionary(self.version) - d_fuels = defaultdict( - lambda: {"amount": 0, "energy": 0, "fossil CO2": 0, "biogenic CO2": 0} - ) - - for exc in ws.technosphere(dataset): - fuel_name = exc["name"] - - if fuel_name in self.cement_fuels_map["cement, dry feed rotary kiln"]: - fuel_data = self.fuels_specs[self.fuel_map_reverse[fuel_name]] - co2_emission = fuel_data["co2"] - biogenic_share = fuel_data["biogenic_share"] - - # Calculate the energy once for the given exc - input_energy = ( - calculate_input_energy( - fuel_name=exc["name"], - fuel_amount=exc["amount"], - fuel_unit=exc["unit"], - fuels_specs=self.fuels_specs, - fuel_map_reverse=self.fuel_map_reverse, - ) - * 1000 - ) - - # Update the dictionary in one go - d_fuels[fuel_name]["amount"] += exc["amount"] - d_fuels[fuel_name]["energy"] += input_energy - d_fuels[fuel_name]["fossil CO2"] += ( - co2_emission * input_energy * (1 - biogenic_share) - ) - d_fuels[fuel_name]["biogenic CO2"] += ( - co2_emission * input_energy * biogenic_share - ) - - return d_fuels - - def fetch_bio_ratio(self, dataset: dict) -> float: - """ - Return teh ratio between bio and non-bio CO2 emissions - in the dataset. - - :param dataset: clinker production dataset - :return: ratio between bio and non-bio CO2 emissions - """ - - bio_co2 = sum( - e["amount"] - for e in dataset["exchanges"] - if e["name"] == "Carbon dioxide, non-fossil" - ) - non_bio_co2 = sum( - e["amount"] - for e in dataset["exchanges"] - if e["name"] == "Carbon dioxide, fossil" - ) - - return bio_co2 / (bio_co2 + non_bio_co2) - - def rescale_fuel_inputs(self, dataset, scaling_factor, energy_details): - if scaling_factor != 1 and scaling_factor > 0: - for exc in dataset["exchanges"]: - if exc["name"] in self.cement_fuels_map["cement, dry feed rotary kiln"]: - exc["amount"] *= scaling_factor - - # update energy_details - energy_details[exc["name"]]["amount"] *= scaling_factor - energy_details[exc["name"]]["energy"] *= scaling_factor - energy_details[exc["name"]]["fossil CO2"] *= scaling_factor - energy_details[exc["name"]]["biogenic CO2"] *= scaling_factor - - new_energy_input = sum(d["energy"] for d in energy_details.values()) - - dataset["log parameters"].update( - { - "new energy input per ton clinker": new_energy_input, - } - ) - - return dataset - - def rescale_emissions(self, dataset: dict, energy_details: dict) -> dict: - for exc in ws.biosphere(dataset, ws.contains("name", "Carbon dioxide")): - if "non-fossil" in exc["name"].lower(): - dataset["log parameters"].update( - { - "initial biogenic CO2": exc["amount"], - } - ) - # calculate total biogenic CO2 from energy_details - total_biogenic_CO2 = sum( - [d["biogenic CO2"] for d in energy_details.values()] - ) - - exc["amount"] = total_biogenic_CO2 / 1000 - dataset["log parameters"].update( - { - "new biogenic CO2": total_biogenic_CO2 / 1000, - } - ) - else: - # calculate total fossil CO2 from energy_details - total_fossil_CO2 = sum( - [d["fossil CO2"] for d in energy_details.values()] - ) - - dataset["log parameters"].update( - { - "initial fossil CO2": exc["amount"], - } - ) - - # remove 543 kg for calcination - exc["amount"] = 0.543 + (total_fossil_CO2 / 1000) - dataset["log parameters"].update( - { - "new fossil CO2": exc["amount"], - } - ) - return dataset def build_CCS_datasets(self): ccs_datasets = { @@ -369,95 +247,15 @@ def build_clinker_production_datasets(self) -> list: ) for region, dataset in d_act_clinker.items(): - # calculate current thermal energy consumption per kg clinker - energy_details = self.fetch_current_energy_details(dataset) - - current_energy_input_per_ton_clinker = sum( - d["energy"] for d in energy_details.values() - ) - - if region == "WEU": - from pprint import pprint - - print(region, current_energy_input_per_ton_clinker) - pprint(energy_details) - - # fetch the amount of biogenic CO2 emissions - bio_CO2 = sum( - e["amount"] - for e in ws.biosphere( - dataset, ws.contains("name", "Carbon dioxide, non-fossil") - ) - ) - - # back-calculate the amount of waste fuel from - # the biogenic CO2 emissions - # biogenic CO2 / MJ for waste fuel - - waste_fuel_biogenic_co2_emission_factor = ( - self.fuels_specs["waste"]["co2"] - * self.fuels_specs["waste"]["biogenic_share"] - ) - - waste_fuel_fossil_co2_emission_factor = self.fuels_specs["waste"][ - "co2" - ] * (1 - self.fuels_specs["waste"]["biogenic_share"]) - - # energy input of waste fuel in MJ - energy_input_waste_fuel = ( - bio_CO2 / waste_fuel_biogenic_co2_emission_factor - ) - # amount waste fuel, in kg - amount_waste_fuel = ( - energy_input_waste_fuel / self.fuels_specs["waste"]["lhv"] - ) - - # add waste fuel to the energy details - energy_details["market for waste plastic, mixture"] = { - "amount": amount_waste_fuel, - "energy": energy_input_waste_fuel * 1000, - "fossil CO2": waste_fuel_fossil_co2_emission_factor - * energy_input_waste_fuel, - "biogenic CO2": bio_CO2, - } - - # add the waste fuel energy input - # to the total energy input - current_energy_input_per_ton_clinker += ( - energy_input_waste_fuel * 1000 - ) - if region == "WEU": - print(current_energy_input_per_ton_clinker) - - # add the waste fuel input to the dataset - if amount_waste_fuel != 0: - dataset["exchanges"].append( - { - "uncertainty type": 0, - "loc": 0, - "amount": amount_waste_fuel * -1, - "type": "technosphere", - "production volume": 0, - "name": "clinker production", - "unit": "kilogram", - "location": "RoW", - "product": "waste plastic, mixture", - } - ) - if "log parameters" not in dataset: - dataset["log parameters"] = {} - - dataset["log parameters"].update( - { - "initial energy input per ton clinker": current_energy_input_per_ton_clinker, - } - ) + # from Kellenberger at al. 2007, the total energy + # input per ton of clinker is 3.4 GJ/ton clinker + current_energy_input_per_ton_clinker = 3400 # calculate the scaling factor - # the correction factor applied to all fuel/electricity input is - # equal to the ratio fuel/output in the year in question - # divided by the ratio fuel/output in 2020 + # the correction factor applied to hard coal input + # we assume that any fuel use reduction would in priority + # affect hard coal use scaling_factor = 1 / self.find_iam_efficiency_change( data=self.iam_data.cement_efficiencies, @@ -465,20 +263,19 @@ def build_clinker_production_datasets(self) -> list: location=dataset["location"], ) - if region == "WEU": - print(scaling_factor) + new_energy_input_per_ton_clinker = 3400 + + if "log parameters" not in dataset: + dataset["log parameters"] = {} - new_energy_input_per_ton_clinker = 0 + dataset['log parameters']["initial energy input per ton clinker"] = current_energy_input_per_ton_clinker - if not np.isnan(scaling_factor) and scaling_factor > 0.0: + if not np.isnan(scaling_factor): # calculate new thermal energy # consumption per kg clinker new_energy_input_per_ton_clinker = ( current_energy_input_per_ton_clinker * scaling_factor ) - if region == "WEU": - print("new", new_energy_input_per_ton_clinker) - # put a floor value of 3100 kj/kg clinker if new_energy_input_per_ton_clinker < 3100: new_energy_input_per_ton_clinker = 3100 @@ -486,32 +283,56 @@ def build_clinker_production_datasets(self) -> list: elif new_energy_input_per_ton_clinker > 5000: new_energy_input_per_ton_clinker = 5000 + # but if efficient kiln, + # set the energy input to 3000 kJ/kg clinker + if variable.startswith( + "cement, dry feed rotary kiln, efficient" + ): + new_energy_input_per_ton_clinker = 3000 + + dataset['log parameters'][ + "new energy input per ton clinker"] = int(new_energy_input_per_ton_clinker) + scaling_factor = ( new_energy_input_per_ton_clinker / current_energy_input_per_ton_clinker ) - if region == "WEU": - print("new scaling factor", scaling_factor) + dataset['log parameters']["energy scaling factor"] = scaling_factor - # but if efficient kiln, set the energy input to 3100 kJ/kg clinker - if variable.startswith( - "cement, dry feed rotary kiln, efficient" + # rescale hard coal consumption and related emissions + coal_specs = self.fuels_specs["hard coal"] + old_coal_input, new_coal_input = 0, 0 + for exc in ws.technosphere( + dataset, + ws.contains("name", "hard coal"), ): - new_energy_input_per_ton_clinker = 3000 - scaling_factor = ( - new_energy_input_per_ton_clinker - / current_energy_input_per_ton_clinker + # in kJ + old_coal_input = float(exc["amount"] * coal_specs["lhv"]) + # in MJ + new_coal_input = old_coal_input - (( + current_energy_input_per_ton_clinker + - new_energy_input_per_ton_clinker + )/1000) + exc["amount"] = np.clip( + new_coal_input / coal_specs["lhv"], + 0, + None ) - # rescale fuel consumption and emissions - # rescale the fuel and electricity input - dataset = self.rescale_fuel_inputs( - dataset, scaling_factor, energy_details - ) + # rescale combustion-related fossil CO2 emissions + for exc in ws.biosphere( + dataset, + ws.contains("name", "Carbon dioxide"), + ): + if exc["name"] == "Carbon dioxide, fossil": + dataset["log parameters"]["initial fossil CO2"] = exc["amount"] + co2_reduction = (old_coal_input - new_coal_input) * coal_specs["co2"] + exc["amount"] -= co2_reduction + dataset["log parameters"]["new fossil CO2"] = exc["amount"] - # rescale combustion-related CO2 emissions - dataset = self.rescale_emissions(dataset, energy_details) + if exc["name"] == "Carbon dioxide, non-fossil": + dataset["log parameters"]["initial biogenic CO2"] = exc["amount"] # add 0.005 kg/kg clinker of ammonia use for NOx removal # according to Muller et al., 2024 @@ -599,7 +420,7 @@ def build_clinker_production_datasets(self) -> list: variable == "cement, dry feed rotary kiln, efficient, with on-site CCS" ): - # only 90% of process emissions (calcination) are captured + # only 95% of process emissions (calcination) are captured CCS_amount = ( 0.543 * ccs_datasets[variable]["capture share"] ) @@ -608,47 +429,96 @@ def build_clinker_production_datasets(self) -> list: CO2_amount * ccs_datasets[variable]["capture share"] ) - if variable in ccs_datasets: - ccs_exc = { - "uncertainty type": 0, - "loc": CCS_amount, - "amount": CCS_amount, - "type": "technosphere", - "production volume": 0, - "name": ccs_datasets[variable]["name"], - "unit": "kilogram", - "location": dataset["location"], - "product": ccs_datasets[variable][ - "reference product" - ], - } - dataset["exchanges"].append(ccs_exc) - - # Update CO2 exchanges - for exc in dataset["exchanges"]: + dataset["log parameters"][ + 'carbon capture rate' + ] = CCS_amount / CO2_amount + + ccs_exc = { + "uncertainty type": 0, + "loc": CCS_amount, + "amount": CCS_amount, + "type": "technosphere", + "production volume": 0, + "name": ccs_datasets[variable]["name"], + "unit": "kilogram", + "location": dataset["location"], + "product": ccs_datasets[variable][ + "reference product" + ], + } + dataset["exchanges"].append(ccs_exc) + + # Update CO2 exchanges + for exc in ws.biosphere( + dataset, + ws.contains("name", "Carbon dioxide, fossil"), + ): if ( - exc["name"].lower().startswith("carbon dioxide") - and exc["type"] == "biosphere" + variable + != "cement, dry feed rotary kiln, efficient, with on-site CCS" ): exc["amount"] *= ( CO2_amount - CCS_amount ) / CO2_amount - # make sure it's not negative - if exc["amount"] < 0: - exc["amount"] = 0 - - if "non-fossil" in exc["name"].lower(): - dataset["log parameters"].update( - { - "new biogenic CO2": exc["amount"], - } - ) - else: - dataset["log parameters"].update( - { - "new fossil CO2": exc["amount"], - } - ) + else: + exc["amount"] -= CCS_amount + + # make sure it's not negative + if exc["amount"] < 0: + exc["amount"] = 0 + + dataset["log parameters"]["new fossil CO2"] = exc["amount"] + + # Update biogenic CO2 exchanges + if ( + variable + != "cement, dry feed rotary kiln, efficient, with on-site CCS" + ): + for exc in ws.biosphere( + dataset, + ws.contains("name", "Carbon dioxide, non-fossil"), + ): + dataset["log parameters"]["initial biogenic CO2"] = exc["amount"] + exc["amount"] *= ( + CO2_amount - CCS_amount + ) / CO2_amount + + # make sure it's not negative + if exc["amount"] < 0: + exc["amount"] = 0 + + dataset["log parameters"]["new biogenic CO2"] = exc["amount"] + + biogenic_CO2_reduction = ( + dataset["log parameters"]["initial biogenic CO2"] + - dataset["log parameters"]["new biogenic CO2"] + ) + # add a flow of "Carbon dioxide, in air" to reflect + # the permanent storage of biogenic CO2 + dataset["exchanges"].append( + { + "uncertainty type": 0, + "loc": biogenic_CO2_reduction, + "amount": biogenic_CO2_reduction, + "type": "biosphere", + "name": "Carbon dioxide, in air", + "unit": "kilogram", + "categories": ("natural resource", "in air"), + "comment": "Permanent storage of biogenic CO2", + "input": ( + "biosphere3", + self.biosphere_dict[ + ( + "Carbon dioxide, in air", + "natural resource", + "in air", + "kilogram", + ) + ], + ), + } + ) + else: # Carbon capture rate: share of capture of total CO2 emitted carbon_capture_rate = self.get_carbon_capture_rate( @@ -835,6 +705,41 @@ def add_datasets_to_database(self) -> None: # add it to list of created datasets self.add_to_index(new_dataset) + # exclude the regionalization of these datasets + # because they are very rarely used in the database + excluded = [ + "factory", + "tile", + "sulphate", + "plaster", + "Portland Slag", + 'CP II-Z', + 'CP IV', + 'CP V RS', + 'Portland SR3', + 'CEM II/A-S', + 'CEM II/A-V', + 'CEM II/B-L', + 'CEM II/B-S', + 'type I (SM)', + 'type I-PM', + 'type IP/P', + 'type IS', + 'type S', + 'CEM III/C', + 'CEM V/A', + 'CEM V/B', + 'CEM II/A-L', + 'CEM III/B', + 'Pozzolana Portland', + 'ART', + 'type IP', + 'CEM IV/A', + 'CEM IV/B', + 'type ICo', + 'carbon' + ] + # cement markets markets = list( ws.get_many( @@ -842,7 +747,8 @@ def add_datasets_to_database(self) -> None: ws.contains("name", "market for cement"), ws.contains("reference product", "cement"), ws.doesnt_contain_any( - "name", ["factory", "tile", "sulphate", "plaster"] + "name", + excluded, ), ws.doesnt_contain_any("location", self.regions), ) @@ -879,7 +785,7 @@ def add_datasets_to_database(self) -> None: ws.contains("name", "cement production"), ws.contains("reference product", "cement"), ws.doesnt_contain_any( - "name", ["factory", "tile", "sulphate", "plaster", "carbon"] + "name", excluded ), ) ) @@ -919,6 +825,7 @@ def write_log(self, dataset, status="created"): f"{status}|{self.model}|{self.scenario}|{self.year}|" f"{dataset['name']}|{dataset['location']}|" f"{dataset.get('log parameters', {}).get('initial energy input per ton clinker', '')}|" + f"{dataset.get('log parameters', {}).get('energy scaling factor', '')}|" f"{dataset.get('log parameters', {}).get('new energy input per ton clinker', '')}|" f"{dataset.get('log parameters', {}).get('carbon capture rate', '')}|" f"{dataset.get('log parameters', {}).get('initial fossil CO2', '')}|" diff --git a/premise/data/additional_inventories/lci-carbon-capture.xlsx b/premise/data/additional_inventories/lci-carbon-capture.xlsx index d64ba88c37ce861012cbd9b3564f054b6ca7168c..df75871265c11532af1effb845bce6e8cc605d73 100644 GIT binary patch delta 3342 zcmYk9RaBIL7Dk5}U;wG1QKUOXLQ)uzZiZGmMrr_Q<{ugX5g0=0kZwm%Kw4TrN?Jf# zTDotnyY9W`>8y43+xKwxHy?_-9*SGL4kjSW+2e`FY=a*Fg;EqKg{@mWr;}7hY9%~G z6C3M19051ZblcBiBh0d;*~xOtFsiuOm*HY{lPEE)j-z6l>)P;eY!$Uc%}%5qb*8Kv zkWxyYC3eAtNQ82tHn#=53HwH)V#DADwXA^-j3G^zH=hUVjYdd#bMJ#F0%J7n;G#WG zgw3>18Z7})9DdC*1j4#Br}jCoDv6bt;~&UX4&Cnzuh0gfx+et6Lg}(jW#2P1h_M9v zl?C9O_Jcqv~^LdO$&rZiT)(Tat&ivuf{B2C*XC|Xl7knm+`V;p9H~E zOn{H~?P-NHov@-Q->^8U#5&MY=uWvy{Bvjr#e2c4-J218TyCTJt>d3OgnKpPOnsAb zA)((xZ!``!SuZ5uk*);nA`hmo3Kn?#OV4h_N%KTp+2 zq>ziY;otq-?PM3$l7`8Rke_fOrJrn@WJ{a946p8 zK_{pWx2nMpWF7F9T()9U7v53y|yZ4y$;Y}sQ-RG_P@ox~^FSCz@SD5g5OkX>mY zGDw^XLpa6>luU*Yk_)AL<#`uUlE*)N`4+nx|IG=DeXb^SC}Z?vU^xMVQKp%#=47NC zd8;RrGl1)3U^x0?z{`=zyHI;hSsn0<`B|z!AJEe07ani#uE;iW|4nE6Zi!h9@O13( zL#|obv>*IyU66o+Ka|Y#O1!W*RIHw6HoZt1B*w_n*ShqGgV;a8VT zqb)b16FE0yLYtP;IJKJx7xu!=w;U;Uzo>ufw12_s@0sgglg|XVQ)t^hX*HtaLD@Zd zA0$+6=#P)+)bxLV41C4vXZn zrtB?qdtQFIDC4UZ77@|Ob|9tG+AG_+v&9o54MdABB4UZvkJGf6TLwd&4Lc6fYzV+$z_nbJ_K1i1kyS>&>hg7HPHF*JI&!3*N2b16iR*sy|Nll!4Y3sifKE89n zmD%|S5nuKG`&wslOkJy>`@8NBVH`s5I&uMv8#L}00;7D6+VV?CV@OniqR*2~c1bLM zQNz8fSlwN0K$jPP7fv=z16c?Nkur^CLHyZ5-4IkbPLa21}e`@K5HwQZ>*>M&F=8Q(d^jatbooDxAcdK>3GtPX|l zMRrR&JYylR|8>BsW#QiX2;Se*&+vl1uI<6=!}t$f6p<#@I|fp89A9vH69T1r!18~% zW#!pLbCUW+nBPVpP8;hMmdHx<4%+RgQJ}g+Z<7LudU`}N_RBV!Oz9XU$z&VnB;2mn ziVtNUs;ljP&yg7N&P*uY4qB|t5F4vbNcoj(Y-k>+Z{g!Rr?UF&LIH#|Bxh41<`KGp z&fCjmvV)ZQubwAW^`jW(oA*Jn+t<3l%Nar@D7q(si|yB>%k79^g)c%6U3)TE~L6eXs zc2&7kMTgxZj<`q0c`z+68fm&XP9s!+WPBEU{ArP4bvMQLV>Alpq>!6^vC(>m z{ixf*j1P;K%N!6R!Gur_qKmH^3P{%X7KGK<~PBw0K2<5w>fU$dA9N zY%6$8gqDt}e9s6<)i2R3aW>qt>%_6h7DxunwD5@sE*Py25_MRkFqGN4jpxa|mrN-* zF-$F0Q-ZfJ-H0y8&pl0iIx5~ij~FIwGA2GvrkdCZum89q#Xf#yU@hvo2xtCmx~Q67 z%VsL`&+~UTcSp!u2VW*GH{oxagYHXS6KRj4&PMZ7)NbENaf(;zEf5oJ*ip zI10;hx_Y(Tn;^DwI&k#l#8qZe8%zHlQkorq)P1w?;}tz^pcVQ_?0{?(ae2=fR@7*j zS^R-^xD-gG?^+DigCrW% z$k^L+cy+!~$;~YV=jkX(w~ebEo&i286)p%?aC_Dz?T;lG`O_qX=@>t^BCw`MY&T$d ziC92Ek`CXE9M?NKr$3r*$~t-Td+@?yST#U(7muY#Ph20&%0$01gGkjdzkHl&{k4k* zHty40oE9KnFq6M|{i&*sxYa7zdD9D81=-y7o>!_d_(+a%RdjG|3WLBZ0k!E;YEr_n zPXeXO>qzsJDH^@-4Z}uL_8Y^|+3fc(hij?SOeoQj4)XcJ$?^MJP_fZ(MUvWnC9lEl z&%h-v0thho`9w<8$x^WVdryBNa*-wYgY8JN=wc6Pq`4U{`epOS%FGcsr88;5aZ2jJ z$?N;;JmWg4;1EIDG}`(&;5dKOF=J@T7%#e5JH(0$E`Y#hmn+@B|61ykfTfK3sg-l| z+L0!I63y=*PJn^DIV|h1Z3p+8(83yB!-st0u`dl}xKi67m|0bMJ!%rNW1XZ(k#=nd%bf;6rB$7ZDrFI?I)<;(#w1pIIkw0dhvv-wT`=*X?%3 zPC|yLafc(@R=%5d*V&9nBSkwkL$T#Qs6$b&w3QcIiP~ZZO7+|9K~w{YF zDp{E`cmn!Z?sWQY=iryK%~eUXWAK^V76J*F zQ?TnudsOCGRWNN0Vk$*b>@*e++KWd zQor_EhS!^DXfRBIrT7m{m|dx2s4p!hX33)luW%<9uSE>Ww{`kv-zP@KfkZy0Fvw}m z*>z3=F)kl9qI1w$T}&dNhqI4a28?hvFcN5Xrhg}n0|LFo1%W94hyQb9 U!1$o$ak4R3G&|TefANfx_Ovph9HpekI4XJ;N6?^73hkI5kcqgl1j}^Rv5$})D2uQ2ZN(jMw zCt7dM%}2w_B`?|iR=N&dt-jF8W~xL^Nwt~e+^{@C7ci7-_BsJxsd_c4c?qk;3%mis z!@Znul#{b1txGclA-C{g7z6{qXDvY(acP(m)UdG>26VXd>rXY;V2=w43U_~Q*|(Z2 z289Ls0$-t}Sx6W9hMK~uRT&}tRfF?bNn1tuGdD%Oz))iq*KFVC)KE-w2nL9QmUAwi zfv{AZY5YdP^tfDpL&G$)fx!@&E&J{L&rt#=RM_hD#wZ8wuaaxX)g66?%z-}gU149@ z)O6+|Qz4mu?-qgS825w0fFwV_85M+?q_rt_qOi~r z>Vg7}mZo&mt`IM*dHzb{ySKYs+yB(GYd@^R_V~N!Y^`7AV~5V>fs0(O8;@Sv`-=el zTQ>_2JU2yzI-cL%&;8B#V*zYQzu&ioqI}CLLI-S;Et?cB*ER=i@EdkNFio08P+l7Z)rMnTu@C26O3L6Y&Lms+XVcUHKu zdo1616!mfQG^3`5GPM=jj6>U|yV?EZayzk$;6Y`Dw~2LS_w=s}@8F$WvJ;Kd`x6bv zU#7F^iMH31+590r)i|DxlK6D{`1UsbcQ*N_-2(q_Kr!STB-03H9=D$%!~X!2;dK&93?+YCYuhjsejn^V7`?}~Y&T6q(lT1Q74|T;ZhKbb<3z-=JW07R z_TP6T-vWW)HY7T-?C)|e&f?)H%U}=M2vsc!4Pz2O#Z@k<^^*L2eV)unU@WV0R;mh? z{ z@idZ5RHR{;>oFXvC7GQHi^6Ru>96f02*d-9|t zkbM5Ku9Rl067xRNjPc;8@tfc;?PUDQ9ZN&d#|XM&NsB_5XU-am4`$OU%TWff>B zmgEzizoxU8ME46nLB9kX%-KG$Z1n?5;1*DYlEA9^D-`w-$`a8jMGtOfS4wRi_647c zQO09$8hl1@& zI~>l!S(?NtO>X*|-__v@i1o%I1W)~3&GXX}7>`P8 zPN!Ksb=6B4DSz9NU>ryge#J5Vk$J}$JI82#q@L?yQ)t|D@Z`<5Y2Pp03^eqO+0(9h zZZpsfeIJ`uS4KM2kc>)fSyycMZ{ju>|2}E|gOy6t-qOT@q=f^zqiv*#?b?n1rvGK!Kc21Xr726%ST=3 zkK5QicTk~!NIoQ7_mnCGB=Vx`+$%M1dtQ;;(~K0SVoY=R zk_wp-1yeclim{|*Sm;9;_X6LKyo|8iDJitGWE&zGk)I}GHxb#GC^lf6shOeWpe$*> z8|6Zh0S8g1xJeQ;#gPoqRMt$)>I$EXB~lb3Ri{9I*Ar>V61pmG%WHWgSx^GXFQbG* z&kvS#pUM|fYI>4BFzr64*U2YYoT&mOVv?(_b2eW><(GFu@Nv|1Q0bLRF$6o^p`X#o zuO}z|sqf#RH+uS)`)J{Z&l92ExaH5qh1vGo9df*y=MsZ(nE?>K{>AqqZavn)zA z+f9ytv(1XGYFe-C#sbpAwxzb=CPiCowr<#a25Gp-MQfZiUwT4zuZoRcCl&c3L@@Zu zq(u8uF23Zk{su7ufupzeI>q1UfpA#C+I@-OLLvnT4sl~va+1+<$0gxxAer8ll8o_L zxg6*PQxmFv8G{Vfi(bj$5g)Vve?HE?%x(jJ?ZsD$g(Y79wRm`~JhJ%6(V*+ZF;u3y zI2|ZyR~@xd4$zN%F`WJMOup}aY%epeuRO=8XX~l1n#IUeK<#9l&oA&m*I`)bbpY!q zD)Sg7s2bnS#!!WGfMun1&Aw-Lk0hDlAhZs6hGDNW5ON4Gu!au$1}K+$9ZpjP=`Y!T z=wAOSF^0bbp%g%+UT4V2NaTd;ie8_n2B1ztIls|R@y~Qgt7&Q>26NlxN~04!1VyT0 zNw1s${iQ<{jwz4nYk2)JM8;!2)AyPoUd~|aV%9gBFXnGK8|4|b4}6qD(L@=HY_4q2 z)~nRgQn1kg>+P-~nx^Yjwd|wO(gsC;>(jQzCi*r>qT$hAv~XmQ-gBOt>s3njVUi7~ zj7?uqp@=031C4zSOw+QU7I{Cd@o@#z@cd9NZXA%-=G1)TU@L)i839~a<`eoN$@rE| zArnnpded}snrO7VXKfb_ z)=Bc*g@&VD^7)08sC+UwYPGYxh7WnM;Dg4%-q)uo5ETHyTT|O7m0yL))<)h@6AKM( z9~IB?FaR4Mwbel^^$&CWjdbsS*mW*NmJxW$G6)((8cY~hEZ2CtVP3B4KBU_JLBmg8 zAArcV4m?8mAj5FF=w8fMrJtBhUo)2qXbfpeCS2XlKX#qP_;)&FlMK92?fS?bgfb+$ z&SLytH(5B+A_Gu*U%(R_{Gy3uUFYj{|EzU&9S82Y-#>So4H~+wuz%%$hRw_V)m7Z` z1OM`y_0YY?Gq-t{2Xuy;?SjK&xU7_|guhv=bscL`if`IW5Zji$6-55q5c_W2@Uh#B z$hmtSH9|KIac~ti``2L{TC#^Pd=B?LjLV00EqvHkETf#|wXbRq*{k3rm_DI|S9`)+ z{L`cN4*&oF|NjF3P)h@o>U9gVe^#g=1ptJU%uKT^cqRdVUr)mz6vf|7{0a;1Iw4_1>Ys%P8WO$^sTdb&cE5GoK0DgP;Z9X?fcyd>y#{&<1w6rgBQeGx^_vI25 z2}wvuCSfuw<0PHlq*LYPJS%~^V{mX(360E6#~=@lkp51ld*m(0os$?ekL0j zrK?)j1ONa!82|tc0000000000000000B4gOe>wqZlURR20pydKe^3GDlk0y}0p629 yfFm0Kgp|xo0RRAN0ssIJ00000000000000001%UYfIb0}lf8f=24Z~x0000mJ5R9y diff --git a/premise/data/utils/logging/reporting.yaml b/premise/data/utils/logging/reporting.yaml index d5901cf6..b35fd392 100644 --- a/premise/data/utils/logging/reporting.yaml +++ b/premise/data/utils/logging/reporting.yaml @@ -290,6 +290,10 @@ premise_cement: name: Initial energy input per ton clinker description: Energy input per ton clinker before adjustment (kj/kg) unit: kj/kg + energy scaling factor: + name: Energy scaling factor + description: Scaling factor the initial energy input is multiplied by + unit: 0-1 new energy input per ton clinker: name: New energy input per ton clinker after adjustment description: Energy input per ton clinker after (kj/kg)