-{% else %}
-
diff --git a/docs/conf.py b/docs/conf.py
deleted file mode 100644
index bba1044..0000000
--- a/docs/conf.py
+++ /dev/null
@@ -1,259 +0,0 @@
-### path setup ####################################################################################
-
-import datetime
-
-###################################################################################################
-### Project Information ###########################################################################
-###################################################################################################
-
-project = "pulpo"
-author = "Fabian Lechtenberg"
-copyright = datetime.date.today().strftime("%Y") + " pulpo developers"
-version: str = "latest" # required by the version switcher
-
-###################################################################################################
-### Project Configuration #########################################################################
-###################################################################################################
-
-needs_sphinx = "7.3.0"
-
-extensions = [
- # core extensions
- "sphinx.ext.mathjax",
- "sphinx.ext.viewcode",
- "sphinx.ext.intersphinx",
- "sphinx.ext.extlinks",
- "sphinx.ext.inheritance_diagram",
- "sphinx.ext.autosummary",
- "sphinx.ext.napoleon",
- # iPython extensions
- "IPython.sphinxext.ipython_directive",
- "IPython.sphinxext.ipython_console_highlighting",
- # Markdown support
- # 'myst_parser', # do not enable separately if using myst_nb, compare: https://github.com/executablebooks/MyST-NB/issues/421#issuecomment-1164427544
- # Jupyter Notebook support
- "myst_nb",
- # mermaid support
- "sphinxcontrib.mermaid",
- # API documentation support
- "autoapi",
- # responsive web component support
- "sphinx_design",
- # custom 404 page
- "notfound.extension",
- # custom favicons
- "sphinx_favicon",
- # copy button on code blocks
- "sphinx_copybutton",
- # carousels
- "sphinx_carousel.carousel",
-]
-
-autoapi_dirs = ["../pulpo"]
-autoapi_type = "python"
-autoapi_ignore = [
- "*/data/*",
- "*tests/*",
- "*tests.py",
- "*validation.py",
- "*version.py",
- "*.rst",
- "*.yml",
- "*.md",
- "*.json",
- "*.data",
-]
-
-autoapi_options = [
- "members",
- "undoc-members",
- "private-members",
- "show-inheritance",
- "show-module-summary",
- #'special-members',
- #'imported-members',
- "show-inheritance-diagram",
-]
-
-autoapi_python_class_content = "both"
-autoapi_member_order = "bysource"
-autoapi_root = "content/api"
-autoapi_template_dir = "_templates/autoapi_templates/"
-autoapi_keep_files = False
-
-graphviz_output_format = "svg" # https://pydata-sphinx-theme.readthedocs.io/en/stable/examples/graphviz.html#inheritance-diagram
-
-# Inject custom JavaScript to handle theme switching
-mermaid_init_js = """
- function initializeMermaidBasedOnTheme() {
- const theme = document.documentElement.dataset.theme;
-
- if (theme === 'dark') {
- mermaid.initialize({
- startOnLoad: true,
- theme: 'base',
- themeVariables: {
- edgeLabelBackground: 'transparent',
- defaultLinkColor: '#ced6dd',
- titleColor: '#ced6dd',
- nodeTextColor: '#ced6dd',
- lineColor: '#ced6dd',
- }
- });
- } else {
- mermaid.initialize({
- startOnLoad: true,
- theme: 'base',
- themeVariables: {
- edgeLabelBackground: 'transparent',
- defaultLinkColor: '#222832',
- titleColor: '#222832',
- nodeTextColor: '#222832',
- lineColor: '#222832',
- }
- });
- }
-
- // Re-render all Mermaid diagrams
- mermaid.contentLoaded();
- }
-
- // Observer to detect changes to the data-theme attribute
- const themeObserver = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {
- initializeMermaidBasedOnTheme();
- }
- });
- });
-
- themeObserver.observe(document.documentElement, { attributes: true });
-
- initializeMermaidBasedOnTheme();
-"""
-
-master_doc = "index"
-
-root_doc = "index"
-html_static_path = ["_static"]
-templates_path = ["_templates"]
-exclude_patterns = ["_build"]
-html_theme = "pydata_sphinx_theme"
-
-suppress_warnings = [
- "myst.header" # suppress warnings of the kind "WARNING: Non-consecutive header level increase; H1 to H3"
-]
-
-
-####################################################################################################
-### Theme html Configuration #######################################################################
-####################################################################################################
-
-html_show_sphinx = False
-html_show_copyright = True
-
-html_css_files = [
- "custom.css",
- "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css", # for https://fontawesome.com/ icons
-]
-
-html_sidebars = {
- "**": [
- "sidebar-nav-bs.html",
- ],
- "content/index": [],
- "content/installation": [],
- "content/theory": [],
- "content/contributing": [],
- "content/codeofconduct": [],
- "content/license": [],
- "content/changelog": [],
- "content/funding": [],
-}
-
-html_theme_options = {
- # page elements
- # "announcement": "⚠️ placeholder",
- "navbar_start": ["navbar-logo"],
- "navbar_end": ["theme-switcher", "navbar-icon-links.html"],
- "navbar_align": "content",
- # "navbar_persistent": ["theme-switcher"], # this is where the search button is usually placed
- "footer_start": ["copyright"],
- "footer_end": ["footer"],
- "secondary_sidebar_items": ["page-toc", "edit-this-page", "sourcelink", "support"],
- "header_links_before_dropdown": 5,
- # page elements content
- "icon_links": [
- {
- "name": "Open this Repo on GitHub",
- "url": "https://github.com/flechtenberg/pulpo",
- "icon": "fab fa-brands fa-github",
- },
- ],
- # various settings
- "collapse_navigation": True,
- # "show_prev_next": False,
- "use_edit_page_button": True,
- "navigation_with_keys": True,
- "logo": {
- "image_light": "_static/pulpo_logo_big.svg",
- "image_dark": "_static/pulpo_logo_big.svg",
- },
-}
-
-# required by html_theme_options: "use_edit_page_button"
-html_context = {
- "github_user": "flechtenberg",
- "github_repo": "pulpo",
- "github_version": "master",
- "doc_path": "docs",
-}
-
-# notfound Configuration ################################################
-# https://sphinx-notfound-page.readthedocs.io
-
-notfound_context = {
- "title": "Page Not Found",
- "body": """
-
🍂 Page Not Found (404)
-
- Oops! It looks like you've stumbled upon a page that's been recycled into the digital abyss.
- But don't worry, we're all about sustainability here.
- Why not take a moment to reduce, reuse, and recycle your clicks by heading back to the main page?
- And remember, every little bit counts in the grand scheme of things.
-
- """,
-}
-
-####################################################################################################
-### Extension Configuration ########################################################################
-####################################################################################################
-
-# myst_parser Configuration ############################################
-# https://myst-parser.readthedocs.io/en/latest/configuration.html
-
-source_suffix = {".rst": "restructuredtext", ".md": "myst-nb", ".ipynb": "myst-nb"}
-
-
-myst_enable_extensions = [
- "amsmath",
- "colon_fence",
- "deflist",
- "dollarmath",
- "html_image",
-]
-
-# myst-nb configuration ################################################
-# https://myst-nb.readthedocs.io/en/latest/configuration.html
-
-nb_execution_mode = "off"
-
-# sphinx-favicon configuration #########################################
-# https://github.com/tcmetzger/sphinx-favicon
-
-favicons = [
- {"rel": "icon", "href": "favicon.svg", "type": "image/svg+xml"},
- {"rel": "icon", "sizes": "144x144", "href": "favicon-144.png", "type": "image/png"},
- {"rel": "mask-icon", "href": "favicon_mask-icon.svg", "color": "#222832"},
- {"rel": "apple-touch-icon", "sizes": "500x500", "href": "favicon-500.png"},
-]
diff --git a/docs/content/examples/data/system_boundaries_rice-no-choice_neutral.svg b/docs/content/examples/data/system_boundaries_rice-no-choice_neutral.svg
deleted file mode 100644
index 0289de5..0000000
--- a/docs/content/examples/data/system_boundaries_rice-no-choice_neutral.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/docs/environment.yaml b/docs/environment.yaml
deleted file mode 100644
index 5e64f83..0000000
--- a/docs/environment.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: pulpo_documentation
-channels:
- - conda-forge
- - nodefaults
-dependencies:
- # core functionality
- - python=3.11
- - ipython
- # sphinx
- - sphinx=7.3.7 # core builder # https://anaconda.org/conda-forge/sphinx/files
- # theme and extensions
- - pydata-sphinx-theme=0.15.3 # website theme # https://anaconda.org/conda-forge/pydata-sphinx-theme/files
- - myst-parser=3.0.1 # Markdown support # https://anaconda.org/conda-forge/myst-parser/files
- - myst-nb=1.1.0 # Jupyter notebook support # https://anaconda.org/conda-forge/myst-nb/files
- - sphinxcontrib-mermaid=0.9.2 # Mermaid support # https://anaconda.org/conda-forge/sphinxcontrib-mermaid/files
- - sphinx-autoapi=3.0.0 # to build docs from source code instead of package import # https://anaconda.org/conda-forge/sphinx-autoapi/files
- - sphinx-design=0.5.0 # responsive web component support # https://anaconda.org/conda-forge/sphinx-design/files
- - sphinx-notfound-page=1.0.0 # custom 404 page # https://anaconda.org/conda-forge/sphinx-notfound-page/files
- - graphviz=11.0.0 # for plotting dependency diagrams with sphinx-autoapi # https://anaconda.org/conda-forge/graphviz/files
- - sphinx-favicon=1.0.1 # for custom favicons # https://anaconda.org/conda-forge/sphinx-favicon/files
- - sphinx-copybutton=0.5.2 # for copy button in code blocks # https://anaconda.org/conda-forge/sphinx-copybutton/files
- # build process
- - sphinx-autobuild=2024.4.16 # live-html support # https://anaconda.org/conda-forge/sphinx-autobuild/files
- - pip
- - pip:
- - sphinx-carousel==1.2.0 # for carousel support # https://pypi.org/project/sphinx-carousel/
diff --git a/genindex.html b/genindex.html
new file mode 100644
index 0000000..213907d
--- /dev/null
+++ b/genindex.html
@@ -0,0 +1,849 @@
+
+
+
+
+
+
+
+
+
+
Index — pulpo documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Index
+
+
+
C
+ |
D
+ |
E
+ |
G
+ |
H
+ |
I
+ |
L
+ |
M
+ |
O
+ |
P
+ |
R
+ |
S
+ |
U
+
+
+C
+
+
+D
+
+
+E
+
+
+G
+
+
+H
+
+
+I
+
+
+L
+
+
+M
+
+
+O
+
+
+P
+
+
+
+
+ pulpo.utils.bw_parser
+
+
+
+ pulpo.utils.converter
+
+
+
+ pulpo.utils.optimizer
+
+
+
+ pulpo.utils.saver
+
+
+
+ pulpo.utils.utils
+
+
+ PulpoOptimizer (class in pulpo.pulpo)
+
+
+
+
+R
+
+
+S
+
+
+U
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..373cd1f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,599 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Life Cycle Optimization (LCO) with PULPO — pulpo documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Life Cycle Optimization (LCO) with PULPO
+PULPO
is a python package for Life Cycle Optimization (LCO) based on life cycle inventories. It is intended to serve as a platform for optimization tasks of varying complexity.
+The package builds on top of the Brightway LCA framework as well as the optimization modeling framework Pyomo .
+
+✨ Capabilities
+Applying optimization is recommended when the system of study has (1) many degrees of freedom which would prompt the manual assessment of a manifold of scenarios, although only the “optimal” one is of interest and/or (2) any of the following capabilities makes sense within the goal and scope of the study:
+
+Specify technology and regional choices throughout the entire supply chain (i.e. fore- and background), such as choices for the production technology of electricity or origin of metal resources. Consistently accounting for changes in the background in “large scale” decisions can lead to significantly different insights .
+Specify constraints on any activity in the life cycle inventories, which can be interpreted as tangible limitations such as raw material availability, production capacity, or environmental regulations.
+Optimize and/or constrain any impact category for which the characterization factors are available.
+Specify supply values instead of final demands, which can become relevant if only production values are available (e.g. here ).
+
+
+
+💬 Support
+If you have any questions or need help, do not hesitate to contact us:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/notebooks/electricity_showcase.ipynb b/notebooks/electricity_showcase.ipynb
deleted file mode 100644
index 3230c55..0000000
--- a/notebooks/electricity_showcase.ipynb
+++ /dev/null
@@ -1,1433 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "3e2beb82",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5dcdd302",
- "metadata": {},
- "source": [
- "PULPO Tutorial. This notebook showcases the optimization of the German electricity mix. First, the basic functionalities are demonstrated. Advanced functionalities are also shown later in the notebook.\n",
- "\n",
- "Written by Fabian Lechtenberg, 18.09.2023\n",
- "Last Update: 15.12.2023"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1ed6b95f",
- "metadata": {},
- "source": [
- "
\n",
- "
(1) Selection of LCI Data \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4f8eff9d",
- "metadata": {},
- "source": [
- "### Import section"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "448abc38",
- "metadata": {},
- "source": [
- "Import a couple of necessary Python packages. The \"sys.path.append('../')\" is only necessary if you forked this repository."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "606b78ed",
- "metadata": {
- "jupyter": {
- "is_executing": true
- }
- },
- "outputs": [],
- "source": [
- "import os\n",
- "import sys\n",
- "sys.path.append('../')\n",
- "from pulpo import pulpo\n",
- "\n",
- "import pandas as pd\n",
- "pd.set_option('display.max_colwidth', None)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0da2fe63",
- "metadata": {},
- "source": [
- "### Setup"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "84d12867",
- "metadata": {},
- "source": [
- "Specify the project, database and method to be used. Also indicate the folder where the working and results data should be stored. For this example to work, you need a project \"**pulpo**\" with a database \"**cutoff38**\", which is the ecoinvent 3.8 cutoff system model."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "31a552aa-a98f-459a-9e53-e808c7ef2fe2",
- "metadata": {},
- "outputs": [
- {
- "name": "stdin",
- "output_type": "stream",
- "text": [
- "Enter version (bw2 or bw25): bw25\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Set to: project=pulpo_bw25, database=ecoinvent-3.8-cutoff, methods=('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')\n"
- ]
- }
- ],
- "source": [
- "# Ask the user for input\n",
- "version = input(\"Enter version (bw2 or bw25): \")\n",
- "\n",
- "# Set variables based on user input\n",
- "if version == \"bw2\":\n",
- " project = \"pulpo\"\n",
- " database = \"cutoff38\"\n",
- " methods = \"('IPCC 2013', 'climate change', 'GWP 100a')\"\n",
- "elif version == \"bw25\":\n",
- " project = \"pulpo_bw25\"\n",
- " database = \"ecoinvent-3.8-cutoff\"\n",
- " methods = \"('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')\"\n",
- "else:\n",
- " raise ValueError(\"Invalid version specified. Please enter 'pulpo' or 'pulpo_bw25'.\")\n",
- "\n",
- "print(f\"Set to: project={project}, database={database}, methods={methods}\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "ead64289",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-18T10:01:56.272770400Z",
- "start_time": "2024-12-17T15:37:33.257637Z"
- }
- },
- "outputs": [],
- "source": [
- "# Substitute with your working directory of choice\n",
- "notebook_dir = os.path.dirname(os.getcwd())\n",
- "directory = os.path.join(notebook_dir, 'data')\n",
- "\n",
- "# Substitute with your GAMS path\n",
- "GAMS_PATH = r\"C:\\APPS\\GAMS\\win64\\40.1\\gams.exe\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0e5e5da2",
- "metadata": {},
- "source": [
- "Create a pulpo object called \"pulpo_worker\". This object is an element of the class \"PulpoOptimizer\", a class that links the different utilitiy modules containing code for retrieving, preparing and adjusting the data, preparing and running the optimization problem, as well as saving the results."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "ae4b5787",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-18T10:01:56.276762Z",
- "start_time": "2024-12-17T15:37:33.340373Z"
- }
- },
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2a9fcd18",
- "metadata": {},
- "source": [
- "Retrieve the data LCI data:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "80697078",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:37.011160Z",
- "start_time": "2024-12-17T15:37:33.353602Z"
- }
- },
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e16f8296",
- "metadata": {},
- "source": [
- "
\n",
- "
(2) User Specifications \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "22175932",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a8492b7e",
- "metadata": {},
- "source": [
- "### Specify the **functional unit**"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "de935003",
- "metadata": {},
- "source": [
- "Retrieve the market activity for high voltage electricity in Germany. Use the function \"**
retrieve_activities **\" for this purpose. The function takes 4 optional arguments: \n",
- "\n",
- "\"keys\" (🔑) --> \"activities\" (⚙️) --> \"reference_products\" (📦) --> \"locations\" (🗺️). \n",
- "\n",
- "The activities are retrieved by this order. \n",
- "\n",
- "Since the key is unique, a single activity for each passed key will be returned. Activity names, reference_product and locations are not unique, so the best match for the passed data will be returned. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2fc40bd9",
- "metadata": {},
- "source": [
- "#### Passing keys 🔑"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "80fce33f",
- "metadata": {},
- "source": [
- "Keys can be obtained e.g. directly from **activity browser** and several keys can be passed at the same time."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "167a2bfb",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:37.023035Z",
- "start_time": "2024-12-17T15:37:37.019284Z"
- }
- },
- "outputs": [],
- "source": [
- "keys = [\"('cutoff38', '962727b9a36bcaa186f222b29b57f6a3')\", \"('cutoff38', '473d4bb488e8f903b58203f3e5161636')\"]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b46fa327",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:38.423093Z",
- "start_time": "2024-12-17T15:37:37.032839Z"
- }
- },
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(keys=keys)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "daf88526",
- "metadata": {},
- "source": [
- "#### Passing activity name (⚙️), reference_product (📦) and/or location (🗺️)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4074fec3",
- "metadata": {},
- "source": [
- "Instead of passing the keys, a combination of activities, reference_products and locations can be passed. A best match (all existing combinations) will be returned. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4d445dfc",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:38.437078Z",
- "start_time": "2024-12-17T15:37:38.434209Z"
- }
- },
- "outputs": [],
- "source": [
- "activities = [\"market for electricity, high voltage\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5d0976d1",
- "metadata": {},
- "source": [
- "It is also possible to pass only partial information such as only reference product or only activity name:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0cb7d84f",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:39.939393Z",
- "start_time": "2024-12-17T15:37:38.450640Z"
- },
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(activities=activities)[0:5]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b211d17a",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:41.367139Z",
- "start_time": "2024-12-17T15:37:39.952262Z"
- },
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(reference_products=reference_products)[0:5]"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "03e8a151",
- "metadata": {},
- "source": [
- "Let's retrieve the activity of our functional unit and specify the demand as a dictionary:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "332b2f95",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:42.719152Z",
- "start_time": "2024-12-17T15:37:41.385314Z"
- }
- },
- "outputs": [],
- "source": [
- "electricity_market = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1959b64f",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:42.731441Z",
- "start_time": "2024-12-17T15:37:42.726550Z"
- }
- },
- "outputs": [],
- "source": [
- "electricity_market"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7cf0adef",
- "metadata": {},
- "source": [
- "Setting a demand of 128,819.0 GWh of electricity according to [Germany electricity demand 2018](https://www.destatis.de/EN/Themes/Society-Environment/Environment/Material-Energy-Flows/Tables/electricity-consumption-households.html)\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "223e1cf1",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:42.743240Z",
- "start_time": "2024-12-17T15:37:42.739455Z"
- }
- },
- "outputs": [],
- "source": [
- "demand = {electricity_market[0]: 1.28819e+11}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "992d6029",
- "metadata": {},
- "source": [
- "### Specify the **choices**"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4b6d561a",
- "metadata": {},
- "source": [
- "The choices are specified similar to the demand / functional unit. First, search for the processes with equivalent products:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d704a9a5",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:44.043245Z",
- "start_time": "2024-12-17T15:37:42.777555Z"
- }
- },
- "outputs": [],
- "source": [
- "activities = [\"electricity production, lignite\", \n",
- " \"electricity production, hard coal\",\n",
- " \"electricity production, nuclear, pressure water reactor\",\n",
- " \"electricity production, wind, 1-3MW turbine, onshore\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]\n",
- "\n",
- "electricity_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9d8fac69",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:44.055487Z",
- "start_time": "2024-12-17T15:37:44.046251Z"
- }
- },
- "outputs": [],
- "source": [
- "electricity_activities"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "12c4d7a7-826d-4168-a9e5-902cf21537d1",
- "metadata": {},
- "source": [
- "These are the currently four most employed technologies for electricity production in Germany (lignite: 24.2%, wind: 15.4%, coal: 11.9%, nuclear: 10.6%) according to the \"_market for electricity, high voltage (DE)_\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d9a512a5",
- "metadata": {},
- "source": [
- "Specify also the choices as a dictionary. Be aware, that this time we are dealing with a dictionary of dictionaries. Each inner dictionary corresponds to one type of choice in the background! Here, we only consider choices between electricity production activities, so we assign the key \"electricity\" to the equivalent product they produce. \n",
- "\n",
- "The assigned value in the inner dictionary is the capacity limit of this activity, which for now is set to a very high value, to consider an unconstrained situation. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bfae6af4",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:44.071741Z",
- "start_time": "2024-12-17T15:37:44.067894Z"
- }
- },
- "outputs": [],
- "source": [
- "choices = {'electricity': {electricity_activities[0]: 1e16,\n",
- " electricity_activities[1]: 1e16,\n",
- " electricity_activities[2]: 1e16,\n",
- " electricity_activities[3]: 1e16}}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "25f8cf77",
- "metadata": {},
- "source": [
- "
\n",
- "
(3) Solution \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a90008f",
- "metadata": {},
- "source": [
- "### Instantiate the worker"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "be46ea2d",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:48.909729Z",
- "start_time": "2024-12-17T15:37:44.090006Z"
- },
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "20353834",
- "metadata": {},
- "source": [
- "### Solve the instance"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "43da9882",
- "metadata": {},
- "source": [
- "When specifying a valid GAMS_PATH with a licence for CPLEX, as shown below, CPLEX with fine-tuned parameters is automatically selected to solve the Linear Problem (**LP**).\n",
- "\n",
- "If no GAMS_PATH is specified, the \"[HiGHS](https://highs.dev/)\" solver is automatically used. It has almost double the run time of \"CPLEX\" and fails to solve the problem in a couple of instances."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "eb13ed22",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:37:59.112923Z",
- "start_time": "2024-12-17T15:37:48.925367Z"
- },
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "#results = pulpo_worker.solve()\n",
- "# Alternatively using GAMS (cplex) solvers:\n",
- "results = pulpo_worker.solve(GAMS_PATH=GAMS_PATH)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "916c7e48",
- "metadata": {},
- "source": [
- "### Save and summarize the results 💾📈"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "cba63697",
- "metadata": {},
- "source": [
- "The \"**save_results()**\" function will save the results in an processed format to an excel file in the data folder that has been specified at the beginning."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cf427cea",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:38:00.644642Z",
- "start_time": "2024-12-17T15:37:59.127619Z"
- }
- },
- "outputs": [],
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='electricity_showcase_results.xlsx')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "20b00f17",
- "metadata": {},
- "source": [
- "You can inspect the generated excel file."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4c4a1df1",
- "metadata": {},
- "source": [
- "There is another function to summarize the results in dataframe form within jupyter notbeooks called \"summarize_results\". This function has similar inputs to the \"save_results\" function, but does not require the specification of a filename. Additionally, by specifying the \"*zeroes*\" parameter to \"*True*\" all the not-selected choices are omitted in the summary."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f6141497",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:38:00.699492Z",
- "start_time": "2024-12-17T15:38:00.659681Z"
- }
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c1b2f442",
- "metadata": {},
- "source": [
- "This is the end of the very basic PULPO functionalities using the electricity case study. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "b5298095",
- "metadata": {},
- "source": [
- "The following sections will dive deeper into additional functionalities."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "602c9d5e",
- "metadata": {},
- "source": [
- "
\n",
- "
Additional Constraints \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "07bffb38-471b-4f7c-b48d-9954e0fe4e55",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "450f9fc7",
- "metadata": {},
- "source": [
- "#### Technosphere Flows"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e277bb96",
- "metadata": {},
- "source": [
- "Let's assess what happens if the \"_electricity production, nuclear, pressure water reactor | electricity, high voltage | DE_\" activity is indirectly constrained trough a restriction on \"_nuclear fuel element, for pressure water reactor, UO2 4.0% & MOX_\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "04b68998",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:38:02.179850Z",
- "start_time": "2024-12-17T15:38:00.743258Z"
- }
- },
- "outputs": [],
- "source": [
- "activities = [\"market for nuclear fuel element, for pressure water reactor, UO2 4.0% & MOX\"]\n",
- "reference_products = [\"nuclear fuel element, for pressure water reactor, UO2 4.0% & MOX\"]\n",
- "locations = [\"GLO\"]\n",
- "\n",
- "nuclear_fuel = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "aebdc35c",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:38:02.615734Z",
- "start_time": "2024-12-17T15:38:02.608721Z"
- }
- },
- "outputs": [],
- "source": [
- "nuclear_fuel"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a89c6ee5",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2024-12-17T15:38:02.761750Z",
- "start_time": "2024-12-17T15:38:02.758220Z"
- }
- },
- "outputs": [],
- "source": [
- "upper_limit = {nuclear_fuel[0]: 100000}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "da61b77d",
- "metadata": {},
- "source": [
- "The rationale behind choosing this activity and this limit is based on inspection of the scaling vector of the previous results. This activity is limiting for the nuclear electricity activity but not for the others, so, to enforce a different result than before (for demonstration purpose), this activity is constrained."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "87267aa9",
- "metadata": {
- "ExecuteTime": {
- "start_time": "2024-12-17T15:38:02.791255Z"
- },
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit=upper_limit)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a03f1671",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5f409b26",
- "metadata": {},
- "source": [
- "As can be seen from the summary above, part of the final electricity demand is supplied by the wind turbine processes, because the nuclear electricity process is constrained by the nuclear fuel process. It is also evident that the impact is higher than the previous one, as the GWP minimizing process (nuclear) can no longer supply the full demand."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "52f439fb",
- "metadata": {},
- "source": [
- "#### Elementary Flows"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ac1cba55",
- "metadata": {},
- "source": [
- "Apart from technosphere flows, elementary flows may also be constrained. This could be a limitation on the extraction of raw materials or the emission of a certain compound. In this case study, we limit the emission of Radon-22:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "46d1812d",
- "metadata": {},
- "outputs": [],
- "source": [
- "elem = pulpo_worker.retrieve_envflows(activities='Radon-222')\n",
- "elem"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0786e76e",
- "metadata": {},
- "source": [
- "As can be seen from the results of the previous assessment, the \"low population density, long-term\" emission is the largest elementary flow with 3.69x1E13 kg Becquerel. For testing purpose, we limit this emissio to 5.00x1E12 kg Becquerel:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4bdc2692",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "elem = [flow for flow in elem if 'long-term' in str(flow)]\n",
- "elem_limit = {elem[0]: 5e12}\n",
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand, upper_elem_limit=elem_limit)\n",
- "results = pulpo_worker.solve() "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a50c00e5",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='electricity_showcase_results_elem.xlsx')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bac65431",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2f7b6a4a",
- "metadata": {},
- "source": [
- "As can be seen, the share of nuclear power is limited through the introduced elementary flow constraint."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "48249a97",
- "metadata": {},
- "source": [
- "
\n",
- "
Additional Methods \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a455b7b",
- "metadata": {},
- "source": [
- "Let's see how to evaluate different methods and set them as objectives, in this case evaluating the ReCiPe endpoints, and setting the human health one as objective:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6ccd79d5",
- "metadata": {},
- "outputs": [],
- "source": [
- "methods = {\n",
- " (f\"('ecoinvent-3.8', {k[1:]}\" if version == \"bw25\" else k): (1 if k == \"('ReCiPe Endpoint (E,A)', 'human health', 'total')\" else 0)\n",
- " for k in [\n",
- " \"('IPCC 2013', 'climate change', 'GWP 100a')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'resources', 'total')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'human health', 'total')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'ecosystem quality', 'total')\"\n",
- " ]\n",
- "}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "97f4df9e-1e6b-44d2-9f63-2551fd8f99d6",
- "metadata": {},
- "source": [
- "With this, a new Pulpo worker must be created:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8c71c0b9",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "60d4cad9",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cb241deb",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e81c9f8c",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bfe4c83f-1585-405c-938d-c3c6e3fc34f7",
- "metadata": {},
- "source": [
- "From the summary above, it can be seen that for the \"_human health_\" category, the nuclear process is not the most suitable anymore. With this objective, the wind turbine process is selected. \n",
- "\n",
- "As another category is minimized, the GWP has changed as well: previously, with nuclear electricity the total GWP was 1.599836e+10 while with wind electricity it is 1.739234e+10."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7fb09ed7-e772-4248-8bc5-8409fb5ebfe0",
- "metadata": {},
- "source": [
- "
\n",
- "
Lower Level Decisions (Regional Choice) \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "26fec4c4",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ee72103c",
- "metadata": {},
- "source": [
- "In this case study, we would like to keep the current share of the electricity supplied by fossil sources the same. The choices that we consider on the electricity production level are between the coal and lignite activities:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1e28df91-e6fc-4123-b3e6-3067ee6deca3",
- "metadata": {},
- "outputs": [],
- "source": [
- "methods = {\n",
- " (f\"('ecoinvent-3.8', {k[1:]}\" if version == \"bw25\" else k): (1 if k == \"('IPCC 2013', 'climate change', 'GWP 100a')\" else 0)\n",
- " for k in [\n",
- " \"('IPCC 2013', 'climate change', 'GWP 100a')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'resources', 'total')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'human health', 'total')\",\n",
- " \"('ReCiPe Endpoint (E,A)', 'ecosystem quality', 'total')\"\n",
- " ]\n",
- "}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2b881759-2c15-4528-9780-39293f3747be",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\"\n",
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e7cff49c-5163-4451-aa97-a1ef41bce88b",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"electricity production, lignite\", \n",
- " \"electricity production, hard coal\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]\n",
- "\n",
- "electricity_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a8f82b5b",
- "metadata": {},
- "source": [
- "Instead of assessing only the **technology** choices, we are invetigating the best **regional** choice for the source of coal and lignite:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e68e44ef",
- "metadata": {},
- "outputs": [],
- "source": [
- "coal_activities = [\"market for hard coal\"]\n",
- "lignite_activities = [\"market for lignite\"]\n",
- "\n",
- "coal_activities = pulpo_worker.retrieve_activities(activities=coal_activities)\n",
- "lignite_activities = pulpo_worker.retrieve_activities(activities=lignite_activities)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ae575912",
- "metadata": {},
- "source": [
- "The updated choice dictionary looks like this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bc665036",
- "metadata": {},
- "outputs": [],
- "source": [
- "choices = {'electricity': {elec: 1e16 for elec in electricity_activities},\n",
- " 'coal': {coal: 1e16 for coal in coal_activities},\n",
- " 'lignite': {lignite: 1e16 for lignite in lignite_activities}}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6db1e764",
- "metadata": {},
- "source": [
- "Instantiating and solving the adapted problem:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1143473f",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "73eadc47",
- "metadata": {},
- "source": [
- "Visualizing the results"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d9c7c140",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "18a60969",
- "metadata": {},
- "source": [
- "I can be seen that out of the fossil alternatives, the electricity from coal minimizes GWP when the coal comes from RLA [Latin America and the Caribbean] (omitting transport emissions). Moreover, it can be seen that the market for lignite is somewhere used upstream of the coal production activity. In the place where it is used, the RER market for lignite is the preferred one. The lignite consumption is one order of magnitude lower than the coal consumption."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d71d8e1c",
- "metadata": {},
- "source": [
- "
\n",
- "
Supply vs. Demand Problem \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "66cb3f62",
- "metadata": {},
- "source": [
- "Finally, let's test and assess the functionality of PULPO to specify supply values rather than demand values. This can be done by setting the lower_limit and the upper_limit of activities to the same value. This will enforce the corresponding scaling vector entry of that activity to the specified value, and activates the slack variable to relax the demand value. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4a3f2eac",
- "metadata": {},
- "source": [
- "This can simply be done by specifying the upper and lower limits rather than the demand (we continue with the choices from the previous section):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "89ecef38",
- "metadata": {},
- "outputs": [],
- "source": [
- "upper_limit = {electricity_market[0]: 1.28819e+11}\n",
- "lower_limit = {electricity_market[0]: 1.28819e+11}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6f72394d",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, upper_limit=upper_limit, lower_limit=lower_limit)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "006b3b87",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6ecc80bf",
- "metadata": {},
- "source": [
- "From the results it can be observed that the resulting GWP is **considerably** lower (6.191744e+10 vs. 5.920967e+10: ~4.4%) than in the previous section. Now, the production value (supply) of electricity is specified, so that electricity consumed in the background is accounted for in the specifications.\n",
- "\n",
- "Overall, when specifying supply values instead of demand values, the corresponding scaling vector entries are always smaller."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "976fd3a8-e3eb-4f8c-a875-856eb741aa3a",
- "metadata": {},
- "source": [
- "
\n",
- "
Foreground vs. Background Modelling \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d0b2e993-009a-4b7b-a7ee-ece90fe1eea0",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7610381f-c826-417d-8885-5a4e4b938199",
- "metadata": {},
- "source": [
- "In this final part of the electricity showcase, the difference between foreground and background modelling and optimization is demonstrated. For that purpose a foreground system must be created ... this can be done either by hand or I can upload a folded foreground system for this case ... in essence, a new database must be created (e.g. \"_cutoff38_foreground_\" where copies from the market and electricity production activites are duplicated to from the \"_cutoff38_\". What this does is disconnecting this activities from their downstream.\n",
- "\n",
- "We are then replacing the original inputs in the electricity market with the duplicated processes from the foreground system, effectively disconnecting the choices made in the electricity market from the upstream of the electricity production technologies:"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "be25cefe-6ca4-42d2-bb8a-3096c93b8663",
- "metadata": {},
- "source": [
- "With this in mind, we can set up the optimization as usual, importing the \"_cutoff38_foreground_\" database instead of the \"_cutoff38_\" database:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "83385f75-df84-4bb9-9248-aef2e78e3e3f",
- "metadata": {},
- "outputs": [],
- "source": [
- "project = \"pulpo\"\n",
- "database = \"cutoff38_foreground\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "651554db-128f-4b74-ab2d-0ab98ae5012b",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e9b26ce5-8055-4afe-b81d-e06f057d34f1",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1840257e-f372-4a83-a519-cce3097bc68e",
- "metadata": {},
- "source": [
- "Now, choose the foreground market for electricity:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ff250df5-3646-4d2d-8d7f-2b7750c06bdb",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"market for electricity, high voltage, foreground\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "63766777-83a7-4a3b-b49a-36601fe72638",
- "metadata": {},
- "outputs": [],
- "source": [
- "foreground_market = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "37c0635f-cb0b-495d-bfd4-d72a2aabe414",
- "metadata": {},
- "outputs": [],
- "source": [
- "demand = {foreground_market[0]: 1.28819e+11}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7e358b4f-c25c-42d4-af5b-8fc3c2de4edb",
- "metadata": {},
- "source": [
- "And the foreground electricity production technologies:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "32cbd648-bc8f-4ec0-af63-b7147803e805",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"electricity production, lignite, foreground\", \n",
- " \"electricity production, hard coal, foreground\",\n",
- " \"electricity production, nuclear, pressure water reactor, foreground\",\n",
- " \"electricity production, wind, 1-3MW turbine, onshore, foreground\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]\n",
- "\n",
- "electricity_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9af3f0cc-ca10-46b6-b6a6-818c7fba3579",
- "metadata": {},
- "outputs": [],
- "source": [
- "choices = {'electricity': {electricity_activities[0]: 1e16,\n",
- " electricity_activities[1]: 1e16,\n",
- " electricity_activities[2]: 1e16,\n",
- " electricity_activities[3]: 1e16}}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "da8c0aec-7047-4e6c-8a2f-55777c160a78",
- "metadata": {},
- "source": [
- "Create the instance and solve the problem:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e2cd342f-cb54-49fb-8d11-078b16845fca",
- "metadata": {},
- "outputs": [],
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "823f2a7d-053d-4ad3-8452-32d05d8aec9f",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2e40a4aa-3c1c-4e45-b679-c6461e41fa1f",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5e8924a0-6f11-4891-9f12-c06eb2c699b2",
- "metadata": {},
- "source": [
- "The result of this optimization is a minimum GWP of 1.764977e+10 kg CO2eq instead of 1.599836e+10 kg CO2eq from the initial calculations using the full LCI. This is a difference of **8%**!"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "63afe2ba-d322-4a1e-a75b-fc36e0e354b6",
- "metadata": {},
- "source": [
- "
\n",
- "
Integer Cuts \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6485f0f7-0889-4a15-9abd-5b214bc7617a",
- "metadata": {},
- "source": [
- "This functionality will be available in future versions of PULPO"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.10.16"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/notebooks/energy_transition_showcase.ipynb b/notebooks/energy_transition_showcase.ipynb
deleted file mode 100644
index d1c451a..0000000
--- a/notebooks/energy_transition_showcase.ipynb
+++ /dev/null
@@ -1,250 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "bd87768d-b2ea-4593-8a70-c89ed8227bb8",
- "metadata": {},
- "source": [
- "## Energy Transition Case Study\n",
- "\n",
- "This notebook presents the base case optimization of the German electricity market as presented in the manuscript presenting the PULPO framework.\n",
- "\n",
- "Updated by Fabian Lechtenberg, 15.04.2024.\n",
- "\n",
- "See [this notebook](./electricity_showcase.ipynb) for additional results and functionalities of this case study, and [this notebook](./plastic_showcase.ipynb) for a more thorough demonstration of the functionalities on a plastics recycling case study."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bbc904da-04a9-4151-baba-f1537711e796",
- "metadata": {},
- "source": [
- "
\n",
- "
Demonstration 🚀 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ea903462-b798-40ae-ba75-52820ac325ff",
- "metadata": {},
- "source": [
- "### Base Problem"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "614b70a0-858d-46c6-bc11-afc44cc7b0e6",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Import section\n",
- "import os\n",
- "import sys\n",
- "sys.path.append('../')\n",
- "\n",
- "import pandas as pd\n",
- "from pulpo import pulpo"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6bb959c5-ef79-45c3-8f29-a876322eabb4",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Your brightway2 project, database and targeted impact category\n",
- "project = \"pulpo\"\n",
- "database = \"cutoff38\"\n",
- "methods = {\"('IPCC 2013', 'climate change', 'GWP 100a')\": 1,\n",
- " \"('ReCiPe Endpoint (E,A)', 'resources', 'total')\": 0,\n",
- " \"('ReCiPe Endpoint (E,A)', 'human health', 'total')\": 0,\n",
- " \"('ReCiPe Endpoint (E,A)', 'ecosystem quality', 'total')\": 0,\n",
- " \"('ReCiPe Midpoint (E) V1.13', 'ionising radiation', 'IRP_HE')\": 0}\n",
- "\n",
- "# Substitute with your working directory of choice\n",
- "notebook_dir = os.path.dirname(os.getcwd())\n",
- "directory = os.path.join(notebook_dir, 'data')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e19799b6-7601-4614-8320-76f84e00aba8",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Create a PULPO object\n",
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "763ba723-2074-48ba-bc38-7922b86134e9",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Retrieve LCI data\n",
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ac586be8-813c-40b3-8fd2-83642b43c378",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Retrieve the electricity market\n",
- "activities = [\"market for electricity, high voltage\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]\n",
- "electricity_market = pulpo_worker.retrieve_activities(activities=activities,\n",
- " reference_products=reference_products,\n",
- " locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ff3da007-1c3e-434c-ab21-f6fb00a19d41",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Specify the functional unit as demand dictionary\n",
- "demand = {electricity_market[0]: 1.28819e+11}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b0d92d90-b230-43b5-99c9-77b9477bb601",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Retrieve the choices\n",
- "activities = [\"electricity production, lignite\", \n",
- " \"electricity production, hard coal\",\n",
- " \"electricity production, nuclear, pressure water reactor\",\n",
- " \"electricity production, wind, 1-3MW turbine, onshore\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "locations = [\"DE\"]\n",
- "\n",
- "electricity_activities = pulpo_worker.retrieve_activities(activities=activities,\n",
- " reference_products=reference_products,\n",
- " locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f14ab5a4-5ecd-4d93-91e4-958bec6326c0",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Specify the choices dictionary\n",
- "choices = {'electricity': {electricity_activities[0]: 1e16,\n",
- " electricity_activities[1]: 1e16,\n",
- " electricity_activities[2]: 1e16,\n",
- " electricity_activities[3]: 1e16}}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d9baca84-3346-4496-9690-c39a30d5081a",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Instantiate and solve the problem (here with HiGHS)\n",
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "71143edd-c671-4ee0-a79c-3ebe192fc450",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Summarize the results\n",
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ea3df02a-fbe5-4937-842d-990b403bd109",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='energy_transition_showcase.xlsx')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2bb668e7-30ca-4b55-9ea0-50e1415afee6",
- "metadata": {},
- "source": [
- "### No optimization"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d70de808-ca7b-4db1-9eed-1c9a0913c073",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Instantiate and solve the problem (here with HiGHS)\n",
- "instance = pulpo_worker.instantiate(choices={}, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f7e055e4-f7a6-4cdf-863f-2b104f0e2ed1",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c756d642-6362-417b-80d4-11eff0d8880e",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='energy_transition_showcase_noopt.xlsx')"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.9.19"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/notebooks/helper.py b/notebooks/helper.py
deleted file mode 100644
index 658cf32..0000000
--- a/notebooks/helper.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import brightway2 as bw
-
-def create_or_update_activity(db, activity_code, activity_details, exchanges, biosphere):
- """
- Creates or updates an activity with specified technosphere and biosphere exchanges.
-
- Parameters:
- - db: The Brightway2 database object.
- - activity_code: Unique code for the activity.
- - activity_details: Dictionary containing the name, unit, and location of the activity.
- - exchanges: List of dictionaries detailing the exchanges to be added or updated.
- - biosphere: The Brightway2 biosphere database object for biosphere exchanges.
- """
- try:
- # Try to get the activity if it already exists
- activity = db.get(activity_code)
- print(f"{activity_details['name']} already exists, updating exchanges.")
- except:
- # If not, create a new activity
- activity = db.new_activity(code=activity_code, **activity_details)
- activity.save()
- print(f"Created {activity_details['name']}.")
-
- # Add or update exchanges
- for exch in exchanges:
- # Determine if the exchange is technosphere or biosphere
- if exch['type'] == 'biosphere':
- search_result = biosphere.search(exch['name'])[0]
- else: # 'technosphere'
- search_result = db.search(exch['name'])[0]
-
- # Add or update the exchange
- activity.new_exchange(input=search_result.key, amount=exch['amount'], type=exch['type']).save()
-
- # Save changes to the activity
- activity.save()
- print(f"Updated {activity_details['name']} with new exchanges.")
-
-def copy_activity(original_activity):
- # Construct the new name for the copied activity
- new_activity_name = original_activity['name'] + " copy"
-
- # Get the database of the original activity
- db = bw.Database(original_activity['database'])
-
- # Check if the activity with the new name already exists
- existing_activities = {a['name']: a for a in db}
- if new_activity_name in existing_activities:
- print(f"Activity '{new_activity_name}' already exists.")
- return existing_activities[new_activity_name]
- else:
- # Create a new activity as a copy of the original activity
- copied_activity = original_activity.copy()
- copied_activity['name'] = new_activity_name
- copied_activity.save()
- print(f"Created a copy of '{original_activity['name']}' named '{new_activity_name}'.")
- return copied_activity
diff --git a/notebooks/hydrogen_showcase.ipynb b/notebooks/hydrogen_showcase.ipynb
deleted file mode 100644
index 01f8b48..0000000
--- a/notebooks/hydrogen_showcase.ipynb
+++ /dev/null
@@ -1,959 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "5dcdd302",
- "metadata": {},
- "source": [
- "Hydrogen showcase for basic PULPO\n",
- "\n",
- "Written by Fabian Lechtenberg, 07.07.2023\n",
- "\n",
- "Last Update: 24.09.2023"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1ed6b95f",
- "metadata": {},
- "source": [
- "
\n",
- "
(1) Selection of LCI Data \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4f8eff9d",
- "metadata": {},
- "source": [
- "### Import section"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "448abc38",
- "metadata": {},
- "source": [
- "In this working version of the pulpo repository, pulpo musst be imported from the folder above, which can be done by appending \"..\" to the system path."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "606b78ed",
- "metadata": {},
- "outputs": [],
- "source": [
- "import os\n",
- "import sys\n",
- "sys.path.append('..')\n",
- "from pulpo import pulpo\n",
- "\n",
- "import pandas as pd\n",
- "pd.set_option('display.max_colwidth', None)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0da2fe63",
- "metadata": {},
- "source": [
- "### Setup"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "84d12867",
- "metadata": {},
- "source": [
- "Specify the project, database and method to be used. Also indicate the folder where the working data should be stored."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d116e4d4-be73-4291-a77c-603459b3ef2f",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Ask the user for input\n",
- "version = input(\"Enter version (bw2 or bw25): \")\n",
- "\n",
- "# Set variables based on user input\n",
- "if version == \"bw2\":\n",
- " project = \"pulpo\"\n",
- " database = \"cutoff38\"\n",
- " method = \"('IPCC 2013', 'climate change', 'GWP 100a')\"\n",
- "elif version == \"bw25\":\n",
- " project = \"pulpo_bw25\"\n",
- " database = \"ecoinvent-3.8-cutoff\"\n",
- " method = \"('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')\"\n",
- "else:\n",
- " raise ValueError(\"Invalid version specified. Please enter 'pulpo' or 'pulpo_bw25'.\")\n",
- "\n",
- "print(f\"Set to: project={project}, database={database}, methods={method}\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ead64289",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Substitute with your working directory of choice\n",
- "notebook_dir = os.path.dirname(os.getcwd())\n",
- "directory = os.path.join(notebook_dir, 'data')\n",
- "\n",
- "# Substitute with your GAMS path\n",
- "GAMS_PATH = r\"C:\\APPS\\GAMS\\win64\\40.1\\gams.exe\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0e5e5da2",
- "metadata": {},
- "source": [
- "Create a pulpo object called \"pulpo_worker\". This object is an element of the class \"PulpoOptimizer\", a class that links the different utilitiy modules containing code for retrieving, preparing and adjusting the data, preparing and running the optimization problem, as well as saving the results."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ae4b5787",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, method, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2a9fcd18",
- "metadata": {},
- "source": [
- "Retrieve the data. If data is already loaded, this step is automatically skipped. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "80697078",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e16f8296",
- "metadata": {},
- "source": [
- "
\n",
- "
(2) User Specifications \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a8492b7e",
- "metadata": {},
- "source": [
- "### Specify the **functional unit**"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "de935003",
- "metadata": {},
- "source": [
- "Retrieve the market activity for liquid hydrogen in Europe (RER). Use the function \"**
retrieve_activities **\" for this purpose. The function takes 4 optional arguments: \"keys\" (🔑) --> \"activities\" (⚙️) --> \"reference_products\" (📦) --> \"locations\" (🗺️). The activities are retrieved by this order. \n",
- "\n",
- "Since the key is unique, a single activity for each passed key will be returned. Activity names, reference_prduct and locations are not unique, so the best match for the passed data will be returned. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2fc40bd9",
- "metadata": {},
- "source": [
- "#### Passing keys 🔑"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "80fce33f",
- "metadata": {},
- "source": [
- "Keys can be obtained e.g. directly from **activity browser** and several keys can be passed at the same time."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "167a2bfb",
- "metadata": {},
- "outputs": [],
- "source": [
- "keys = [\"('cutoff38', 'a834063e527dafabe7d179a804a13f39')\", \"('cutoff38', 'b665bad6dd31cc988da3d434d5293b60')\"]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b46fa327",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(keys=keys)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "daf88526",
- "metadata": {},
- "source": [
- "#### Passing activity name (⚙️), reference_product (📦) and/or location (🗺️)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4074fec3",
- "metadata": {},
- "source": [
- "Instead of passing the keys, a combination of activities, reference_products and locations can be passed. A best match (all existing combinations) will be returned. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4d445dfc",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"market for hydrogen, liquid\"]\n",
- "reference_products = [\"hydrogen, liquid\"]\n",
- "locations = [\"RER\"]"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5d0976d1",
- "metadata": {},
- "source": [
- "It is also possible to pass only partial information such as only reference product or only activity name:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "0cb7d84f",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(activities=activities)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b211d17a",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.retrieve_activities(reference_products=reference_products)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "03e8a151",
- "metadata": {},
- "source": [
- "Let's retrieve the activity of our functional unit and specify the demand as a dictionary:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "332b2f95",
- "metadata": {},
- "outputs": [],
- "source": [
- "hydrogen_market = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1959b64f",
- "metadata": {},
- "outputs": [],
- "source": [
- "hydrogen_market"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7cf0adef",
- "metadata": {},
- "source": [
- "Setting a demand of 100 kg of hydrogen"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "223e1cf1",
- "metadata": {},
- "outputs": [],
- "source": [
- "demand = {hydrogen_market[0]: 100}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "992d6029",
- "metadata": {},
- "source": [
- "### Specify the **choices**"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4b6d561a",
- "metadata": {},
- "source": [
- "The choices are specified similar to the demand / functional unit. First, search for the equivalent activities."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d704a9a5",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"chlor-alkali electrolysis, diaphragm cell\", \n",
- " \"chlor-alkali electrolysis, membrane cell\",\n",
- " \"chlor-alkali electrolysis, mercury cell\",\n",
- " \"hydrogen cracking, APME\"]\n",
- "reference_products = [\"hydrogen, liquid\"]\n",
- "locations = [\"RER\"]\n",
- "\n",
- "hydrogen_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9d8fac69",
- "metadata": {},
- "outputs": [],
- "source": [
- "hydrogen_activities"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d9a512a5",
- "metadata": {},
- "source": [
- "Specify also the choices as a dictionary. Be aware, that this time we are dealing with a dictionary of dictionaries. Each inner dictionary corresponds to one type of choice in the background! Here, we only consider choices between hydrogen production activities, so we assign the key \"hydrogen\" to the equivalent product they produce. The next showcase demonstrates a case where two types of choices are considered. \n",
- "\n",
- "The assigned value in the inner dictionary is the capacity limit of this activity. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bfae6af4",
- "metadata": {},
- "outputs": [],
- "source": [
- "choices = {'hydrogen': {hydrogen_activities[0]: 10000,\n",
- " hydrogen_activities[1]: 10000,\n",
- " hydrogen_activities[2]: 10000,\n",
- " hydrogen_activities[3]: 10000}}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "25f8cf77",
- "metadata": {},
- "source": [
- "
\n",
- "
(3) Solution \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a90008f",
- "metadata": {},
- "source": [
- "### Instantiate the worker"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "be46ea2d",
- "metadata": {},
- "outputs": [],
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "20353834",
- "metadata": {},
- "source": [
- "### Solve the instance"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "43da9882",
- "metadata": {},
- "source": [
- "When specifying a valid GAMS_PATH with a licence for CPLEX, as shown below, CPLEX with fine-tuned parameters is automatically selected to solve the Linear Problem (LP).\n",
- "\n",
- "If no GAMS_PATH is specified, the \"[HiGHS](https://highs.dev/)\" solver is automatically used. It has almost double the run time of \"CPLEX\"."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "eb13ed22",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "results = pulpo_worker.solve()\n",
- "# Alternatively using GAMS (cplex) solvers:\n",
- "# results = pulpo_worker.solve(GAMS_PATH=GAMS_PATH)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "916c7e48",
- "metadata": {},
- "source": [
- "### Save and summarize the results"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "cba63697",
- "metadata": {},
- "source": [
- "The \"**save_results()**\" function will save the results in an processed format to an excel file in the data folder that has been specified at the beginning."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cf427cea",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='hydrogen_showcase_results.xlsx')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4c4a1df1",
- "metadata": {},
- "source": [
- "There is another function to summarize the results in dataframe form within jupyter notbeooks calles \"summarize_results\". This function has similar inputs to the \"save_results\" function, but does not require the specification of a filename. Additionally, by specifying the \"zeroes\" parameter to \"True\" all the not-selected choices are omitted in the summary."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f6141497",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f5893613",
- "metadata": {},
- "source": [
- "# Closing Remarks"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c1b2f442",
- "metadata": {},
- "source": [
- "This is the end of the very basic PULPO functionalities using the hydrogen case study. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "b5298095",
- "metadata": {},
- "source": [
- "The following sections will dive deeper into additional functionalities."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "602c9d5e",
- "metadata": {},
- "source": [
- "
\n",
- "
Additional Constraints \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e277bb96",
- "metadata": {},
- "source": [
- "Let's assess what happens if the \"hydrogen cracking, APME\" activity is indirectly constrained trough a restriction on \"treatment of spoil from hard coal mining, in surface landfill\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "04b68998",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"treatment of waste cement, hydrated, residual material landfill\"]\n",
- "reference_products = [\"waste cement, hydrated\"]\n",
- "locations = [\"CH\"]\n",
- "\n",
- "mining = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "aebdc35c",
- "metadata": {},
- "outputs": [],
- "source": [
- "mining"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a89c6ee5",
- "metadata": {},
- "outputs": [],
- "source": [
- "upper_limit = {mining[0]: 0.4}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "da61b77d",
- "metadata": {},
- "source": [
- "The rationale behind choosing this activity and this limit is based on inspection of the scaling vector of the previous results. This activity is limiting for the cracking activity but not for the electrolysis ones, so to enforce a different result than before, this activity is constrained."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "87267aa9",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit=upper_limit)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "a03f1671",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5f409b26",
- "metadata": {},
- "source": [
- "As can be seen from the summary above, part of the final hydrogen demand is supplied by the membrane cell electrolysis, because the hydrogen cracking case study is constrained by the mining activity. It is also evident that the impact is higher than the previous one, as the most suitable activity (hydrogen cracking) can no longer supply the full demand."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "48249a97",
- "metadata": {},
- "source": [
- "
\n",
- "
Additional Methods \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a455b7b",
- "metadata": {},
- "source": [
- "Let's see how to evaluate different methods and set them as objectives"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6ccd79d5",
- "metadata": {},
- "outputs": [],
- "source": [
- "if version==\"bw25\":\n",
- " methods = {\"('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')\": 1,\n",
- " \"('ecoinvent-3.8', 'CML 2001 (superseded)', 'terrestrial ecotoxicity', 'TAETP infinite')\": 0}\n",
- "else:\n",
- " methods = {\"('IPCC 2013', 'climate change', 'GWP 100a')\": 1,\n",
- " \"('CML 2001 (superseded)', 'terrestrial ecotoxicity', 'TAETP infinite')\": 0}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8c71c0b9",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "60d4cad9",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cb241deb",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e81c9f8c",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "58aa77d0-0e9b-4b88-b6a3-84cf5701377e",
- "metadata": {},
- "outputs": [],
- "source": [
- "if version==\"bw25\":\n",
- " methods = {\"('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')\": 0,\n",
- " \"('ecoinvent-3.8', 'CML 2001 (superseded)', 'terrestrial ecotoxicity', 'TAETP infinite')\": 1}\n",
- "else:\n",
- " methods = {\"('IPCC 2013', 'climate change', 'GWP 100a')\": 0,\n",
- " \"('CML 2001 (superseded)', 'terrestrial ecotoxicity', 'TAETP infinite')\": 1}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "dfbe2fe3-f3d1-46a0-9a7d-a49af4adb80d",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)\n",
- "if version==\"bw25\":\n",
- " pulpo_worker.intervention_matrix=\"ecoinvent-3.8-biosphere\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ae7f071c-be80-44f3-ad4f-eef0c603a56e",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.get_lci_data()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "46094d6d-9c62-4f46-887f-e28a8e958b85",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "ede20fa6-4883-4dd9-a14b-25faecc27bd7",
- "metadata": {},
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "26fec4c4",
- "metadata": {},
- "source": [
- "
\n",
- "
Lower Level Decisions \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ee72103c",
- "metadata": {},
- "source": [
- "In this case study, we would like to keep the current share of the hydrogen supplied by cracking in the market the same. The choices that we consider on the hydrogen level are between the different electrolsysis activities:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e68e44ef",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"chlor-alkali electrolysis, diaphragm cell\", \n",
- " \"chlor-alkali electrolysis, membrane cell\",\n",
- " \"chlor-alkali electrolysis, mercury cell\"]\n",
- "reference_products = [\"hydrogen, liquid\"]\n",
- "locations = [\"RER\"]\n",
- "\n",
- "hydrogen_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a8f82b5b",
- "metadata": {},
- "source": [
- "Instead of assessing only the **technology** choices, we are invetigating the best **regional** choice for the source of electricity:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "5b5471b2",
- "metadata": {},
- "outputs": [],
- "source": [
- "activities = [\"market for electricity, medium voltage\"]\n",
- "reference_products = [\"electricity, medium voltage\"]\n",
- "locations = [\"AL\",\"AT\",\"BA\",\"BE\",\"BG\",\"BY\",\"CZ\",\"DE\",\"DK\",\"EE\",\"ES\",\"FI\",\"FR\",\"GB\",\"GI\",\"GR\",\"HR\",\"HU\",\"IE\",\"IS\",\"IT\",\"LT\",\"LU\",\"LV\",\"MD\",\"ME\",\"MK\",\"MT\",\"NL\",\"NO\",\"PL\",\"PT\",\"RO\",\"RS\",\"SE\",\"SI\",\"SK\",\"UA\",\"XK\"]\n",
- "elec_activities = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ae575912",
- "metadata": {},
- "source": [
- "The updated choice dictionary looks like this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bc665036",
- "metadata": {},
- "outputs": [],
- "source": [
- "choices = {'hydrogen': {hydrogen: 1000 for hydrogen in hydrogen_activities},\n",
- " 'electricity': {elec: 100000 for elec in elec_activities}}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6db1e764",
- "metadata": {},
- "source": [
- "Instantiating and solving the adapted problem:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "1143473f",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve(GAMS_PATH=GAMS_PATH)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "73eadc47",
- "metadata": {},
- "source": [
- "Visualizing the results"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "d9c7c140",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "18a60969",
- "metadata": {},
- "source": [
- "It is again evident, that the GWP increased (185.4) compared to the best result from the base case (179.4), because not the full demand is fulfilled with hydrogen from cracking. \n",
- "\n",
- "As for the technology and regional choice in the two specified choices, we find that diaphragm cell electrolysis supplied powered by grid electricity from Norway (NO) minimizes the GWP. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d71d8e1c",
- "metadata": {},
- "source": [
- "
\n",
- "
Supply vs. Demand Problem \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "66cb3f62",
- "metadata": {},
- "source": [
- "Finally, let's test and assess the functionality of PULPO to specify supply values rather than demand values. This can be done by setting the lower_limit and the upper_limit of activities to the same value. This will enforce the corresponding scaling vector entry of that activity to the specified value, and activates the slack variable to relax the demand value. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4a3f2eac",
- "metadata": {},
- "source": [
- "This can simply be done by specifying the upper and lower limits rather than the demand (note, we continue with the choices from the previous section):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "89ecef38",
- "metadata": {},
- "outputs": [],
- "source": [
- "upper_limit = {hydrogen_market[0]: 100}\n",
- "lower_limit = {hydrogen_market[0]: 100}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6f72394d",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.instantiate(choices=choices, upper_limit=upper_limit, lower_limit=lower_limit)\n",
- "results = pulpo_worker.solve()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "006b3b87",
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit, zeroes=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6ecc80bf",
- "metadata": {},
- "source": [
- "From the results it can be observed that the resulting GWP is **slightly** lower (185.402 vs. 185.414) than in the previous section, which is due to the fact that previously, a little more than 100kg of hydrogen needed to be produced as somewhere in the background hydrogen was consumed. Now, the production value (supply) of hydrogen is specified, so that hydrogen consumed in the background is accounted for in the specifications.\n",
- "\n",
- "Overall, when specifying supply values instead of demand values, the corresponding scaling vector entries are always smaller."
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.10.16"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/notebooks/pictures/PP_pyrolysis_inventory.png b/notebooks/pictures/PP_pyrolysis_inventory.png
deleted file mode 100644
index 8602f07..0000000
Binary files a/notebooks/pictures/PP_pyrolysis_inventory.png and /dev/null differ
diff --git a/notebooks/pictures/PP_pyrolysis_system_boundaries.png b/notebooks/pictures/PP_pyrolysis_system_boundaries.png
deleted file mode 100644
index f95721c..0000000
Binary files a/notebooks/pictures/PP_pyrolysis_system_boundaries.png and /dev/null differ
diff --git a/notebooks/pictures/PP_regional_choice.png b/notebooks/pictures/PP_regional_choice.png
deleted file mode 100644
index 189d07e..0000000
Binary files a/notebooks/pictures/PP_regional_choice.png and /dev/null differ
diff --git a/notebooks/pictures/PP_ripple_effect.png b/notebooks/pictures/PP_ripple_effect.png
deleted file mode 100644
index 12a809f..0000000
Binary files a/notebooks/pictures/PP_ripple_effect.png and /dev/null differ
diff --git a/notebooks/pictures/PULPO Infogram.png b/notebooks/pictures/PULPO Infogram.png
deleted file mode 100644
index e46e7ac..0000000
Binary files a/notebooks/pictures/PULPO Infogram.png and /dev/null differ
diff --git a/notebooks/pictures/electricity_showcase_1.png b/notebooks/pictures/electricity_showcase_1.png
deleted file mode 100644
index 61d306f..0000000
Binary files a/notebooks/pictures/electricity_showcase_1.png and /dev/null differ
diff --git a/notebooks/pictures/electricity_showcase_2.png b/notebooks/pictures/electricity_showcase_2.png
deleted file mode 100644
index 72e055d..0000000
Binary files a/notebooks/pictures/electricity_showcase_2.png and /dev/null differ
diff --git a/notebooks/pictures/electricity_showcase_3.png b/notebooks/pictures/electricity_showcase_3.png
deleted file mode 100644
index ac3cd75..0000000
Binary files a/notebooks/pictures/electricity_showcase_3.png and /dev/null differ
diff --git a/notebooks/pictures/electricity_showcase_4.png b/notebooks/pictures/electricity_showcase_4.png
deleted file mode 100644
index f66dcdd..0000000
Binary files a/notebooks/pictures/electricity_showcase_4.png and /dev/null differ
diff --git a/notebooks/plastic_showcase.ipynb b/notebooks/plastic_showcase.ipynb
deleted file mode 100644
index fc9bf15..0000000
--- a/notebooks/plastic_showcase.ipynb
+++ /dev/null
@@ -1,2094 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "512986c4-dc9a-4758-bbfb-130278bd8c03",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-30T11:06:45.551434Z",
- "iopub.status.busy": "2024-03-30T11:06:45.551434Z",
- "iopub.status.idle": "2024-03-30T11:06:45.570370Z",
- "shell.execute_reply": "2024-03-30T11:06:45.568377Z",
- "shell.execute_reply.started": "2024-03-30T11:06:45.551434Z"
- }
- },
- "source": [
- "## Plastic Waste Pyrolysis Case Study 🚮♻️\n",
- "\n",
- "This notebook explores the capabilities of PULPO in the context of (simplified) plastic waste pyrolysis. This case study focuses on the conversion of plastic waste into valuable products through pyrolysis technology.\n",
- "\n",
- "Updated by Fabian Lechtenberg, 30.03.2024\n",
- "\n",
- "The key functionalities demonstrated include:\n",
- "\n",
- "- Technology Choice 🛠️\n",
- "- Foreground vs. Background 🎭🌐\n",
- "- Regional Choice 🌍\n",
- "- Alternative Indicators 🔄\n",
- "- Technosphere Capacity Constraint ⛓️\n",
- "- Biosphere Capacity Constraint 🌱⛔\n",
- "- Indicator Constraints 📏\n",
- "- Supply vs. Demand 🔄💼"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "93c8779d-6182-45c6-9cf9-608df6f468ec",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-31T07:48:33.597797Z",
- "iopub.status.busy": "2024-03-31T07:48:33.597797Z",
- "iopub.status.idle": "2024-03-31T07:48:33.611750Z",
- "shell.execute_reply": "2024-03-31T07:48:33.610753Z",
- "shell.execute_reply.started": "2024-03-31T07:48:33.597797Z"
- }
- },
- "source": [
- "
\n",
- "
🚨 Disclaimer: Implementation of Inventories \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0bf61e02-6982-480c-89fd-7618259565c5",
- "metadata": {},
- "source": [
- "In typical LCA applications, especially for attributional / comparative studies, inventories are pre-established or pre-build by the practitioner within LCA databases. The manual steps shown here to create or adjust inventories for the plastic waste pyrolysis case study are illustrative, aimed at demonstrating process customization for this specific context."
- ]
- },
- {
- "cell_type": "code",
- "id": "a56ba1a4-e5ab-4d56-8de6-eb449c917b28",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:20.212772Z",
- "iopub.status.busy": "2024-06-30T13:57:20.211775Z",
- "iopub.status.idle": "2024-06-30T13:57:23.315910Z",
- "shell.execute_reply": "2024-06-30T13:57:23.314914Z",
- "shell.execute_reply.started": "2024-06-30T13:57:20.212772Z"
- }
- },
- "source": [
- "import brightway2 as bw"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "0000ea69-0377-4252-8aad-5abe6a57c12a",
- "metadata": {},
- "source": [
- "**Setup Brightway2 Project**\n",
- "\n",
- "Initializes the Brightway2 project named \"PULPO Final\". It checks if the Ecoinvent database \"cutoff38\" is available.\n"
- ]
- },
- {
- "cell_type": "code",
- "id": "64738a38-ec25-4922-857b-238c23ea8c7c",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.317904Z",
- "iopub.status.busy": "2024-06-30T13:57:23.316907Z",
- "iopub.status.idle": "2024-06-30T13:57:23.379698Z",
- "shell.execute_reply": "2024-06-30T13:57:23.378700Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.317904Z"
- }
- },
- "source": [
- "# Setup Brightway2 project\n",
- "bw.projects.set_current(\"pulpo\")\n",
- "if \"cutoff38\" not in bw.databases:\n",
- " print(\"Ecoinvent database not found. Please import it before running this script.\")\n",
- "else:\n",
- " db = bw.Database(\"cutoff38\")\n",
- " biosphere = bw.Database(\"biosphere3\")"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "79f350b9-d397-411b-a3fd-c6c1e6c4fb88",
- "metadata": {},
- "source": [
- "**System Inventory Overview**\n",
- "\n",
- "The diagram illustrates the inventory flows for the polypropylene (PP) pyrolysis process. Inputs such as electricity, deionized water, and chromium steel are quantified on the left, feeding into the central PP pyrolysis activity. The \"PP waste collected\" is considered a burden-free input, serving as a placeholder for later implementing technical constraints. Outputs of the process include pyrolysis oil and emissions of CO2 and H2O. 🔄🚮🛢️➡️🌎"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6c6611a6-59e9-4cb8-b3f6-89ff1397aa64",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-30T17:30:48.187968Z",
- "iopub.status.busy": "2024-03-30T17:30:48.186973Z",
- "iopub.status.idle": "2024-03-30T17:30:48.195942Z",
- "shell.execute_reply": "2024-03-30T17:30:48.194945Z",
- "shell.execute_reply.started": "2024-03-30T17:30:48.187968Z"
- }
- },
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "76aaf86e-9c72-486b-96d6-e5755886a499",
- "metadata": {},
- "source": [
- "**Create or Check for Waste Polypropylene Process**\n",
- "\n",
- "Retrieve or create a new activity for the collection of PP waste."
- ]
- },
- {
- "cell_type": "code",
- "id": "8a9d4e28-3b6a-4ebb-ab00-53fd4d4b9214",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.383684Z",
- "iopub.status.busy": "2024-06-30T13:57:23.383684Z",
- "iopub.status.idle": "2024-06-30T13:57:23.413663Z",
- "shell.execute_reply": "2024-06-30T13:57:23.410670Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.383684Z"
- }
- },
- "source": [
- "# Check if the empty PP waste process already exists\n",
- "try:\n",
- " pp_waste_process = db.get(\"pp_waste\")\n",
- " print(\"PP waste process already exists, skipping the addition.\")\n",
- "except:\n",
- " pp_waste_process = db.new_activity(\n",
- " code=\"pp_waste\",\n",
- " name=\"PP Waste collected\",\n",
- " unit=\"kilogram\",\n",
- " location=\"Europe without Switzerland\",\n",
- " )\n",
- " pp_waste_process[\"reference product\"] = \"PP waste\"\n",
- " pp_waste_process.save()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "82a9e059-cc56-4eb5-93b1-560cb7b26101",
- "metadata": {},
- "source": [
- "**Create or Check for PP Pyrolysis Process**\n",
- "\n",
- "Retrieve or create a new activity for the PP pyrolysis process, including setting up various technosphere and biosphere exchanges."
- ]
- },
- {
- "cell_type": "code",
- "id": "263125d3-69d4-4250-9895-74d0603aab22",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.415653Z",
- "iopub.status.busy": "2024-06-30T13:57:23.414657Z",
- "iopub.status.idle": "2024-06-30T13:57:23.442563Z",
- "shell.execute_reply": "2024-06-30T13:57:23.441568Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.415653Z"
- }
- },
- "source": [
- "# Check if the PP pyrolysis process already exists\n",
- "try:\n",
- " pp_pyrolysis_process = db.get(\"pp_pyrolysis\")\n",
- " print(\"PP pyrolysis process already exists, skipping the addition.\")\n",
- "except:\n",
- " pp_pyrolysis_process = db.new_activity(\n",
- " code=\"pp_pyrolysis\",\n",
- " name=\"PP pyrolysis process\",\n",
- " unit=\"kilogram\",\n",
- " location=\"Europe without Switzerland\",\n",
- " )\n",
- " pp_pyrolysis_process[\"reference product\"] = \"pyrolysis oil\"\n",
- "\n",
- " # Add technosphere exchanges\n",
- " # PP waste\n",
- " pp = db.search(\"PP Waste collected\")[0]\n",
- " pp_pyrolysis_process.new_exchange(input=pp.key, amount=(26.6)/23.9, type='technosphere').save()\n",
- " # Add electricity input\n",
- " electricities = [act for act in db if \"market group for electricity, high voltage\" in act['name'] and act['location'] == \"Europe without Switzerland\"]\n",
- " electricity = electricities[0] if electricities else None\n",
- " if electricity:\n",
- " pp_pyrolysis_process.new_exchange(input=electricity.key, amount=(7.881+7.368e-2)/23.9, type='technosphere').save()\n",
- " # Add water input\n",
- " water = db.search(\"market for water, deionised\")[0]\n",
- " pp_pyrolysis_process.new_exchange(input=water.key, amount=(1e-4)/23.9, type='technosphere').save() \n",
- " # Add equipment input\n",
- " steel = db.search(\"market for steel, chromium steel 18/8\")[0]\n",
- " pp_pyrolysis_process.new_exchange(input=steel.key, amount=(1.075e-4)/23.9, type='technosphere').save()\n",
- " # Add biosphere exchanges\n",
- " co2 = biosphere.search(\"carbon dioxide\")[0]\n",
- " pp_pyrolysis_process.new_exchange(input=co2.key, amount=(5.278)/23.9, type='biosphere').save()\n",
- " h2o = biosphere.search(\"water, in air\")[0]\n",
- " pp_pyrolysis_process.new_exchange(input=h2o.key, amount=(3.129)/23.9, type='biosphere').save()\n",
- "\n",
- " # Save the activity\n",
- " pp_pyrolysis_process.save()\n",
- " print(\"PP pyrolysis process and its exchanges have been successfully added.\")"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "3a23a090-54e0-4093-922d-3bf57bd891d7",
- "metadata": {},
- "source": [
- "
\n",
- "
Demonstration 🚀 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a34e0fdc-4c51-49a8-a711-f425fd87e0b8",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-30T11:12:35.355473Z",
- "iopub.status.busy": "2024-03-30T11:12:35.355473Z",
- "iopub.status.idle": "2024-03-30T11:12:35.376455Z",
- "shell.execute_reply": "2024-03-30T11:12:35.375459Z",
- "shell.execute_reply.started": "2024-03-30T11:12:35.355473Z"
- }
- },
- "source": [
- "With the inventories now defined, we're stepping into the practical demonstration of our plastic waste pyrolysis case study.\n"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a50bdeff-8d89-493c-afe2-414babf31166",
- "metadata": {},
- "source": [
- "In these code snippets, we're setting up the environment and preparing for an analysis with the Pulpo framework:"
- ]
- },
- {
- "cell_type": "code",
- "id": "33cda03a-3488-4447-8609-f3c3c3bc8cec",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.446551Z",
- "iopub.status.busy": "2024-06-30T13:57:23.445554Z",
- "iopub.status.idle": "2024-06-30T13:57:23.869228Z",
- "shell.execute_reply": "2024-06-30T13:57:23.868232Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.446551Z"
- }
- },
- "source": [
- "import os\n",
- "import sys\n",
- "sys.path.append('../') ### not necessary if pulpo is pip installed!\n",
- "from pulpo import pulpo\n",
- "\n",
- "import pandas as pd\n",
- "pd.set_option('display.max_colwidth', None)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "a1910169-9386-4067-ab86-407610e2b4eb",
- "metadata": {},
- "source": [
- "This segment of the code is focused on defining key parameters and paths for the analysis:\n",
- "\n",
- "- **Project and Database**: Specifies the Brightway2 project (`\"pulpo\"`) and database (`\"cutoff38\"`) to be used for the life cycle assessment.\n",
- "- **Methods**: Sets the impact assessment method to IPCC 2013 GWP 100a, a widely recognized standard for evaluating global warming potential.\n",
- "- **Directory Paths**: Configures the working directory (`directory`) relative to the notebook's location for storing and accessing data files.\n",
- "- **GAMS Path**: Establishes the file path to the GAMS executable (`GAMS_PATH`), integrating the GAMS optimization software with our Python environment for performing complex optimization tasks.\n",
- "\n",
- "
**Note:** Instead of GAMS, HiGHS, an open-source linear and nonlinear solver, can also be used for optimization tasks."
- ]
- },
- {
- "cell_type": "code",
- "id": "d1da19fa-555d-4e0b-bffc-b3e6dd931e23",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.870225Z",
- "iopub.status.busy": "2024-06-30T13:57:23.870225Z",
- "iopub.status.idle": "2024-06-30T13:57:23.887168Z",
- "shell.execute_reply": "2024-06-30T13:57:23.884185Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.870225Z"
- }
- },
- "source": [
- "project = \"pulpo\"\n",
- "database = \"cutoff38\"\n",
- "methods = \"('IPCC 2013', 'climate change', 'GWP 100a')\"\n",
- "\n",
- "# Substitute with your working directory of choice\n",
- "notebook_dir = os.path.dirname(os.getcwd())\n",
- "directory = os.path.join(notebook_dir, 'data')\n",
- "\n",
- "# Substitute with your GAMS path\n",
- "GAMS_PATH = \"C:/GAMS/37/gams.exe\""
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "ff9723e8-002a-4893-8738-604afd7c5e65",
- "metadata": {},
- "source": [
- "Initialize a Pulpo object by passing the key parameters and paths to the PulpoOptimizer class:"
- ]
- },
- {
- "cell_type": "code",
- "id": "cafc2ad9-575e-41a4-ba70-6af9660adb02",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.890161Z",
- "iopub.status.busy": "2024-06-30T13:57:23.889162Z",
- "iopub.status.idle": "2024-06-30T13:57:23.901122Z",
- "shell.execute_reply": "2024-06-30T13:57:23.900125Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.890161Z"
- }
- },
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods, directory)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "d1df751a-dfff-48d7-899b-4d7e8f0ca594",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-31T07:47:46.947508Z",
- "iopub.status.busy": "2024-03-31T07:47:46.947508Z",
- "iopub.status.idle": "2024-03-31T07:47:46.957474Z",
- "shell.execute_reply": "2024-03-31T07:47:46.956477Z",
- "shell.execute_reply.started": "2024-03-31T07:47:46.947508Z"
- }
- },
- "source": [
- "
\n",
- "
Technology choice 🛠️ and fore- vs. background optimization 🎭🌐 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3bc58aef-6c20-4219-ad0d-ceb0afd17f79",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-30T18:00:09.433988Z",
- "iopub.status.busy": "2024-03-30T18:00:09.432991Z",
- "iopub.status.idle": "2024-03-30T18:00:09.453921Z",
- "shell.execute_reply": "2024-03-30T18:00:09.452925Z",
- "shell.execute_reply.started": "2024-03-30T18:00:09.433988Z"
- }
- },
- "source": [
- "In the forthcoming segment, we delve into a comparative demonstration focused on alternative technologies:\n",
- "\n",
- "- **Pyrolysis Oil** 🚮⛽\n",
- "- **Fossil Diesel** 🦕⛽\n",
- "- **Biodiesel** 🌱⛽\n",
- "\n",
- "We'll also examine two contrasting optimization strategies:\n",
- "\n",
- "1. **Decoupled (Offline) Optimization** Assessing the market in a vacuum, disconnected from wider technosphere / economy dynamics.\n",
- "2. **Integrated (Simultaneous) Optimization** Conducting a holistic technosphere optimization, considering the ripple effects and feedback from market changes."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c2fb4314-7eee-4646-9286-c03c9a32aba7",
- "metadata": {},
- "source": [
- "**Retrieving Necessary Activities for Assessment**\n",
- "\n",
- "Below, we fetch the essential activities for our analysis. The system under review is illustrated in the figure that follows. 📉👇"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "aa732440-bd14-4356-aa8a-8064c195bd28",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-30T18:04:21.157485Z",
- "iopub.status.busy": "2024-03-30T18:04:21.157485Z",
- "iopub.status.idle": "2024-03-30T18:04:21.175468Z",
- "shell.execute_reply": "2024-03-30T18:04:21.175468Z",
- "shell.execute_reply.started": "2024-03-30T18:04:21.157485Z"
- }
- },
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f9f7d950-ee6d-4bc7-a1b6-940ec1389c5d",
- "metadata": {},
- "source": [
- "**Diesel Market**\n"
- ]
- },
- {
- "cell_type": "code",
- "id": "129a190a-0397-4aaa-baa0-9154a050bc14",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.903115Z",
- "iopub.status.busy": "2024-06-30T13:57:23.902119Z",
- "iopub.status.idle": "2024-06-30T13:57:23.917069Z",
- "shell.execute_reply": "2024-06-30T13:57:23.916072Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.902119Z"
- }
- },
- "source": [
- "activities = [\"market for diesel\"]\n",
- "reference_products = [\"diesel\"]\n",
- "locations = [\"Europe without Switzerland\"]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "a349fae8-ef67-4135-b7a9-a5ac9db84bc2",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:23.919062Z",
- "iopub.status.busy": "2024-06-30T13:57:23.919062Z",
- "iopub.status.idle": "2024-06-30T13:57:27.053714Z",
- "shell.execute_reply": "2024-06-30T13:57:27.053714Z",
- "shell.execute_reply.started": "2024-06-30T13:57:23.919062Z"
- }
- },
- "source": [
- "diesel_market = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "857c4d88-bcc6-41f3-b91e-2db2eb16724d",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:27.055744Z",
- "iopub.status.busy": "2024-06-30T13:57:27.054709Z",
- "iopub.status.idle": "2024-06-30T13:57:28.037360Z",
- "shell.execute_reply": "2024-06-30T13:57:28.036362Z",
- "shell.execute_reply.started": "2024-06-30T13:57:27.055744Z"
- }
- },
- "source": [
- "from helper import copy_activity\n",
- "diesel_market_foreground = copy_activity(diesel_market)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "3effbf0d-6778-4bdb-83e8-9342f6721b3b",
- "metadata": {},
- "source": [
- "**Diesel Production**"
- ]
- },
- {
- "cell_type": "code",
- "id": "645d9806-e6eb-46e3-93af-eacf325757cb",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:28.038355Z",
- "iopub.status.busy": "2024-06-30T13:57:28.038355Z",
- "iopub.status.idle": "2024-06-30T13:57:28.052308Z",
- "shell.execute_reply": "2024-06-30T13:57:28.052308Z",
- "shell.execute_reply.started": "2024-06-30T13:57:28.038355Z"
- }
- },
- "source": [
- "activities = [\"diesel production, petroleum refinery operation\"]\n",
- "reference_products = [\"diesel\"]\n",
- "locations = [\"Europe without Switzerland\"]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "9b369b84-b663-4cf4-8bd7-321e6e02de88",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:28.054303Z",
- "iopub.status.busy": "2024-06-30T13:57:28.054303Z",
- "iopub.status.idle": "2024-06-30T13:57:29.038745Z",
- "shell.execute_reply": "2024-06-30T13:57:29.036752Z",
- "shell.execute_reply.started": "2024-06-30T13:57:28.054303Z"
- }
- },
- "source": [
- "diesel_fossil = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "e58777d6-8be6-49e0-9db0-4a7314ccf84d",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:29.039741Z",
- "iopub.status.busy": "2024-06-30T13:57:29.039741Z",
- "iopub.status.idle": "2024-06-30T13:57:30.099482Z",
- "shell.execute_reply": "2024-06-30T13:57:30.099482Z",
- "shell.execute_reply.started": "2024-06-30T13:57:29.039741Z"
- }
- },
- "source": [
- "diesel_fossil_foreground = copy_activity(diesel_fossil)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "fd68811f-cd0d-4b91-9fc2-1275c667e489",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:30.101475Z",
- "iopub.status.busy": "2024-06-30T13:57:30.100479Z",
- "iopub.status.idle": "2024-06-30T13:57:30.115429Z",
- "shell.execute_reply": "2024-06-30T13:57:30.115429Z",
- "shell.execute_reply.started": "2024-06-30T13:57:30.100479Z"
- }
- },
- "source": [
- "activities = [\"soybean oil refinery operation\"]\n",
- "reference_products = [\"soybean oil, refined\"]\n",
- "locations = [\"RoW\"]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "e7b1e593-30a9-4996-b1ba-a79fcc573439",
- "metadata": {},
- "source": [
- "**Biodiesel Production**"
- ]
- },
- {
- "cell_type": "code",
- "id": "e613439b-9a42-4b32-8e23-c92113c7bacc",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:30.117422Z",
- "iopub.status.busy": "2024-06-30T13:57:30.116426Z",
- "iopub.status.idle": "2024-06-30T13:57:31.197550Z",
- "shell.execute_reply": "2024-06-30T13:57:31.197550Z",
- "shell.execute_reply.started": "2024-06-30T13:57:30.117422Z"
- }
- },
- "source": [
- "diesel_bio = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "208dbb7f-00cc-4b3d-bb2e-a493ab95dde2",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:31.198547Z",
- "iopub.status.busy": "2024-06-30T13:57:31.198547Z",
- "iopub.status.idle": "2024-06-30T13:57:32.185718Z",
- "shell.execute_reply": "2024-06-30T13:57:32.185718Z",
- "shell.execute_reply.started": "2024-06-30T13:57:31.198547Z"
- }
- },
- "source": [
- "diesel_bio_foreground = copy_activity(diesel_bio)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "2a058f29-e599-4d8e-aa7b-2349e512727c",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:32.186714Z",
- "iopub.status.busy": "2024-06-30T13:57:32.186714Z",
- "iopub.status.idle": "2024-06-30T13:57:32.202663Z",
- "shell.execute_reply": "2024-06-30T13:57:32.201666Z",
- "shell.execute_reply.started": "2024-06-30T13:57:32.186714Z"
- }
- },
- "source": [
- "activities = [\"PP pyrolysis process\"]\n",
- "reference_products = [\"pyrolysis oil\"]\n",
- "locations = [\"Europe without Switzerland\"]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "f40b25a8-c16c-40b8-bea9-a91a634fb567",
- "metadata": {},
- "source": [
- "**Pyrolysis Oil Production**"
- ]
- },
- {
- "cell_type": "code",
- "id": "5d02aff8-9914-4f2f-bf00-29f1304df2d7",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:32.203658Z",
- "iopub.status.busy": "2024-06-30T13:57:32.202663Z",
- "iopub.status.idle": "2024-06-30T13:57:33.459295Z",
- "shell.execute_reply": "2024-06-30T13:57:33.459295Z",
- "shell.execute_reply.started": "2024-06-30T13:57:32.203658Z"
- }
- },
- "source": [
- "diesel_pp = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=locations)[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "546e2288-0207-443e-95e0-8bebff83a506",
- "metadata": {},
- "source": [
- "Once all inventories have been fetched, load the LCI data to the Pulpo worker:"
- ]
- },
- {
- "cell_type": "code",
- "id": "0e80cbc6-62f2-427a-a900-1e39b1dfe310",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:33.460292Z",
- "iopub.status.busy": "2024-06-30T13:57:33.460292Z",
- "iopub.status.idle": "2024-06-30T13:57:34.857163Z",
- "shell.execute_reply": "2024-06-30T13:57:34.857163Z",
- "shell.execute_reply.started": "2024-06-30T13:57:33.460292Z"
- }
- },
- "source": [
- "pulpo_worker.get_lci_data()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "6b5da7e6-c017-40ab-9e6b-4a5370a61c8d",
- "metadata": {},
- "source": [
- "**No optimization**"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ddf19cdc-ef3b-44b7-8aa8-81f312f5892e",
- "metadata": {},
- "source": [
- "In this segment, we're setting up a comparative LCA for three different types of diesel without optimization.\n",
- "\n",
- "For each fuel type, we are evaluating the environmental impact associated with the production of 1 kilogram. The assessment is conducted using a suite of impact assessment methods:\n",
- "\n",
- "- **Global Warming Potential (GWP)**: Assessed over 100 years as per IPCC 2013.\n",
- "- **Land Use Change GWP100**: Evaluates climate impact specifically from land use and land use change.\n",
- "- **Freshwater Eutrophication**: Measures the potential impact of nutrient enrichment in freshwater ecosystems.\n",
- "- **Ionising Radiation Human Health**: Estimates the exposure efficiency to ionizing radiation and its effect on human health."
- ]
- },
- {
- "cell_type": "code",
- "id": "15c3c94d-fef1-43ce-ae22-48927fa2bd18",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:57:34.858161Z",
- "iopub.status.busy": "2024-06-30T13:57:34.858161Z",
- "iopub.status.idle": "2024-06-30T13:59:18.379992Z",
- "shell.execute_reply": "2024-06-30T13:59:18.379667Z",
- "shell.execute_reply.started": "2024-06-30T13:57:34.858161Z"
- }
- },
- "source": [
- "functional_units = [\n",
- " {diesel_bio: 1}, # 1 kg of biodiesel\n",
- " {diesel_pp: 1}, # 1 kg of diesel from PP\n",
- " {diesel_fossil: 1} # 1 kg of fossil diesel\n",
- "]\n",
- "\n",
- "methods_list = [\n",
- " (\"IPCC 2013\", \"climate change\", \"GWP 100a\"),\n",
- " (\"EF v3.0\", \"climate change: land use and land use change\", \"global warming potential (GWP100)\"),\n",
- " (\"EF v3.0\", \"eutrophication: freshwater\", \"fraction of nutrients reaching freshwater end compartment (P)\"),\n",
- " (\"EF v3.0\", \"ionising radiation: human health\", \"human exposure efficiency relative to u235\"),\n",
- "]\n",
- "\n",
- "my_calculation_setup = {'inv': functional_units, 'ia': methods_list}\n",
- "bw.calculation_setups['diesel_comparison'] = my_calculation_setup\n",
- "mlca = bw.MultiLCA('diesel_comparison')"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "0fe58313-6136-453e-aacd-3c4295ed05ad",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:18.380211Z",
- "iopub.status.busy": "2024-06-30T13:59:18.380211Z",
- "iopub.status.idle": "2024-06-30T13:59:18.660529Z",
- "shell.execute_reply": "2024-06-30T13:59:18.659819Z",
- "shell.execute_reply.started": "2024-06-30T13:59:18.380211Z"
- }
- },
- "source": [
- "import pandas as pd\n",
- "from IPython.display import display\n",
- "\n",
- "# Define the names of the activities and methods based on your setup\n",
- "activity_names = ['Biodiesel', 'Diesel from PP', 'Fossil Diesel']\n",
- "\n",
- "# Convert the mlca.results array to a DataFrame\n",
- "results_df = pd.DataFrame(\n",
- " mlca.results, \n",
- " index=activity_names, \n",
- " columns=methods_list\n",
- ")\n",
- "\n",
- "# Define a custom function to apply colors based on ranking within each column\n",
- "def highlight_by_column_rank(s):\n",
- " is_max = s == s.max()\n",
- " is_min = s == s.min()\n",
- " # Assign colors: red for max, green for min, orange for others\n",
- " return ['background-color: red' if v else 'background-color: green' if m else 'background-color: orange' for v, m in zip(is_max, is_min)]\n",
- "\n",
- "# Apply the styling for each column\n",
- "styled_df = results_df.style.format(\"{:.2e}\")\n",
- "styled_df = styled_df.apply(highlight_by_column_rank, axis=0)\n",
- "\n",
- "# Display the styled DataFrame\n",
- "display(styled_df)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "f7b9dc7e-5eba-4429-9afe-fb2376b2a93b",
- "metadata": {},
- "source": [
- "The table showcases the comparative LCA results across different diesel options, color-coded to indicate the lowest (green), middle (orange), and highest (red) environmental impacts in each category. Biodiesel shows a higher GWP 100a, while Diesel from PP demonstrates potential as the least impactful in the GWP category. As we move to optimize for GWP, the preliminary data suggests that pyrolysis diesel might minimize the impact. However, the extent of this benefit, especially when considering technical constraints and the distinction between decoupled and integrated optimization results, remains to be explored in the following sections."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "8320b759-0228-4016-9ec6-d84d63fc53fe",
- "metadata": {},
- "source": [
- "**Foreground Assessment** 🎭"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4bc49008-2601-49b8-a861-e8663b88bd2f",
- "metadata": {},
- "source": [
- "Specify the demand of the assessment as 1 kg of diesel from the *foreground* diesel market:"
- ]
- },
- {
- "cell_type": "code",
- "id": "013db433-bf2c-44d1-a69c-1757f5df3c1c",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:18.661657Z",
- "iopub.status.busy": "2024-06-30T13:59:18.660529Z",
- "iopub.status.idle": "2024-06-30T13:59:18.664090Z",
- "shell.execute_reply": "2024-06-30T13:59:18.663948Z",
- "shell.execute_reply.started": "2024-06-30T13:59:18.661657Z"
- }
- },
- "source": [
- "demand = {diesel_market_foreground: 1}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "9392b436-a02c-43ba-8f49-62be3d99fb12",
- "metadata": {},
- "source": [
- "Specify the choices of the assessment as the three diesel production alternatives:"
- ]
- },
- {
- "cell_type": "code",
- "id": "fb7585bc-6084-4e69-85f4-6118bdb448c6",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:18.664090Z",
- "iopub.status.busy": "2024-06-30T13:59:18.664090Z",
- "iopub.status.idle": "2024-06-30T13:59:18.679715Z",
- "shell.execute_reply": "2024-06-30T13:59:18.679715Z",
- "shell.execute_reply.started": "2024-06-30T13:59:18.664090Z"
- }
- },
- "source": [
- "choices = {'diesel': {diesel_bio_foreground: 10,\n",
- " diesel_fossil_foreground: 10,\n",
- " diesel_pp: 10}}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "2fdc9222-b711-4640-868b-64a6a8265035",
- "metadata": {},
- "source": [
- "Instantiate and solve the problem:"
- ]
- },
- {
- "cell_type": "code",
- "id": "b75c116a-7645-42f3-9233-7eea0e8ef3a9",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:18.679715Z",
- "iopub.status.busy": "2024-06-30T13:59:18.679715Z",
- "iopub.status.idle": "2024-06-30T13:59:40.802055Z",
- "shell.execute_reply": "2024-06-30T13:59:40.802055Z",
- "shell.execute_reply.started": "2024-06-30T13:59:18.679715Z"
- }
- },
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "994b077f-3bb8-4b51-a2ab-17840cbffca0",
- "metadata": {},
- "source": [
- "Summarize the results:"
- ]
- },
- {
- "cell_type": "code",
- "id": "4de2467c-f0b7-4d10-8b19-f0f97c145b49",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:40.802055Z",
- "iopub.status.busy": "2024-06-30T13:59:40.802055Z",
- "iopub.status.idle": "2024-06-30T13:59:40.852199Z",
- "shell.execute_reply": "2024-06-30T13:59:40.852199Z",
- "shell.execute_reply.started": "2024-06-30T13:59:40.802055Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "a3e8379b-c0d5-442c-a1c2-db3435935f8f",
- "metadata": {},
- "source": [
- "**Background Assessment** 🌐"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7acdbce1-26bc-4819-a5ca-5c3cf12a2819",
- "metadata": {},
- "source": [
- "Specify the demand of the assessment as 1 kg of diesel from the *original* diesel market which is connected to all other processes of the LCI database:"
- ]
- },
- {
- "cell_type": "code",
- "id": "ef7be8cd-5776-4e7d-ace2-bdf82b2a44bb",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:40.853192Z",
- "iopub.status.busy": "2024-06-30T13:59:40.853192Z",
- "iopub.status.idle": "2024-06-30T13:59:40.867901Z",
- "shell.execute_reply": "2024-06-30T13:59:40.867901Z",
- "shell.execute_reply.started": "2024-06-30T13:59:40.853192Z"
- }
- },
- "source": [
- "demand = {diesel_market: 1}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "53779561-671c-4e70-b303-f844d24e83bc",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:40.868901Z",
- "iopub.status.busy": "2024-06-30T13:59:40.868901Z",
- "iopub.status.idle": "2024-06-30T13:59:40.881157Z",
- "shell.execute_reply": "2024-06-30T13:59:40.881157Z",
- "shell.execute_reply.started": "2024-06-30T13:59:40.868901Z"
- }
- },
- "source": [
- "choices = {'diesel': {diesel_bio: 10,\n",
- " diesel_fossil: 10,\n",
- " diesel_pp: 10}}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "632b04a6-1a9f-4499-881c-e3bbc4140183",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T13:59:40.881157Z",
- "iopub.status.busy": "2024-06-30T13:59:40.881157Z",
- "iopub.status.idle": "2024-06-30T14:00:04.662000Z",
- "shell.execute_reply": "2024-06-30T14:00:04.661242Z",
- "shell.execute_reply.started": "2024-06-30T13:59:40.881157Z"
- }
- },
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "b99cb105-6d3f-4f19-8331-7e256e7c342e",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:04.662000Z",
- "iopub.status.busy": "2024-06-30T14:00:04.662000Z",
- "iopub.status.idle": "2024-06-30T14:00:04.711285Z",
- "shell.execute_reply": "2024-06-30T14:00:04.711285Z",
- "shell.execute_reply.started": "2024-06-30T14:00:04.662000Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "e0e5e675-8283-4ed0-8b10-0a2bddca748f",
- "metadata": {},
- "source": [
- "The optimization analysis reaffirms our expectations: pyrolysis oil emerges as the preferable choice, with its corresponding alpha (α) parameter set to \"1\", indicating full selection in the optimized mix.\n",
- "\n",
- "When contrasting the \"foreground\" (market-specific) with the \"background\" (economy-wide) optimization scenarios, we observe a marginal disparity: the foreground scenario yields a GWP of **0.373366 kg CO
2 e**, while the background scenario presents a marginally lower GWP of **0.373292 kg CO
2 e**. This small difference is attributable to the ripple effects of the diesel market's lower impacts cascading upstream, thereby slightly reducing the overall environmental burden.\n",
- "\n",
- "Notably, the scaling vector for PP pyrolysis, s
diesel_PP , which represents the level of utilization of pyrolysis oil, remains consistent at \"1\" in the foreground scenario—signifying exclusive use within the market. In contrast, the background scenario, which integrates the technology economy-wide, reflects a subtle uptick in utilization to s
diesel_PP = 1.000713. This represents a 0.07% increment, hinting at a small but noteworthy expansion in demand when the technology is adopted across the broader economy. \n",
- "\n",
- "The following illustration shows two example paths that are affected by the change in the market composition, which are omitted in the foreground scenario 📉👇 "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c307d5d5-727f-4e16-9556-63099bbc8b07",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-31T13:54:22.768890Z",
- "iopub.status.busy": "2024-03-31T13:54:22.768890Z",
- "iopub.status.idle": "2024-03-31T13:54:22.777859Z",
- "shell.execute_reply": "2024-03-31T13:54:22.776863Z",
- "shell.execute_reply.started": "2024-03-31T13:54:22.768890Z"
- }
- },
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3f18cdaa-f2e6-4f46-b5b5-97b18f715ce8",
- "metadata": {},
- "source": [
- "The more direct route originates from the diesel market and proceeds to the freight train transport activity. This activity subsequently feeds into the transport market, which in turn serves as an input back to the diesel market, thus establishing a feedback loop. Such a loop allows any changes in the environmental impact of the diesel market to feed back to the diesel market, influencing its own impact."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4a5ca882-432f-4100-8738-624284d59573",
- "metadata": {},
- "source": [
- "A secondary feedback loop is illustrated as follows: it starts from the \"market for transport, freight train\" and moves to the market for lignite. This, in sequence, contributes to the production of electricity from lignite, which is part of the German electricity mix. The German mix then plays a role in the European electricity mix, which, in turn, is a key input for the plastic pyrolysis process. This interconnected loop exemplifies how changes within one segment can propagate through the entire energy supply chain, ultimately affecting the pyrolysis process and the diesel market itself."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ceb07d33-4895-4b6c-b48c-f7694f61a9f0",
- "metadata": {},
- "source": [
- "See [this showcase](electricity_showcase.ipynb) for an example with a much larger ripple effect! "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f9fc48c0-725f-4533-8730-081a77f29341",
- "metadata": {},
- "source": [
- "
\n",
- "
Regional choice 🌍 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "add6e5c7-6355-4ac4-92d1-72cb0fbee021",
- "metadata": {},
- "source": [
- "Our previous assessment concentrated on evaluating **technology choices**. Now, we shift our focus to **regional selections**, simultaneously considering various European sourcing options for electricity. By specifying the PP pyrolysis process to accept electricity from the broader EUR electricity market group, we allow for the possibility of drawing power from any eligible national electricity markets within Europe.\n",
- "\n",
- "From a mathematical standpoint, the distinction between technological and regional choices is subtle, as both essentially involve selecting from explicitly modeled **processes** within the Life Cycle Inventory (LCI) database. Whether differentiating by technology or by geographic origin, the underlying computational approach remains consistent."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "680abe18-0b81-4752-bc5f-271888a05ac9",
- "metadata": {},
- "source": [
- "In our expanded analysis, we introduce \"electricity\" as a new choice alongside \"diesel.\" Now, the electricity used in the PP pyrolysis process can come from any national market within Europe, not just the European mix. This addition opens up 40 different alternatives, complicating the decision-making process as each choice has implications for multiple impact categories and can directly or indirectly affect the other technologies. Determining the optimal choice in this intricate network of possibilities presents a more complex challenge 📉👇 "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "82cf253c-6bad-457f-9ada-de8e6611131c",
- "metadata": {},
- "source": [
- "
\n",
- "
\n",
- "
"
- ]
- },
- {
- "cell_type": "code",
- "id": "cf3ab0a2-d544-4280-b9c7-57ccd7610454",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:04.711285Z",
- "iopub.status.busy": "2024-06-30T14:00:04.711285Z",
- "iopub.status.idle": "2024-06-30T14:00:04.725614Z",
- "shell.execute_reply": "2024-06-30T14:00:04.725614Z",
- "shell.execute_reply.started": "2024-06-30T14:00:04.711285Z"
- }
- },
- "source": [
- "country_codes = [\n",
- " \"FR\", \"DE\", \"GB\", \"IT\", \"ES\", \"PL\", \"UA\", \"SE\", \"NO\", \"NL\",\n",
- " \"FI\", \"BE\", \"AT\", \"CZ\", \"GR\", \"RO\", \"PT\", \"HU\", \"RS\", \"BG\",\n",
- " \"BY\", \"DK\", \"IE\", \"SK\", \"IS\", \"HR\", \"SI\", \"BA\", \"LT\", \"MK\",\n",
- " \"AL\", \"EE\", \"LU\", \"LV\", \"MD\", \"ME\", \"XK\", \"MT\", \"GI\"\n",
- "]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "1bc0079a-d36d-4b15-b071-4472fc211bea",
- "metadata": {},
- "source": [
- "Now let's use a Pulpo function to retrieve the corresponding electricity markets. The function \"retrieve_activities\" of the worker allows us to specify the activity names, the reference product, or the locations and will return the best match:"
- ]
- },
- {
- "cell_type": "code",
- "id": "b6968ff5-93db-4545-85cd-38296333b59a",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:04.725614Z",
- "iopub.status.busy": "2024-06-30T14:00:04.725614Z",
- "iopub.status.idle": "2024-06-30T14:00:06.224371Z",
- "shell.execute_reply": "2024-06-30T14:00:06.223909Z",
- "shell.execute_reply.started": "2024-06-30T14:00:04.725614Z"
- }
- },
- "source": [
- "activities = [\"market for electricity, high voltage\"]\n",
- "reference_products = [\"electricity, high voltage\"]\n",
- "# Get regional markets\n",
- "electricity_markets = pulpo_worker.retrieve_activities(activities=activities, reference_products=reference_products, locations=country_codes)\n",
- "# Get european market\n",
- "electricity_markets.append(pulpo_worker.retrieve_activities(activities=[\"market group for electricity, high voltage\"],\n",
- " reference_products=reference_products,\n",
- " locations=[\"Europe without Switzerland\"])[0])\n",
- "\n",
- "print(f\"A total of {len(electricity_markets)} electricity markets have been retrieved.\")"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "1d15eac8-1181-46a3-9eb4-da35af2e73ac",
- "metadata": {},
- "source": [
- "Now that the electricity markets have been retrieved, let's specify the new choice \"electricity\":"
- ]
- },
- {
- "cell_type": "code",
- "id": "a8347656-3735-4973-8819-3cafe0f77aa2",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:06.224979Z",
- "iopub.status.busy": "2024-06-30T14:00:06.224979Z",
- "iopub.status.idle": "2024-06-30T14:00:06.240604Z",
- "shell.execute_reply": "2024-06-30T14:00:06.240604Z",
- "shell.execute_reply.started": "2024-06-30T14:00:06.224979Z"
- }
- },
- "source": [
- "choices['electricity'] = {market: 10 for market in electricity_markets}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "8969b491-b69b-498a-9643-d4342cbc17b7",
- "metadata": {},
- "source": [
- "With the expanded choces, proceed to re-instatiate the problem and re-solve:"
- ]
- },
- {
- "cell_type": "code",
- "id": "772aa8ef-e420-44d2-a704-c6fd04879d85",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:06.240604Z",
- "iopub.status.busy": "2024-06-30T14:00:06.240604Z",
- "iopub.status.idle": "2024-06-30T14:00:30.194845Z",
- "shell.execute_reply": "2024-06-30T14:00:30.194474Z",
- "shell.execute_reply.started": "2024-06-30T14:00:06.240604Z"
- }
- },
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "ba9f21b2-0eb8-4d4f-a55f-01ae1753409d",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:30.195845Z",
- "iopub.status.busy": "2024-06-30T14:00:30.194845Z",
- "iopub.status.idle": "2024-06-30T14:00:30.248971Z",
- "shell.execute_reply": "2024-06-30T14:00:30.248971Z",
- "shell.execute_reply.started": "2024-06-30T14:00:30.195845Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "5814cf9f-5efb-455a-9339-1e0a0081e3ba",
- "metadata": {},
- "source": [
- "For the regional choice \"Albania\" (AL) has been chosen, supplying a total of **0.4565 kWh**, of which 0.3328 kWh go to the PP pyrolysis and the rest is used somewhere else in the technosphere. As a result, the optimized system can further reduce the GWP from **0.3733 kg CO2** (only technology choice) to **0.2385 kg CO2** (simultaneous technology and regional choice). "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "b2604581-1cba-49e0-b775-b07eb472a695",
- "metadata": {},
- "source": [
- "
\n",
- "
Alternative Indicators 🔄 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ae2cebc7-7266-4972-bfe3-50cef07b856f",
- "metadata": {},
- "source": [
- "Judging from the \"*no optimization*\" case from before, the best choice for the \"**Freshwater Eutrophication (EF v3.0)**\" category will be **fossil diesel**. In this segment, let's assess what happens if we optimize for this category, while simultaneously allow for regional choices to be active."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "15da02d1-5add-412f-86e9-4527138ac2bc",
- "metadata": {},
- "source": [
- "To that end, create a new worker with all the methods:"
- ]
- },
- {
- "cell_type": "code",
- "id": "508ef9e6-b974-4f0e-9623-b9aa0d45f7ae",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:30.249989Z",
- "iopub.status.busy": "2024-06-30T14:00:30.249989Z",
- "iopub.status.idle": "2024-06-30T14:00:30.266118Z",
- "shell.execute_reply": "2024-06-30T14:00:30.264976Z",
- "shell.execute_reply.started": "2024-06-30T14:00:30.249989Z"
- }
- },
- "source": [
- "methods_list = {\n",
- " \"('IPCC 2013', 'climate change', 'GWP 100a')\": 0,\n",
- " \"('EF v3.0', 'climate change: land use and land use change', 'global warming potential (GWP100)')\": 0,\n",
- " \"('EF v3.0', 'eutrophication: freshwater', 'fraction of nutrients reaching freshwater end compartment (P)')\": 1,\n",
- " \"('EF v3.0', 'ionising radiation: human health', 'human exposure efficiency relative to u235')\": 0,\n",
- "}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "6df62c62-31ea-4840-8a16-4e7f9a7fefc4",
- "metadata": {},
- "source": [
- "The provided dictionary is utilized within the optimization framework to allocate specific weights to various impact categories. Each key in this dictionary represents a distinct environmental impact category, as identified by its methodological definition (e.g., \"IPCC 2013\" for climate change or \"EF v3.0\" for specific Environmental Footprint categories). The value assigned to each key represents the weight that the optimization algorithm should give to that particular impact category in the decision-making process.\n",
- "\n",
- "- The weight of 0 for most categories (climate change, land use change's GWP, and ionising radiation's human health impact) indicates that these categories do not influence the optimization's outcome. However, they are evaluated (calculated) alongside the optimization and their final value can be printed and assessed.\n",
- "- The weight of 1 assigned to \"eutrophication: freshwater\" signifies that the optimization process exclusively focuses on minimizing the impact in this category, while still calculating the impacts for the other categories alongside."
- ]
- },
- {
- "cell_type": "code",
- "id": "196a5f1d-c9dd-48ab-a922-dae7345efc9b",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:30.267115Z",
- "iopub.status.busy": "2024-06-30T14:00:30.267115Z",
- "iopub.status.idle": "2024-06-30T14:00:31.773722Z",
- "shell.execute_reply": "2024-06-30T14:00:31.773722Z",
- "shell.execute_reply.started": "2024-06-30T14:00:30.267115Z"
- }
- },
- "source": [
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods_list, directory)\n",
- "pulpo_worker.get_lci_data()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "7152b664-4ee7-48ac-924a-7e2bef065ae2",
- "metadata": {},
- "source": [
- "Let's re-instantiate and re-solve the problem (same choices, same demand):"
- ]
- },
- {
- "cell_type": "code",
- "id": "7ee4fec3-5ed0-477d-931e-18918f9d1add",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:31.773722Z",
- "iopub.status.busy": "2024-06-30T14:00:31.773722Z",
- "iopub.status.idle": "2024-06-30T14:00:52.567459Z",
- "shell.execute_reply": "2024-06-30T14:00:52.567141Z",
- "shell.execute_reply.started": "2024-06-30T14:00:31.773722Z"
- }
- },
- "source": [
- "instance = pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "74346ac0-c795-4a77-a637-f40609077bb7",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:52.567651Z",
- "iopub.status.busy": "2024-06-30T14:00:52.567651Z",
- "iopub.status.idle": "2024-06-30T14:00:52.617320Z",
- "shell.execute_reply": "2024-06-30T14:00:52.617320Z",
- "shell.execute_reply.started": "2024-06-30T14:00:52.567651Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "8fef4987-d56f-4480-951c-4bd1630f6090",
- "metadata": {},
- "source": [
- "#### Notable Findings:\n",
- "Contrary to initial expectations based solely on technology choice, it has been observed that not fossil diesel but pyrolysis oil, powered with electricity from **Iceland (IS)**, significantly reduces the eutrophication impact from **2.86e-05 kg PO4e** to **2.00e-05 kg PO4e**.\n",
- "\n",
- "However, it's important to note that these findings do not definitively establish Iceland as the optimal location for diesel production of this nature. Instead, they prompt a deeper examination of Iceland's local conditions that contribute to this environmental advantage. Notably, Iceland's energy production is predominantly sourced from hydro and geothermal energy, with a particularly high reliance on geothermal sources. This unique energy landscape suggests that the extensive use of geothermal energy plays a critical role in positioning Iceland as a potentially favorable region for minimizing eutrophication impacts.\n",
- "\n",
- "Accordingly, these results open avenues for further analysis and understanding, potentially revealing broader insights into environmental optimization and regional energy strategies."
- ]
- },
- {
- "cell_type": "code",
- "id": "6fdbd504-0ff7-4995-a975-d2d5194f6a84",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:52.617320Z",
- "iopub.status.busy": "2024-06-30T14:00:52.617320Z",
- "iopub.status.idle": "2024-06-30T14:00:54.065766Z",
- "shell.execute_reply": "2024-06-30T14:00:54.065766Z",
- "shell.execute_reply.started": "2024-06-30T14:00:52.617320Z"
- }
- },
- "source": [
- "# Reset the objective function to IPCC GWP\n",
- "methods_list = {\n",
- " \"('IPCC 2013', 'climate change', 'GWP 100a')\": 1,\n",
- " \"('EF v3.0', 'climate change: land use and land use change', 'global warming potential (GWP100)')\": 0,\n",
- " \"('EF v3.0', 'eutrophication: freshwater', 'fraction of nutrients reaching freshwater end compartment (P)')\": 0,\n",
- " \"('EF v3.0', 'ionising radiation: human health', 'human exposure efficiency relative to u235')\": 0,\n",
- "}\n",
- "\n",
- "pulpo_worker = pulpo.PulpoOptimizer(project, database, methods_list, directory)\n",
- "pulpo_worker.get_lci_data()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "6669ce99-f828-4969-8032-16c26a99e877",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-31T16:36:49.210303Z",
- "iopub.status.busy": "2024-03-31T16:36:49.209306Z",
- "iopub.status.idle": "2024-03-31T16:36:49.230236Z",
- "shell.execute_reply": "2024-03-31T16:36:49.229239Z",
- "shell.execute_reply.started": "2024-03-31T16:36:49.210303Z"
- }
- },
- "source": [
- "
\n",
- "
Additional Constraints \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c093463b-af88-4f0c-9cc8-5e0166643692",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-03-31T16:37:30.479157Z",
- "iopub.status.busy": "2024-03-31T16:37:30.479157Z",
- "iopub.status.idle": "2024-03-31T16:37:30.494163Z",
- "shell.execute_reply": "2024-03-31T16:37:30.493166Z",
- "shell.execute_reply.started": "2024-03-31T16:37:30.479157Z"
- }
- },
- "source": [
- "
\n",
- "
Technosphere Capacity Constraints ⛓️ \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "54a6cdc8-51d1-40f5-bd2f-e50b1d76713a",
- "metadata": {},
- "source": [
- "In 2020, the demand for diesel products stood at **292.6 million tons** ([source](https://www.fuelseurope.eu/uploads/files/modules/documents/file/1663766146_TWxIVaKHUN4dlyHl7hNvrUpf0Jwzbbe6nI9DMDBa.pdf)), necessitating **1.113 kg of PP (polypropylene)** for the production of 1 kg of pyrolysis oil. Within the European Union, the total post-consumer plastic waste collected, both mixed and separately, amounted to **29.5 million tons** ([source](https://plasticseurope.org/knowledge-hub/plastics-the-facts-2022/)). This presents a clear mismatch between demand and available supply.\n",
- "\n",
- "Significantly, over **50% of plastic waste** is amassed through mixed waste collection schemes, with the separately collected fraction rarely categorized by plastic type. This makes acquiring \"pure\" PP for pyrolysis a challenging endeavor. \n",
- "\n",
- "However, for the purposes of our assessment, we'll operate under the optimistic assumption that the separately collected fraction of plastics includes **16.6% PP**, and that it's feasible to sort and extract this PP entirely for pyrolysis usage. Under this premise, approximately **2.4 million tons of raw PP material** could be rendered available for pyrolysis.\n",
- "\n",
- "We will proceed by incorporating this raw material limitation as a **technosphere constraint** in our analysis:"
- ]
- },
- {
- "cell_type": "code",
- "id": "94966000-fd32-43b5-b6e2-8acbe53a065e",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:54.068061Z",
- "iopub.status.busy": "2024-06-30T14:00:54.067064Z",
- "iopub.status.idle": "2024-06-30T14:00:54.087458Z",
- "shell.execute_reply": "2024-06-30T14:00:54.087458Z",
- "shell.execute_reply.started": "2024-06-30T14:00:54.067064Z"
- }
- },
- "source": [
- "# Adjust the final demand for an economy-wide perspective\n",
- "demand = {diesel_market: 292.6e9}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "437f9701-ffde-4a00-912d-ac6f764ca26e",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:54.087458Z",
- "iopub.status.busy": "2024-06-30T14:00:54.087458Z",
- "iopub.status.idle": "2024-06-30T14:00:54.101306Z",
- "shell.execute_reply": "2024-06-30T14:00:54.101306Z",
- "shell.execute_reply.started": "2024-06-30T14:00:54.087458Z"
- }
- },
- "source": [
- "# Re-define the choices and set a reasonably high capacity constraint\n",
- "# Note that we are not considering regional choices here!\n",
- "choices = {'diesel': {diesel_bio: 1e15,\n",
- " diesel_fossil: 1e15,\n",
- " diesel_pp: 1e15}} "
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "35ada40f-cf34-42ea-84bd-c2b9654da72d",
- "metadata": {},
- "source": [
- "To incorporate the constraint on plastic availability, we must initially retrieve the relevant activity. Following this, we'll construct an \"upper_limit\" dictionary that assigns the previously derived value:"
- ]
- },
- {
- "cell_type": "code",
- "id": "69df4192-6da1-40a7-a19e-8a5f9b9718cb",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:54.101306Z",
- "iopub.status.busy": "2024-06-30T14:00:54.101306Z",
- "iopub.status.idle": "2024-06-30T14:00:54.783509Z",
- "shell.execute_reply": "2024-06-30T14:00:54.783509Z",
- "shell.execute_reply.started": "2024-06-30T14:00:54.101306Z"
- }
- },
- "source": [
- "pp_waste = pulpo_worker.retrieve_activities(activities=['PP Waste collected'])[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "82525f47-3de4-42f6-bc55-f87e755eaf70",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:54.784453Z",
- "iopub.status.busy": "2024-06-30T14:00:54.784453Z",
- "iopub.status.idle": "2024-06-30T14:00:54.804789Z",
- "shell.execute_reply": "2024-06-30T14:00:54.804789Z",
- "shell.execute_reply.started": "2024-06-30T14:00:54.784453Z"
- }
- },
- "source": [
- "upper_limit = {pp_waste: 2.4e9}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "b2b3a7e4-3cad-4d98-b322-c88773aa4cbc",
- "metadata": {},
- "source": [
- "With this, we re-instatiate and re-solve the problem:"
- ]
- },
- {
- "cell_type": "code",
- "id": "115d2e6f-4e58-4988-991c-e1182687c354",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:00:54.804789Z",
- "iopub.status.busy": "2024-06-30T14:00:54.804789Z",
- "iopub.status.idle": "2024-06-30T14:01:19.333543Z",
- "shell.execute_reply": "2024-06-30T14:01:19.333543Z",
- "shell.execute_reply.started": "2024-06-30T14:00:54.804789Z"
- }
- },
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit=upper_limit)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "29330019-bdd6-4852-a83f-399ce74cf605",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:01:19.333543Z",
- "iopub.status.busy": "2024-06-30T14:01:19.333543Z",
- "iopub.status.idle": "2024-06-30T14:01:19.398029Z",
- "shell.execute_reply": "2024-06-30T14:01:19.398029Z",
- "shell.execute_reply.started": "2024-06-30T14:01:19.333543Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "f7cf242f-2bd5-429c-b879-9ecb290dbcbc",
- "metadata": {},
- "source": [
- "As expected, under ther technosphere constraint we obtain that 2.15 million ton of pyrolysis oil are produced and 291.10 million ton of fossil diesel. The overall minimized GWP stands at 137.7595 Mt CO2e. \n",
- "\n",
- "Now let's see what happens if we add further constraints to the problem. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6b39a911-3754-4284-9443-cf9c48c76415",
- "metadata": {},
- "source": [
- "**No-constraint**"
- ]
- },
- {
- "cell_type": "code",
- "id": "6b6b3a1b-8281-4bbe-9046-36555a425b3a",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:01:19.399026Z",
- "iopub.status.busy": "2024-06-30T14:01:19.399026Z",
- "iopub.status.idle": "2024-06-30T14:01:44.256505Z",
- "shell.execute_reply": "2024-06-30T14:01:44.256505Z",
- "shell.execute_reply.started": "2024-06-30T14:01:19.399026Z"
- }
- },
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit={})\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "ce090c18-15b3-458c-967e-e0c8064b5461",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:01:44.257502Z",
- "iopub.status.busy": "2024-06-30T14:01:44.257502Z",
- "iopub.status.idle": "2024-06-30T14:01:44.302959Z",
- "shell.execute_reply": "2024-06-30T14:01:44.302959Z",
- "shell.execute_reply.started": "2024-06-30T14:01:44.257502Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "6cc00a3e-f381-4761-a126-14befc7b14b9",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-04-25T11:54:14.519070Z",
- "iopub.status.busy": "2024-04-25T11:54:14.519070Z",
- "iopub.status.idle": "2024-04-25T11:54:14.536069Z",
- "shell.execute_reply": "2024-04-25T11:54:14.535069Z",
- "shell.execute_reply.started": "2024-04-25T11:54:14.519070Z"
- }
- },
- "source": [
- "**No-optimization**"
- ]
- },
- {
- "cell_type": "code",
- "id": "7c041d66-8a96-4003-b783-8455bcc60fc7",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:01:44.302959Z",
- "iopub.status.busy": "2024-06-30T14:01:44.302959Z",
- "iopub.status.idle": "2024-06-30T14:02:08.396198Z",
- "shell.execute_reply": "2024-06-30T14:02:08.396198Z",
- "shell.execute_reply.started": "2024-06-30T14:01:44.302959Z"
- }
- },
- "source": [
- "choices = {'diesel': {diesel_fossil: 1e15}} \n",
- "pulpo_worker.instantiate(choices=choices, demand=demand)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "0d480e08-1035-4cb4-bc76-f9c0d3f1c849",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:08.397195Z",
- "iopub.status.busy": "2024-06-30T14:02:08.397195Z",
- "iopub.status.idle": "2024-06-30T14:02:08.444498Z",
- "shell.execute_reply": "2024-06-30T14:02:08.444498Z",
- "shell.execute_reply.started": "2024-06-30T14:02:08.397195Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "5212bb60-b24a-4ea9-817e-5ee8994eb980",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:08.445494Z",
- "iopub.status.busy": "2024-06-30T14:02:08.445494Z",
- "iopub.status.idle": "2024-06-30T14:02:08.460415Z",
- "shell.execute_reply": "2024-06-30T14:02:08.459417Z",
- "shell.execute_reply.started": "2024-06-30T14:02:08.445494Z"
- }
- },
- "source": [
- "choices = {'diesel': {diesel_bio: 1e15,\n",
- " diesel_fossil: 1e15,\n",
- " diesel_pp: 1e15}} "
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "f787a647-ee8d-4ecf-9325-aa9a90c97bd1",
- "metadata": {},
- "source": [
- "
\n",
- "
Indicator / Impact Constraints 📏 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a36ffcc4-5692-4e4f-abc7-7a9f127807fc",
- "metadata": {},
- "source": [
- "For instance, a regulation aiming to reduce the ionising radiation impact by 5%! Using the previous result as baseline (6.5521e+10 kBq U235e) the target should be 6.2245e+10 kBq U235e. This constraint can be added as follows:"
- ]
- },
- {
- "cell_type": "code",
- "id": "d2b892fb-984c-47eb-8443-5d353c302e64",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:08.460415Z",
- "iopub.status.busy": "2024-06-30T14:02:08.460415Z",
- "iopub.status.idle": "2024-06-30T14:02:08.475468Z",
- "shell.execute_reply": "2024-06-30T14:02:08.474473Z",
- "shell.execute_reply.started": "2024-06-30T14:02:08.460415Z"
- }
- },
- "source": [
- "upper_imp_limit = {\"('EF v3.0', 'ionising radiation: human health', 'human exposure efficiency relative to u235')\": 6.2245e+10}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "8535cc3a-5cb0-4bb7-9c45-e2a9ff0a7125",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:08.476656Z",
- "iopub.status.busy": "2024-06-30T14:02:08.476464Z",
- "iopub.status.idle": "2024-06-30T14:02:34.646795Z",
- "shell.execute_reply": "2024-06-30T14:02:34.646795Z",
- "shell.execute_reply.started": "2024-06-30T14:02:08.476656Z"
- }
- },
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit=upper_limit, upper_imp_limit=upper_imp_limit)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "4cf71269-d175-4fe4-82b9-991325ada0c8",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:34.646795Z",
- "iopub.status.busy": "2024-06-30T14:02:34.646795Z",
- "iopub.status.idle": "2024-06-30T14:02:34.711121Z",
- "shell.execute_reply": "2024-06-30T14:02:34.711121Z",
- "shell.execute_reply.started": "2024-06-30T14:02:34.646795Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, constraints=upper_limit, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "8bf1c47e-7ee2-4491-a457-b96e874e8dcb",
- "metadata": {},
- "source": [
- "Since the process minimizing ionising radiation has already reached its limit through the technosphere constraint, the solver selects the next best process to comply with the additional impact constraint. This results in the use of **39.09 million ton of imported biodiesel**.\n",
- "\n",
- "The trade-off to comply with the constraint is an increased GWP from **137.7595 Mt CO2e** to **428.6267 Mt CO2e**! In other words, to reduce one impact category by 5%, another one increased by 211.13%. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3d2761fd-9973-42d5-9885-077976f0f8ee",
- "metadata": {},
- "source": [
- "This kind of assessment can help to identify technological and systemic bottlenecks in the multi-objective design of production systems."
- ]
- },
- {
- "cell_type": "code",
- "id": "0490537e-5a66-40a4-a84f-a7ca104e7daf",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:34.712119Z",
- "iopub.status.busy": "2024-06-30T14:02:34.711121Z",
- "iopub.status.idle": "2024-06-30T14:02:35.756625Z",
- "shell.execute_reply": "2024-06-30T14:02:35.755630Z",
- "shell.execute_reply.started": "2024-06-30T14:02:34.712119Z"
- }
- },
- "source": [
- "pulpo_worker.save_results(choices=choices, demand=demand, name='plastic_showcase_constrained.xlsx')"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "748f91bd-81b8-47fe-8a78-42cf3e0ed644",
- "metadata": {},
- "source": [
- "
\n",
- "
Biosphere capacity constraints 🌱 \n",
- ""
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "id": "e63f768a-7fe6-45f0-8669-70dc5366efaa",
- "metadata": {},
- "source": [
- "From the results saved in the spreadsheet \"plastic_showcase_constrained.xlsx\" we can identify (as expected) that the biodiesel production has a very large impact on land transformation. The biosphere entry \"Transformation, from annual crop\" takes a value of 109,643 km² which is slightly larger than the entire country of Iceland.\n",
- "\n",
- "Pulpo enable the restriction of biosphere flows as well. Let's repeat the previous assessment, targeting this time ionising radiation as objective, and figure out which is the possible reduction if we allow only 10,000 km² of land transformation: "
- ]
- },
- {
- "cell_type": "code",
- "id": "b38a40ce-5fef-4c54-948f-327670f8016c",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:35.758619Z",
- "iopub.status.busy": "2024-06-30T14:02:35.757622Z",
- "iopub.status.idle": "2024-06-30T14:02:35.777279Z",
- "shell.execute_reply": "2024-06-30T14:02:35.777279Z",
- "shell.execute_reply.started": "2024-06-30T14:02:35.758619Z"
- }
- },
- "source": [
- "pulpo_worker.method[\"('IPCC 2013', 'climate change', 'GWP 100a')\"] = 0\n",
- "pulpo_worker.method[\"('EF v3.0', 'ionising radiation: human health', 'human exposure efficiency relative to u235')\"] = 1"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "7feebe6a-2314-4f5b-9f3f-a623c1232bcd",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:35.777279Z",
- "iopub.status.busy": "2024-06-30T14:02:35.777279Z",
- "iopub.status.idle": "2024-06-30T14:02:35.867502Z",
- "shell.execute_reply": "2024-06-30T14:02:35.867502Z",
- "shell.execute_reply.started": "2024-06-30T14:02:35.777279Z"
- }
- },
- "source": [
- "transformation = pulpo_worker.retrieve_envflows(activities=[\"Transformation, from annual crop\"])[0]"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "b5d0bf16-b732-4a53-9c4d-d93cc535e771",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:35.868498Z",
- "iopub.status.busy": "2024-06-30T14:02:35.868498Z",
- "iopub.status.idle": "2024-06-30T14:02:35.884233Z",
- "shell.execute_reply": "2024-06-30T14:02:35.883503Z",
- "shell.execute_reply.started": "2024-06-30T14:02:35.868498Z"
- }
- },
- "source": [
- "upper_elem_limit = {transformation: 1e10}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "e9831fb1-d99a-4927-94f7-65d26b618ca1",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:35.885230Z",
- "iopub.status.busy": "2024-06-30T14:02:35.884233Z",
- "iopub.status.idle": "2024-06-30T14:02:57.651697Z",
- "shell.execute_reply": "2024-06-30T14:02:57.651697Z",
- "shell.execute_reply.started": "2024-06-30T14:02:35.884233Z"
- }
- },
- "source": [
- "pulpo_worker.instantiate(choices=choices, demand=demand, upper_limit=upper_limit, upper_elem_limit=upper_elem_limit)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "56db081e-ed9f-494c-a1bd-41e2e3c947ff",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:57.652693Z",
- "iopub.status.busy": "2024-06-30T14:02:57.651697Z",
- "iopub.status.idle": "2024-06-30T14:02:57.716270Z",
- "shell.execute_reply": "2024-06-30T14:02:57.716270Z",
- "shell.execute_reply.started": "2024-06-30T14:02:57.652693Z"
- }
- },
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "fc8fa995-9636-407b-a083-b07ee2d01394",
- "metadata": {},
- "source": [
- "It can be observed that, as before, the maximum amount of pyrolysis oil is selected. The biodiesel however now is produced with **17.83 million ton**, reducing the overall ionising radiation to 6.522251e+10 kBq U235e (0.46% reduction)."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "9d344ea8-3f02-418b-b1c1-d521eb117023",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-04-01T11:13:55.119299Z",
- "iopub.status.busy": "2024-04-01T11:13:55.119299Z",
- "iopub.status.idle": "2024-04-01T11:13:55.128269Z",
- "shell.execute_reply": "2024-04-01T11:13:55.127272Z",
- "shell.execute_reply.started": "2024-04-01T11:13:55.119299Z"
- }
- },
- "source": [
- "---\n",
- "\n",
- "**Disclaimer**: This example is designed for demonstrative purposes only, to showcase the functionalities of Pulpo. The figures, scenarios, and scales presented are hypothetical and may not accurately reflect real-world conditions. Any resemblance to actual data or outcomes is purely coincidental and should not be considered as accurate representations of environmental impacts or optimization results.\n",
- "\n",
- "---\n"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ae3a3f79-a1c4-446c-b1bd-d3554ecd339a",
- "metadata": {},
- "source": [
- "
\n",
- "
Supply vs. demand 🔄💼 \n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "564cd3d8-1428-4dc6-b3d3-364e1523173e",
- "metadata": {},
- "source": [
- "Pulpo introduces a feature that pivots from defining a final demand to setting a final supply. This approach is particularly useful in scenarios where the end demand remains uncertain, yet there's clarity on a process's production capacity. Under such circumstances, the aim is to maximize production, anticipating that the eventual demand will exceed this capacity. For example, we might know the production limit for pyrolysis oil but only have an estimated demand for market-sourced diesel.\n",
- "\n",
- "To demonstrate this capability, we'll explore specifying a final **supply** of 1 kg of market diesel, contrasting this with a scenario based on a 1 kg diesel **demand**. It's reasonable to anticipate a somewhat reduced total impact in the supply specification scenario, considering that it accounts for diesel's internal consumption, which is normally added to the final demand."
- ]
- },
- {
- "cell_type": "code",
- "id": "3832f45b-f71b-474f-8a72-d98bf6e1cf06",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:57.717271Z",
- "iopub.status.busy": "2024-06-30T14:02:57.717271Z",
- "iopub.status.idle": "2024-06-30T14:02:57.724556Z",
- "shell.execute_reply": "2024-06-30T14:02:57.723439Z",
- "shell.execute_reply.started": "2024-06-30T14:02:57.717271Z"
- }
- },
- "source": [
- "pulpo_worker.method[\"('IPCC 2013', 'climate change', 'GWP 100a')\"] = 1\n",
- "pulpo_worker.method[\"('EF v3.0', 'ionising radiation: human health', 'human exposure efficiency relative to u235')\"] = 0"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "b0018abb-5af9-4f0e-ab20-050bc006ff83",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:57.725556Z",
- "iopub.status.busy": "2024-06-30T14:02:57.725556Z",
- "iopub.status.idle": "2024-06-30T14:02:57.743618Z",
- "shell.execute_reply": "2024-06-30T14:02:57.743618Z",
- "shell.execute_reply.started": "2024-06-30T14:02:57.725556Z"
- }
- },
- "source": [
- "supply = {diesel_market: 1}"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "03b0e851-2828-43d6-9583-4a900cdd890c",
- "metadata": {},
- "source": [
- "The final supply is specified in the instatiation by setting a lower and upper limit of the scaling vector to the same value:"
- ]
- },
- {
- "cell_type": "code",
- "id": "0a75bfba-4722-4ba9-82f6-6b70ead0715f",
- "metadata": {
- "execution": {
- "iopub.execute_input": "2024-06-30T14:02:57.743618Z",
- "iopub.status.busy": "2024-06-30T14:02:57.743618Z"
- }
- },
- "source": [
- "pulpo_worker.instantiate(choices=choices, lower_limit=supply, upper_limit=supply)\n",
- "results = pulpo_worker.solve()"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "code",
- "id": "4ebcae6c-4dc4-447f-9f47-a421b975de75",
- "metadata": {},
- "source": [
- "pulpo_worker.summarize_results(choices=choices, demand=demand, zeroes=True)"
- ],
- "outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "id": "edfa0287-0287-4236-a653-c4917dbc3f5e",
- "metadata": {},
- "source": [
- "As expected, the total impact is **slightly** lower with 0.373
026 kg CO
2 compared to 0.373
292 kg CO
2 e.\n"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.9.19"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/objects.inv b/objects.inv
new file mode 100644
index 0000000..36507d4
Binary files /dev/null and b/objects.inv differ
diff --git a/pulpo/__init__.py b/pulpo/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/pulpo/pulpo.py b/pulpo/pulpo.py
deleted file mode 100644
index a910748..0000000
--- a/pulpo/pulpo.py
+++ /dev/null
@@ -1,214 +0,0 @@
-from pulpo.utils import optimizer, bw_parser, converter, saver
-from typing import List, Union
-import webbrowser
-from tests.rice_database import setup_rice_husk_db
-from tests.generic_database import setup_generic_db
-
-class PulpoOptimizer:
- def __init__(self, project: str, database: Union[str, List[str]], method: Union[str, List[str], dict], directory: str):
- """
- Initializes the PulpoOptimizer with project, databases, method, and directory.
-
- Args:
- project (str): Name of the project.
- database (Union[str, List[str]]): Name of the database or list of two databases
- (e.g. foreground and linked background).
- method (Union[str, List[str], dict]): Method(s) for optimization.
- directory (str): Directory for saving results.
- """
- self.project = project
- self.database = database
- self.intervention_matrix = 'biosphere3'
- self.method = converter.convert_to_dict(method)
- self.directory = directory
- self.lci_data = None
- self.instance = None
-
- def get_lci_data(self):
- """
- Imports LCI data for the project using the specified database and method.
- """
- self.lci_data = bw_parser.import_data(self.project, self.database, self.method, self.intervention_matrix)
-
- def instantiate(self, choices={}, demand={}, upper_limit={}, lower_limit={}, upper_elem_limit={},
- upper_imp_limit={}):
- """
- Combines inputs and instantiates the optimization model.
-
- Args:
- choices (dict): Choices for the model.
- demand (dict): Demand data.
- upper_limit (dict): Upper limit constraints.
- lower_limit (dict): Lower limit constraints.
- upper_elem_limit (dict): Upper elemental limit constraints.
- upper_imp_limit (dict): Upper impact limit constraints.
- """
- # Instantiate only for those methods that are part of the objective or the limits
- methods = {h: self.method[h] for h in self.method if self.method[h] != 0 or h in upper_imp_limit}
- data = converter.combine_inputs(self.lci_data, demand, choices, upper_limit, lower_limit, upper_elem_limit,
- upper_imp_limit, methods)
- self.instance = optimizer.instantiate(data)
-
- def solve(self, GAMS_PATH=False, solver_name=None, options=None):
- """
- Solves the optimization model and calculates additional methods and inventory flows if needed.
-
- Args:
- GAMS_PATH (bool): Path to GAMS if needed.
- options (dict): Additional options for the solver.
-
- Returns:
- results: Results of the optimization.
- """
- results, self.instance = optimizer.solve_model(self.instance, GAMS_PATH, solver_name=solver_name, options=options)
-
- # Post calculate additional methods, in case several methods have been specified and one of them is 0
- if not isinstance(self.method, str):
- if len(self.method) > 1 and 0 in [self.method[x] for x in self.method]:
- self.instance = optimizer.calculate_methods(self.instance, self.lci_data, self.method)
-
- self.instance = optimizer.calculate_inv_flows(self.instance, self.lci_data)
- return results
-
- def retrieve_processes(self, keys=None, processes=None, reference_products=None, locations=None):
- """
- Retrieves processes from the database based on given filters.
-
- Args:
- keys (list): List of keys to filter activities.
- processes (list): List of processes to filter.
- reference_products (list): List of reference products to filter.
- locations (list): List of locations to filter.
-
- Returns:
- activities: Filtered activities from the database.
- """
- processes = bw_parser.retrieve_processes(self.project, self.database, keys, processes, reference_products,
- locations)
- return processes
-
- def retrieve_activities(self, keys=None, activities=None, reference_products=None, locations=None):
- """
- Works the same as "retrieve_processes" but with a different name. Will be obsolete in future versions.
- """
- activities = bw_parser.retrieve_processes(self.project, self.database, keys, activities, reference_products,
- locations)
- return activities
-
- def retrieve_envflows(self, keys=None, activities=None, categories=None):
- """
- Retrieves environmental flows from the database based on given filters.
-
- Args:
- keys (list): List of keys to filter environmental flows.
- activities (list): List of activities to filter.
- categories (list): List of categories to filter.
-
- Returns:
- activities: Filtered environmental flows from the database.
- """
- activities = bw_parser.retrieve_env_interventions(project=self.project,
- intervention_matrix=self.intervention_matrix, keys=keys,
- activities=activities, categories=categories)
- return activities
-
- def retrieve_methods(self, string=""):
- """
- Retrieves methods from the database based on a search string.
-
- Args:
- string (str): Search string for methods.
-
- Returns:
- methods: List of methods that match the search string.
- """
- methods = bw_parser.retrieve_methods(self.project, string)
- return methods
-
- def save_results(self, choices={}, constraints={}, demand={}, name='results.xlxs'):
- """
- Saves the results of the optimization to a file.
-
- Args:
- choices (dict): Choices for the model.
- constraints (dict): Constraints applied during optimization.
- demand (dict): Demand data used in optimization.
- name (str): Name of the file to save results.
- """
- saver.save_results(self.instance, self.project, self.database, choices, constraints, demand,
- self.lci_data['process_map'], self.lci_data['intervention_map'], self.directory, name)
-
- def summarize_results(self, choices={}, constraints={}, demand={}, zeroes=False):
- """
- Summarizes the results of the optimization.
-
- Args:
- choices (dict): Choices for the model.
- constraints (dict): Constraints applied during optimization.
- demand (dict): Demand data used in optimization.
- zeroes (bool): Whether to include zero values in the summary.
- """
- saver.summarize_results(self.instance, choices, constraints, demand,
- self.lci_data['process_map'], zeroes)
-
-
-def electricity_showcase():
- """
- Opens the electricity showcase notebook in the web browser.
- """
- github_url = 'https://github.com/flechtenberg/pulpo/blob/master/notebooks/electricity_showcase.ipynb'
- nbviewer_url = 'https://nbviewer.jupyter.org/github/' + github_url.split('github.com/')[1]
- webbrowser.open(nbviewer_url)
-
-
-def hydrogen_showcase():
- """
- Opens the hydrogen showcase notebook in the web browser.
- """
- github_url = 'https://github.com/flechtenberg/pulpo/blob/master/notebooks/hydrogen_showcase.ipynb'
- nbviewer_url = 'https://nbviewer.jupyter.org/github/' + github_url.split('github.com/')[1]
- webbrowser.open(nbviewer_url)
-
-
-def plastic_showcase():
- """
- Opens the plastic showcase notebook in the web browser.
- """
- github_url = 'https://github.com/flechtenberg/pulpo/blob/master/notebooks/plastic_showcase.ipynb'
- nbviewer_url = 'https://nbviewer.jupyter.org/github/' + github_url.split('github.com/')[1]
- webbrowser.open(nbviewer_url)
-
-
-def install_rice_husk_db():
- """
- Sets up the rice husk example database.
- """
- setup_rice_husk_db()
-
-def install_generic_db(project="generic_db_project", database="generic_db", n_prod=5, n_proc=3, n_reg=3, n_inputs=4, n_flows=4, n_methods=2, seed=None, return_data=False):
- """
- Sets up the generic LCI database in Brightway2 with specified parameters.
-
- Args:
- project (str): Name of the Brightway2 project to create or use. Defaults to "generic_db_project".
- database (str): Name of the database to create or use. Defaults to "generic_db".
- n_prod (int): Number of products to generate. Defaults to 5.
- n_proc (int): Maximum number of processes per product. Defaults to 3.
- n_reg (int): Number of regions where processes can be active. Defaults to 3.
- n_inputs (int): Maximum number of inputs per process. Defaults to 4.
- n_flows (int): Number of environmental flows to generate. Defaults to 4.
- n_methods (int): Number of impact assessment methods to create. Defaults to 2.
- seed (int, optional): Seed for reproducibility of random data generation. Defaults to None.
- return_data (bool): If True, returns the generated matrices (technosphere, biosphere, and
- characterization). Defaults to False.
-
- Returns:
- tuple: If `return_data` is True, returns a tuple containing:
- - technosphere_matrix (np.ndarray): The technosphere matrix.
- - biosphere_matrix (np.ndarray): The biosphere matrix.
- - characterization_matrices (dict): A dictionary of characterization factor matrices.
- """
- return setup_generic_db(project=project, database=database, n_prod=n_prod, n_proc=n_proc, n_reg=n_reg,
- n_inputs=n_inputs, n_flows=n_flows, n_methods=n_methods,
- seed=seed, return_data=return_data)
-
diff --git a/pulpo/utils/__init__.py b/pulpo/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/pulpo/utils/bw_parser.py b/pulpo/utils/bw_parser.py
deleted file mode 100644
index edf04cf..0000000
--- a/pulpo/utils/bw_parser.py
+++ /dev/null
@@ -1,297 +0,0 @@
-from typing import List, Union, Dict, Any
-import bw2calc as bc
-import bw2data as bd
-from pulpo.utils.utils import is_bw25
-
-def import_data(project: str, databases: Union[str, List[str]], method: Union[str, List[str], Dict[str, int]],
- intervention_matrix_name: str) -> Dict[str, Union[dict, Any]]:
- """
- Main function to import LCI data for a project from one or more databases.
-
- Args:
- project (str): Name of the project.
- databases (Union[str, List[str]]): Name of the primary database or a list of databases
- (foreground, background).
- method (Union[str, List[str], Dict[str, int]]): Method(s) for data retrieval.
- intervention_matrix_name (str): Name of the intervention matrix.
-
- Returns:
- Dict[str, Union[dict, Any]]: Dictionary containing imported LCI data.
- """
-
- # Set project and check if it exists
- if project not in bd.projects:
- raise ValueError(f"Project '{project}' does not exist. Please check the project name.")
-
- bd.projects.set_current(project)
-
- # Normalize databases input to a list
- if isinstance(databases, str):
- databases = [databases]
-
- # Validate each specified database
- for db in databases:
- if db not in bd.databases:
- raise ValueError(
- f"Database '{db}' does not exist in the project '{project}'. "
- f"Available databases: {list(bd.databases.keys())}"
- )
-
- # Prepare methods
- if isinstance(method, str):
- method = [method] # Convert single string to list of strings
- method = sorted(method)
-
- # Retrieve and validate methods
- methods = retrieve_methods(project, method)
- invalid_methods = [m for m in method if m not in [str(mt) for mt in bd.methods]]
- if invalid_methods:
- raise ValueError(
- f"The following methods do not exist in the project '{project}': {invalid_methods}. "
- f"Available methods: {[str(mt) for mt in bd.methods]}"
- )
-
- # Initialize database objects
- eidb = bd.Database(databases[0]) # Foreground database
- eidb_secondary = bd.Database(databases[1]) if len(databases) > 1 else None # Secondary background database
-
- rand_act = eidb.random() # Random activity from foreground database
-
- bw25 = is_bw25()
- characterization_matrices = {}
- secondary_lca = None # Placeholder for secondary LCA object
-
- if bw25:
- # Process with bw25 logic for foreground database
- functional_units_1 = {"act1": {rand_act.id: 1}}
- config_1 = {"impact_categories": methods}
- data_objs_1 = bd.get_multilca_data_objs(functional_units=functional_units_1, method_config=config_1)
-
- lca = bc.MultiLCA(demands=functional_units_1, method_config=config_1, data_objs=data_objs_1)
- lca.load_lci_data()
- lca.load_lcia_data()
-
- # Store the characterization matrices for methods
- characterization_matrices = {str(method): lca.characterization_matrices[method] for method in methods}
-
- # Perform LCA for the secondary database, if specified
- if eidb_secondary:
- functional_units_2 = {"act2": {eidb_secondary.random().id: 1}}
- config_2 = {"impact_categories": methods}
- data_objs_2 = bd.get_multilca_data_objs(functional_units=functional_units_2, method_config=config_2)
-
- secondary_lca = bc.MultiLCA(demands=functional_units_2, method_config=config_2, data_objs=data_objs_2)
- secondary_lca.load_lci_data() # Only need the product dictionary
- # secondary_lca.products_dict will be available later
-
- else:
- # Process with bw2 logic for foreground database
- for method in methods:
- lca = bc.LCA({rand_act: 1}, method)
- lca.lci()
- lca.lcia()
- characterization_matrices[str(method)] = lca.characterization_matrix
-
- # Perform LCA for the secondary database, if specified
- if eidb_secondary:
- rand_act_bg = eidb_secondary.random()
- for method in methods:
- secondary_lca = bc.LCA({rand_act_bg: 1}, method)
- secondary_lca.lci() # Load LCI to access product dictionary
- # Stop after loading one method since we're only interested in secondary_lca.products_dict
- break
-
- # Extract A (Technosphere) and B (Biosphere) matrices from the LCA
- technology_matrix = lca.technosphere_matrix # A matrix
- intervention_matrix = lca.biosphere_matrix # B matrix
-
- # Initialize the process map
- process_map = {}
-
- if bw25:
- # Create activity map for the primary database (eidb)
- process_map.update({act.key: lca.dicts.product[act.id] for act in eidb})
-
- # Add secondary database (secondary_eidb) activities, if available
- if eidb_secondary and secondary_lca:
- process_map.update({act.key: secondary_lca.dicts.product[act.id] for act in eidb_secondary})
- else:
- # Use product_dict for the primary database (eidb)
- process_map.update(lca.product_dict)
-
- # Add secondary database (secondary_eidb) product_dict, if available
- if eidb_secondary and secondary_lca:
- process_map.update(secondary_lca.product_dict)
-
- # Add descriptive strings to the process map for both primary and secondary databases
- for act in eidb:
- process_map[process_map[act.key]] = (
- f"{act['name']} | {act.get('reference product', '')} | {act.get('location', '')}"
- )
-
- if eidb_secondary:
- for act in eidb_secondary:
- process_map[process_map[act.key]] = (
- f"{act['name']} | {act.get('reference product', '')} | {act.get('location', '')}"
- )
-
- if intervention_matrix_name in bd.databases:
- eidb_bio = bd.Database(intervention_matrix_name)
- if bw25:
- intervention_map = {act.key: lca.dicts.biosphere[act.id] for act in eidb_bio if act.id in lca.dicts.biosphere} # TODO: This is adherring to old ways of storring data with keys ... how to work with IDs instead?
- else:
- intervention_map = lca.biosphere_dict
- for act in eidb_bio:
- if act.key in intervention_map:
- intervention_map[intervention_map[act.key]] = act['name'] + ' | ' + str(act['categories'])
- else:
- print(
- "The name of the biosphere is not '" + intervention_matrix_name + "'. Please specify the correct biosphere.")
- return {}
-
- lci_data = {
- 'matrices': characterization_matrices,
- 'intervention_matrix': intervention_matrix,
- 'technology_matrix': technology_matrix,
- 'process_map': process_map,
- 'intervention_map': intervention_map,
- }
-
- return lci_data
-
-
-def retrieve_processes(project: str, databases: Union[str, List[str]], keys=None, activities=None,
- reference_products=None, locations=None):
- """
- Retrieve activities from one or more databases based on specified keys, activities, reference products, and locations.
-
- Args:
- project (str): Name of the project.
- databases (Union[str, List[str]]): Name of the primary database or a list of databases (foreground, background).
- keys (list, optional): List of keys to filter activities.
- activities (list, optional): List of activity names to filter.
- reference_products (list, optional): List of reference products to filter.
- locations (list, optional): List of locations to filter.
-
- Returns:
- list: List of matching activities from the specified databases.
- """
- # Set project
- bd.projects.set_current(project)
-
- # Normalize databases to a list
- if isinstance(databases, str):
- databases = [databases]
-
- # Ensure filters are lists
- if activities is not None and not isinstance(activities, list):
- activities = [activities]
- if reference_products is not None and not isinstance(reference_products, list):
- reference_products = [reference_products]
- if locations is not None and not isinstance(locations, list):
- locations = [locations]
-
- matching_processes = []
-
- # Search each database
- for db_name in databases:
- eidb = bd.Database(db_name)
-
- # Preprocess keys for fast lookup if provided
- if keys is not None:
- if isinstance(keys, str):
- keys = [keys]
- keys_set = set(eval(key) for key in keys) # Use a set for faster lookup
- matching_processes.extend([proc for proc in eidb if proc.key in keys_set])
- else:
- # Preprocess filters for fast lookup
- activity_set = set(activities) if activities is not None else None
- reference_product_set = set(reference_products) if reference_products is not None else None
- location_set = set(locations) if locations is not None else None
-
- # Filter processes efficiently
- matching_processes.extend([
- proc for proc in eidb
- if (activity_set is None or proc['name'] in activity_set) and
- (reference_product_set is None or proc['reference product'] in reference_product_set) and
- (location_set is None or proc['location'] in location_set)
- ])
-
- if not matching_processes:
- print("No activities match the given specifications or the input format is incorrect.")
- return matching_processes
-
-
-def retrieve_env_interventions(project: str = '', intervention_matrix: str = 'biosphere3', keys=None, activities=None,
- categories=None):
- """
- Retrieve environmental flows from the biosphere database based on specified keys, activities, and categories.
-
- Args:
- project (str, optional): Name of the project.
- intervention_matrix (str): Name of the intervention matrix.
- keys (list, optional): List of keys to filter environmental flows.
- activities (list, optional): List of activity names to filter.
- categories (list, optional): List of categories to filter.
-
- Returns:
- list: List of matching environmental flows from the database.
- """
-
- # Set project and get database
- bd.projects.set_current(project)
- eidb = bd.Database(intervention_matrix)
-
- # Filter by keys if provided
- if keys is not None:
- if isinstance(keys, str):
- keys = [keys]
- keys = [eval(key) for key in keys]
- return [flow for flow in eidb if flow.key in keys]
-
- matching_flows = []
-
- # Filter by activities and categories
- for flow in eidb:
- if (activities is None or flow['name'] in activities) and \
- (categories is None or str(flow['categories']) in categories):
- matching_flows.append(flow)
-
- if not matching_flows:
- print("No flows match the given specifications or the input format is incorrect.")
- else:
- return matching_flows
-
-
-def retrieve_methods(project: str, sub_string: List[str]) -> List[str]:
- """
- Retrieve all methods that contain the specified list of substrings.
-
- Args:
- project (str): Name of the project.
- sub_string (List[str]): List of substrings to search for in method names.
-
- Returns:
- List[str]: List of methods that match the substrings.
- """
- bd.projects.set_current(project)
- return [method for method in bd.methods if any([x.lower() in str(method).lower() for x in sub_string])]
-
-#if __name__ == '__main__':
-# if is_bw25():
-# project = "pulpo_bw25"
-# biosphere = "ecoinvent-3.8-biosphere"
-# methods = {"('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 100a')": 1,
-# "('ecoinvent-3.8', 'IPCC 2013', 'climate change', 'GWP 20a')": 0,
-# }
-# else:
-# project = "pulpo"
-# biosphere = "biosphere3"
-# methods = {"('IPCC 2013', 'climate change', 'GWP 100a')": 1,
-# "('IPCC 2013', 'climate change', 'GWP 20a')": 0,
-# }
-#
-# database = "ecoinvent-3.8-cutoff"
-#
-#
-# import_data(project, database, methods, intervention_matrix_name=biosphere)
\ No newline at end of file
diff --git a/pulpo/utils/converter.py b/pulpo/utils/converter.py
deleted file mode 100644
index 6c036a2..0000000
--- a/pulpo/utils/converter.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import scipy.sparse as sparse
-
-
-def combine_inputs(lci_data, demand, choices, upper_limit, lower_limit, upper_inv_limit, upper_imp_limit, methods):
- """
- Combines all the inputs into a dictionary as an input for the optimization model.
-
- Args:
- lci_data (dict): LCI data containing matrices and mappings.
- demand (dict): Demand data.
- choices (dict): Choices for the model.
- upper_limit (dict): Upper limit constraints.
- lower_limit (dict): Lower limit constraints.
- upper_inv_limit (dict): Upper intervention limit constraints.
- upper_imp_limit (dict): Upper impact limit constraints.
- methods (dict): Methods for environmental impact assessment.
-
- Returns:
- dict: Combined data dictionary for the optimization model.
- """
-
- # Load LCI data matrices and mappings
- matrices = lci_data['matrices']
- intervention_matrix = lci_data['intervention_matrix']
- technology_matrix = lci_data['technology_matrix']
- process_map = lci_data['process_map']
- intervention_map = lci_data['intervention_map']
-
- # Remove matrices that are not part of the objective
- matrices = {h: matrices[h] for h in matrices if str(h) in methods}
-
- # Prepare the environmental impact matrices Q[h]*B
- env_cost = {h: sparse.csr_matrix.dot(matrices[h], intervention_matrix) for h in matrices}
-
- # Convert sparse csr biosphere impact matrix to dictionary
- env_cost_dict = {(i - 1, env_cost[h].indices[j], h): env_cost[h].data[j]
- for h in matrices for i in range(1, intervention_matrix.shape[0] + 1)
- for j in range(env_cost[h].indptr[i - 1], env_cost[h].indptr[i])}
-
- # Convert sparse csr technology matrix to dictionary
- technology_matrix_dict = {(i - 1, technology_matrix.indices[j]): technology_matrix.data[j]
- for i in range(1, technology_matrix.shape[0] + 1)
- for j in range(technology_matrix.indptr[i - 1], technology_matrix.indptr[i])}
-
- # Convert sparse csr intervention flow matrix to dictionary
- inv_to_consider = [intervention_map[g] for g in upper_inv_limit]
- inv_dict = {(g, intervention_matrix.indices[j]): intervention_matrix.data[j]
- for g in inv_to_consider
- for j in range(intervention_matrix.indptr[g], intervention_matrix.indptr[g + 1])}
-
- # Make technology matrix rectangular and update keys and product_ids
- keys = {} # Store the activity keys of the choices
- product_ids = [] # Store the product IDs of the choices
- for key, processes in choices.items():
- for proc in processes:
- product_id = process_map[proc.key]
- keys[product_id] = key
- product_ids.append(product_id)
-
- for product, process in list(technology_matrix_dict):
- if product in product_ids:
- if (keys[product], process) not in technology_matrix_dict:
- technology_matrix_dict[(keys[product], process)] = technology_matrix_dict[(product, process)]
- else:
- technology_matrix_dict[(keys[product], process)] += technology_matrix_dict[(product, process)]
- del technology_matrix_dict[(product, process)]
-
- # Create sets using set comprehensions for better performance
- PRODUCTS = {None: list({i[0] for i in technology_matrix_dict})}
- PROCESS = {None: list({i[1] for i in technology_matrix_dict})}
- PRODUCT_PROCESS = {None: list({(i[0], i[1]) for i in technology_matrix_dict})}
- ENV_COST = {None: list({i[0] for i in env_cost_dict})}
- ENV_COST_PROCESS = {None: list({i for i in env_cost_dict})}
- INV = {None: list({i[0] for i in inv_dict})}
- INV_PROCESS = {None: list({(i[0], i[1]) for i in inv_dict})}
- INDICATOR = {None: list({h for h in matrices})}
-
- # Specify the demand
- demand_dict = {prod: 0 for prod in PRODUCTS[None]}
- for dem in demand:
- if dem in process_map:
- # Case when dem is a key in process_map
- demand_dict[process_map[dem]] = demand[dem]
- elif dem in choices:
- # Case when dem is already one of the elements in process_map
- demand_dict[dem] = demand[dem]
- else:
- # Case when dem is neither a key nor a value in process_map
- raise ValueError(f"'{dem}' is not found in process_map keys or values.")
-
- # Specify the lower limit
- lower_limit_dict = {proc: -1e20 for proc in PROCESS[None]}
- for choice in choices:
- for proc in choices[choice]:
- lower_limit_dict[process_map[proc]] = 0
- for proc in lower_limit:
- lower_limit_dict[process_map[proc]] = lower_limit[proc]
-
- # Specify the upper limit
- upper_limit_dict = {proc: 1e20 for proc in PROCESS[None]}
- for proc in upper_limit:
- upper_limit_dict[process_map[proc]] = upper_limit[proc]
- for choice in choices:
- for proc in choices[choice]:
- upper_limit_dict[process_map[proc]] = choices[choice][proc]
-
- # Check if a supply has been specified
- supply_dict = {prod: 0 for prod in PRODUCTS[None]}
- for proc in list(lower_limit.keys() & upper_limit.keys()):
- supply_dict[process_map[proc]] = 1 if lower_limit[proc] == upper_limit[proc] else 0
-
- # Specify the upper elementary flow limit
- upper_inv_limit_dict = {elem: 1e24 for elem in INV[None]}
- for inv in upper_inv_limit:
- upper_inv_limit_dict[intervention_map[inv.key]] = upper_inv_limit[inv]
-
- # Specify the upper impact category limit
- upper_imp_limit_dict = {imp: 1e24 for imp in INDICATOR[None]}
- for imp in upper_imp_limit:
- upper_imp_limit_dict[imp] = upper_imp_limit[imp]
-
- # Create weights
- weights = {method: 1 for method in matrices} if methods == {} else methods
-
- # Assemble the final data dictionary
- model_data = {
- None: {
- 'PRODUCT': PRODUCTS,
- 'PROCESS': PROCESS,
- 'ENV_COST': ENV_COST,
- 'INDICATOR': INDICATOR,
- 'INV': INV,
- 'PRODUCT_PROCESS': PRODUCT_PROCESS,
- 'ENV_COST_PROCESS': ENV_COST_PROCESS,
- 'INV_PROCESS': INV_PROCESS,
- 'TECH_MATRIX': technology_matrix_dict,
- 'ENV_COST_MATRIX': env_cost_dict,
- 'INV_MATRIX': inv_dict,
- 'FINAL_DEMAND': demand_dict,
- 'SUPPLY': supply_dict,
- 'LOWER_LIMIT': lower_limit_dict,
- 'UPPER_LIMIT': upper_limit_dict,
- 'UPPER_INV_LIMIT': upper_inv_limit_dict,
- 'UPPER_IMP_LIMIT': upper_imp_limit_dict,
- 'WEIGHTS': weights,
- }
- }
- return model_data
-
-
-def convert_to_dict(input_data):
- """
- Checks if the passed method is in the correct format and converts it accordingly.
-
- Args:
- input_data (Union[str, list, dict]): Input data to be converted.
-
- Returns:
- dict: Converted dictionary with methods and their weights.
-
- Raises:
- ValueError: If the input data is not in the expected format.
- """
-
- # Check if the input is a string
- if isinstance(input_data, str):
- return {input_data: 1}
-
- # Check if the input is a list of strings
- elif isinstance(input_data, list) and all(isinstance(item, str) for item in input_data):
- return {item: 1 for item in input_data}
-
- # Check if the input is a dictionary with numerical values
- elif isinstance(input_data, dict) and all(isinstance(value, (int, float)) for value in input_data.values()):
- return input_data
-
- # If the input is of any other type, raise an error
- else:
- raise ValueError(
- "Input should be either a string, a list of strings, or a dictionary with string indices and numerical values")
diff --git a/pulpo/utils/optimizer.py b/pulpo/utils/optimizer.py
deleted file mode 100644
index 3e9ee1a..0000000
--- a/pulpo/utils/optimizer.py
+++ /dev/null
@@ -1,286 +0,0 @@
-import pyomo.environ as pyo
-from pyomo.contrib import appsi
-
-def create_model():
- """
- Builds an abstract model on top of the ecoinvent database.
-
- Returns:
- AbstractModel: The Pyomo abstract model for optimization.
- """
- model = pyo.AbstractModel()
-
- # Sets
- model.PRODUCT = pyo.Set(doc='Set of intermediate products (or technosphere exchanges), indexed by i')
- model.PROCESS = pyo.Set(doc='Set of processes (or activities), indexed by j')
- model.ENV_COST = pyo.Set(doc='Set of environmental cost flows, indexed by e')
- model.INDICATOR = pyo.Set(doc='Set of impact assessment indicators, indexed by h')
- model.INV = pyo.Set(doc='Set of intervention flows, indexed by g')
- model.ENV_COST_PROCESS = pyo.Set(within=model.ENV_COST * model.PROCESS * model.INDICATOR, doc='Relation set between environmental cost flows and processes')
- model.ENV_COST_IN = pyo.Set(model.INDICATOR, within=model.ENV_COST)
- model.ENV_COST_OUT = pyo.Set(model.ENV_COST * model.INDICATOR, within=model.PROCESS)
- model.PROCESS_IN = pyo.Set(model.PROCESS, within=model.PRODUCT)
- model.PROCESS_OUT = pyo.Set(model.PRODUCT, within=model.PROCESS)
- model.PRODUCT_PROCESS = pyo.Set(within=model.PRODUCT * model.PROCESS, doc='Relation set between intermediate products and processes')
- model.INV_PROCESS = pyo.Set(within=model.INV * model.PROCESS, doc='Relation set between environmental flows and processes')
- model.INV_OUT = pyo.Set(model.INV, within=model.PROCESS)
-
- # Parameters
- model.UPPER_LIMIT = pyo.Param(model.PROCESS, mutable=True, within=pyo.Reals, doc='Maximum production capacity of process j')
- model.LOWER_LIMIT = pyo.Param(model.PROCESS, mutable=True, within=pyo.Reals, doc='Minimum production capacity of process j')
- model.UPPER_INV_LIMIT = pyo.Param(model.INV, mutable=True, within=pyo.Reals, doc='Maximum intervention flow g')
- model.UPPER_IMP_LIMIT = pyo.Param(model.INDICATOR, mutable=True, within=pyo.Reals, doc='Maximum impact on category h')
- model.ENV_COST_MATRIX = pyo.Param(model.ENV_COST_PROCESS, mutable=True, doc='Enviornmental cost matrix Q*B describing the environmental cost flows e associated to process j')
- model.INV_MATRIX = pyo.Param(model.INV_PROCESS, mutable=True, doc='Intervention matrix B describing the intervention flow g entering/leaving process j')
- model.FINAL_DEMAND = pyo.Param(model.PRODUCT, mutable=True, within=pyo.Reals, doc='Final demand of intermediate product flows (i.e., functional unit)')
- model.SUPPLY = pyo.Param(model.PRODUCT, mutable=True, within=pyo.Binary, doc='Binary parameter which specifies whether or not a supply has been specified instead of a demand')
- model.TECH_MATRIX = pyo.Param(model.PRODUCT_PROCESS, mutable=True, doc='Technology matrix A describing the intermediate product i produced/absorbed by process j')
- model.WEIGHTS = pyo.Param(model.INDICATOR, mutable=True, within=pyo.NonNegativeReals, doc='Weighting factors for the impact assessment indicators in the objective function')
-
- # Variables
- model.impacts = pyo.Var(model.INDICATOR, bounds=(-1e24, 1e24), doc='Environmental impact on indicator h evaluated with the established LCIA method')
- model.scaling_vector = pyo.Var(model.PROCESS, bounds=(-1e24, 1e24), doc='Activity level of each process to meet the final demand')
- model.inv_vector = pyo.Var(model.INV, bounds=(-1e24, 1e24), doc='Intervention flows')
- model.slack = pyo.Var(model.PRODUCT, bounds=(-1e24, 1e24), doc='Supply slack variables')
-
- # Building rules for sets
- model.Env_in_out = pyo.BuildAction(rule=populate_env)
- model.Process_in_out = pyo.BuildAction(rule=populate_in_and_out)
- model.Inv_in_out = pyo.BuildAction(rule=populate_inv)
-
- # Constraints
- model.FINAL_DEMAND_CNSTR = pyo.Constraint(model.PRODUCT, rule=demand_constraint)
- model.IMPACTS_CNSTR = pyo.Constraint(model.INDICATOR, rule=impact_constraint)
- model.INVENTORY_CNSTR = pyo.Constraint(model.INV, rule=inventory_constraint)
- model.UPPER_CNSTR = pyo.Constraint(model.PROCESS, rule=upper_constraint)
- model.LOWER_CNSTR = pyo.Constraint(model.PROCESS, rule=lower_constraint)
- model.SLACK_UPPER_CNSTR = pyo.Constraint(model.PRODUCT, rule=slack_upper_constraint)
- model.SLACK_LOWER_CNSTR = pyo.Constraint(model.PRODUCT, rule=slack_lower_constraint)
- model.INV_CNSTR = pyo.Constraint(model.INV, rule=upper_env_constraint)
- model.IMP_CNSTR = pyo.Constraint(model.INDICATOR, rule=upper_imp_constraint)
-
- # Objective function
- model.OBJ = pyo.Objective(sense=pyo.minimize, rule=objective_function)
-
- return model
-
-
-# Rule functions
-def populate_env(model):
- """Relates the environmental flows to the processes."""
- for i, j, h in model.ENV_COST_PROCESS:
- if i not in model.ENV_COST_IN[h]:
- model.ENV_COST_IN[h].add(i)
- model.ENV_COST_OUT[i, h].add(j)
-
-
-def populate_in_and_out(model):
- """Relates the inputs of an activity to its outputs."""
- for i, j in model.PRODUCT_PROCESS:
- model.PROCESS_OUT[i].add(j)
- model.PROCESS_IN[j].add(i)
-
-def populate_inv(model):
- """Relates the impacts to the environmental flows"""
- for a, j in model.INV_PROCESS:
- model.INV_OUT[a].add(j)
-
-def demand_constraint(model, i):
- """Fixes a value in the demand vector"""
- return sum(model.TECH_MATRIX[i, j] * model.scaling_vector[j] for j in model.PROCESS_OUT[i]) == model.FINAL_DEMAND[i] + model.slack[i]
-
-def impact_constraint(model, h):
- """Calculates all the impact categories"""
- return model.impacts[h] == sum(sum(model.ENV_COST_MATRIX[i, j, h] * model.scaling_vector[j] for j in model.ENV_COST_OUT[i, h]) for i in model.ENV_COST_IN[h])
-
-def inventory_constraint(model, g):
- """Calculates the environmental flows"""
- return model.inv_vector[g] == sum(model.INV_MATRIX[g, j] * model.scaling_vector[j] for j in model.INV_OUT[g])
-
-def upper_constraint(model, j):
- """Ensures that variables are within capacities (Maximum production constraint) """
- return model.scaling_vector[j] <= model.UPPER_LIMIT[j]
-
-def lower_constraint(model, j):
- """ Minimum production constraint """
- return model.scaling_vector[j] >= model.LOWER_LIMIT[j]
-
-def upper_env_constraint(model, g):
- """Ensures that variables are within capacities (Maximum production constraint) """
- return model.inv_vector[g] <= model.UPPER_INV_LIMIT[g]
-
-def upper_imp_constraint(model, h):
- """ Imposes upper limits on selected impact categories """
- return model.impacts[h] <= model.UPPER_IMP_LIMIT[h]
-
-
-def slack_upper_constraint(model, j):
- """ Slack variable upper limit for activities where supply is specified instead of demand """
- return model.slack[j] <= 1e20 * model.SUPPLY[j]
-
-def slack_lower_constraint(model, j):
- """ Slack variable upper limit for activities where supply is specified instead of demand """
- return model.slack[j] >= -1e20 * model.SUPPLY[j]
-
-def objective_function(model):
- """Objective is a sum over all indicators with weights. Typically, the indicator of study has weight 1, the rest 0"""
- return sum(model.impacts[h] * model.WEIGHTS[h] for h in model.INDICATOR)
-
-def calculate_methods(instance, lci_data, methods):
- """
- Calculates the impacts if a method with weight 0 has been specified.
-
- Args:
- instance: The Pyomo model instance.
- lci_data (dict): LCI data containing matrices and mappings.
- methods (dict): Methods for environmental impact assessment.
-
- Returns:
- instance: The updated Pyomo model instance with calculated impacts.
- """
- import scipy.sparse as sparse
- import numpy as np
- matrices = lci_data['matrices']
- intervention_matrix = lci_data['intervention_matrix']
- matrices = {h: matrices[h] for h in matrices if str(h) in methods}
- env_cost = {h: sparse.csr_matrix.dot(matrices[h], intervention_matrix) for h in matrices}
- try:
- scaling_vector = np.array([instance.scaling_vector[x].value for x in instance.scaling_vector])
- except:
- scaling_vector = np.array([instance.scaling_vector[x] for x in instance.scaling_vector])
-
- impacts = {}
- for h in matrices:
- impacts[h] = sum(env_cost[h].dot(scaling_vector))
-
- # Check if instance.impacts_calculated exists
- if hasattr(instance, 'impacts_calculated'):
- # Update values if it already exists
- for h in impacts:
- instance.impacts_calculated[h].value = impacts[h]
- else:
- # Create instance.impacts_calculated
- instance.impacts_calculated = pyo.Var([h for h in impacts], initialize=impacts)
- return instance
-
-def calculate_inv_flows(instance, lci_data):
- """
- Calculates elementary flows post-optimization.
-
- Args:
- instance: The Pyomo model instance.
- lci_data (dict): LCI data containing matrices and mappings.
-
- Returns:
- instance: The updated Pyomo model instance with calculated intervention flows.
- """
- import numpy as np
- intervention_matrix = lci_data['intervention_matrix']
- try:
- scaling_vector = np.array([instance.scaling_vector[x].value for x in instance.scaling_vector])
- except:
- scaling_vector = np.array([instance.scaling_vector[x] for x in instance.scaling_vector])
- flows = intervention_matrix.dot(scaling_vector)
- # Check if inv_flows already exists in the model
- # @TODO: Consider adding "inv_flows" directly as variable to the model and skip this check.
- if hasattr(instance, 'inv_flows'):
- # Update the values of the existing variable
- for i in range(intervention_matrix.shape[0]):
- instance.inv_flows[i].value = flows[i]
- else:
- # Create the variable if it does not exist
- instance.inv_flows = pyo.Var(range(0, intervention_matrix.shape[0]), initialize=dict(enumerate(flows)))
- return instance
-
-
-
-def instantiate(model_data):
- """
- Builds an instance of the optimization model with specific data and objective function.
-
- Args:
- model_data (dict): Data dictionary for the optimization model.
-
- Returns:
- ConcreteModel: The instantiated Pyomo model.
- """
- print('Creating Instance')
- model = create_model()
- problem = model.create_instance(model_data, report_timing=False)
- print('Instance created')
- return problem
-
-
-def solve_model(model_instance, gams_path=None, solver_name=None, options=None):
- """
- Solves the instance of the optimization model.
-
- Args:
- model_instance (ConcreteModel): The Pyomo model instance.
- gams_path (str, optional): Path to the GAMS solver. If None, GAMS will not be used.
- solver_name (str, optional): The solver to use ('highs', 'gams', or 'ipopt'). Defaults to 'highs' unless gams_path is provided.
- options (list, optional): Additional options for the solver.
-
- Returns:
- tuple: Results of the optimization and the updated model instance.
- """
- results = None
-
- # Use GAMS if gams_path is specified
- if gams_path and (solver_name is None or solver_name.lower() == 'gams'):
- pyo.pyomo.common.Executable('gams').set_path(gams_path)
- solver = pyo.SolverFactory('gams')
- print('GAMS solvers library availability:', solver.available())
- print('Solver path:', solver.executable())
-
- io_options = {
- 'mtype': 'lp', # Type of problem (lp, nlp, mip, minlp)
- 'solver': 'CPLEX', # Name of solver
- }
-
- if options is None:
- options = [
- 'option optcr = 1e-15;',
- 'option reslim = 3600;',
- 'GAMS_MODEL.optfile = 1;',
- '$onecho > cplex.opt',
- 'workmem=4096',
- 'scaind=1',
- #'numericalemphasis=1',
- #'epmrk=0.99',
- #'eprhs=1E-9',
- '$offecho',
- ]
-
- results = solver.solve(
- model_instance,
- keepfiles=True,
- symbolic_solver_labels=True,
- tee=False,
- report_timing=False,
- io_options=io_options,
- add_options=options
- )
-
- model_instance.solutions.load_from(results)
-
- # Use IPOPT if explicitly specified
- elif solver_name and solver_name.lower() == 'ipopt':
- opt = pyo.SolverFactory('ipopt')
- if options:
- for option in options:
- opt.options[option] = True
- results = opt.solve(model_instance)
-
- # Default to HiGHS if no solver specified or if solver_name is 'highs'
- else:
- opt = appsi.solvers.Highs()
- results = opt.solve(model_instance)
-
- return results, model_instance
-
-
- print('Optimization problem solved')
- ## TODO: Add a check for infeasibility and other solver errors
-
- return results, model_instance
\ No newline at end of file
diff --git a/pulpo/utils/saver.py b/pulpo/utils/saver.py
deleted file mode 100644
index 28dc282..0000000
--- a/pulpo/utils/saver.py
+++ /dev/null
@@ -1,160 +0,0 @@
-import pyomo.environ as pyo
-from pyomo.repn.plugins.baron_writer import *
-import pandas as pd
-from pathlib import Path
-from IPython.display import display
-
-def save_results(instance, project, database, choices, constraints, demand, process_map, itervention_map, directory, name):
- """
- Saves the results of a Pyomo optimization model to an Excel file.
-
- Args:
- instance: The Pyomo model instance.
- project (str): Name of the project.
- database (str): Name of the database.
- choices (dict): Choices for the model.
- constraints (dict): Constraints applied during optimization.
- demand (dict): Demand data used in optimization.
- process_map (dict): Mapping of process IDs to descriptions.
- itervention_map (dict): Mapping of intervention IDs to descriptions.
- directory (str): Directory to save the results file.
- name (str): Name of the results file.
- """
- # Check if data/results folder exists, if not create it
- Path(directory + '/results').mkdir(parents=True, exist_ok=True)
-
- # Recover dictionary values
- list_of_vars = []
- for v in instance.component_objects(ctype=pyo.Var, active=True, descend_into=True):
- for e in v._data:
- v._data[e] = value(v[e])
- list_of_vars.append(v)
-
- # Open xlsx writer
- writer = pd.ExcelWriter(directory + '/results/' + name, engine='xlsxwriter')
-
- # Raw results
- for v in list_of_vars:
- try:
- if str(v) == 'inv_flows' or str(v) == 'inv_vector':
- data = [(k, itervention_map[k], v) for k, v in v._data.items()]
- else:
- data = [(k, process_map[k], v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['ID', 'Process', 'Value'])
- except:
- data = [(k, v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['Key', 'Value'])
- df.sort_values(by=['Value'], inplace=True, ascending=False)
- df.to_excel(writer, sheet_name=v.name, index=False)
-
- # Normalize database to a list if it is a string
- if isinstance(database, str):
- database = [database]
-
- # Store the metadata
- metadata = [f"{project}__{db}" for db in database]
- pd.DataFrame(metadata).to_excel(writer, sheet_name='project and db')
-
- metadata = {}
- for choice in choices:
- i = 0
- temp_dict = []
- for alt in choices[choice]:
- temp_dict.append((alt, i, instance.scaling_vector[process_map[alt.key]]))
- i+=1
- metadata[(choice, 'Process')] = {'Process ' + str(i): process_map[process_map[alt.key]] for alt, i, val in temp_dict}
- metadata[(choice, 'Capacity')] = {'Process ' + str(i): choices[choice][alt] for alt, i, val in temp_dict}
- metadata[(choice, 'Value')] = {'Process ' + str(i): x for alt, i, x in temp_dict}
-
- pd.DataFrame(metadata).to_excel(writer, sheet_name='choices')
-
- metadata = {}
- metadata['Demand'] = {
- process_map[process_map[key]] if key in process_map else key: demand[key]
- for key in demand
- }
- pd.DataFrame(metadata).to_excel(writer, sheet_name='demand')
-
- metadata = {}
- metadata['Demand'] = {process_map[process_map[key]]: constraints[key] for key in constraints}
- pd.DataFrame(metadata).to_excel(writer, sheet_name='constraints')
-
- # Save xlsx file
- writer.close()
- return
-
-def summarize_results(instance, choices, constraints, demand, process_map, zeroes):
- """
- Summarizes the results of the optimization and prints them to the console.
-
- Args:
- instance: The Pyomo model instance.
- choices (dict): Choices for the model.
- constraints (dict): Constraints applied during optimization.
- demand (dict): Demand data used in optimization.
- process_map (dict): Mapping of process IDs to descriptions.
- zeroes (bool): Whether to include zero values in the summary.
- """
- metadata = {}
- metadata['Demand'] = {
- process_map[process_map[key]] if key in process_map else key: demand[key]
- for key in demand
- }
-
- print('The following demand / functional unit has been specified: ')
- display(pd.DataFrame(metadata))
-
- # Recover dictionary values
- list_of_vars = []
- for v in instance.component_objects(ctype=pyo.Var, active=True, descend_into=True):
- for e in v._data:
- v._data[e] = value(v[e])
- list_of_vars.append(v)
-
- # Raw results
- for v in list_of_vars:
- if v.name == 'impacts':
- try:
- data = [(k, process_map[k], v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['ID', 'Process', 'Value'])
- except:
- data = [(k, v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['Key', 'Value'])
- df.sort_values(by=['Value'], inplace=True, ascending=False)
- print('\nThese are the impacts contained in the objective:')
- display(df)
-
- if v.name == 'impacts_calculated':
- try:
- data = [(k, process_map[k], v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['ID', 'Process', 'Value'])
- except:
- data = [(k, v) for k, v in v._data.items()]
- df = pd.DataFrame(data, columns=['Key', 'Value'])
- df.sort_values(by=['Value'], inplace=True, ascending=False)
- print('\nThe following impacts were calculated: ')
- display(df)
-
- print('\nThe following choices were made: ')
- for choice in choices:
- metadata = {}
- i = 0
- temp_dict = []
- for alt in choices[choice]:
- if zeroes == False or instance.scaling_vector[process_map[alt.key]] != 0:
- temp_dict.append((alt, i, instance.scaling_vector[process_map[alt.key]]))
- i += 1
- metadata[(choice, 'Process')] = {'Process ' + str(i): process_map[process_map[alt.key]] for alt, i, val in temp_dict}
- metadata[(choice, 'Capacity')] = {'Process ' + str(i): choices[choice][alt] for alt, i, val in temp_dict}
- metadata[(choice, 'Value')] = {'Process ' + str(i): x for alt, i, x in temp_dict}
- print(choice)
- display(pd.DataFrame(metadata))
-
- if constraints == {}:
- print('No additional constraints have been passed.')
- else:
- metadata = {}
- metadata['Constraints'] = {process_map[process_map[key]]: constraints[key] for key in constraints}
- print('\nThe following constraints were implemented and oblieged: ')
- display(pd.DataFrame(metadata))
-
diff --git a/pulpo/utils/tests.py b/pulpo/utils/tests.py
deleted file mode 100644
index 1d234db..0000000
--- a/pulpo/utils/tests.py
+++ /dev/null
@@ -1,214 +0,0 @@
-import bw2data as bd
-import bw2calc as bc
-import copy
-import pulpo as pulpo
-from pulpo.utils.bw_parser import import_data, retrieve_methods, retrieve_env_interventions, retrieve_processes
-
-def setup_test_db():
- # Set the current project to "sample_project"
- bd.projects.set_current("sample_project")
-
- # Keys
- # Biosphere
- co2_key = ('biosphere', 'CO2')
- ch4_key = ('biosphere', 'CH4')
- pm_key = ('biosphere', 'PM')
- h2o_irrigation_key = ('biosphere', 'H2O_irrigation')
- # Technosphere
- wind_turbine_key = ('technosphere', 'wind turbine')
- steam_cycle_key = ('technosphere', 'steam cycle')
- lignite_extraction_key = ('technosphere', 'lignite extraction')
- oil_extraction_key = ('technosphere', 'oil extraction')
- e_car_key = ('technosphere', 'e-Car')
-
- # Define biosphere flows and create the "biosphere" database if it doesn't exist
- if "biosphere" not in bd.databases:
- biosphere_db = bd.Database("biosphere")
- biosphere_data = {
- ("biosphere", "CO2"): {
- "name": "Carbon dioxide, fossil",
- "categories": ("climate change", "GWP 100a"),
- "type": "emission",
- "unit": "kg",
- },
- ("biosphere", "CH4"): {
- "name": "Methane, agricultural",
- "categories": ("climate change", "GWP 100a"),
- "type": "emission",
- "unit": "kg",
- },
- ("biosphere", "PM"): {
- "name": "Particulate matter, industrial",
- "categories": ("air quality", "particulate matter"),
- "type": "emission",
- "unit": "g",
- },
- ("biosphere", "H2O_irrigation"): {
- "name": "Water, irrigation",
- "categories": ("water use", "irrigation"),
- "type": "resource",
- "unit": "m3",
- },
- }
- biosphere_db.write(biosphere_data)
-
- # Create the "technosphere" database if it doesn't exist
- if "technosphere" not in bd.databases:
- technosphere_db = bd.Database("technosphere")
- technosphere_db.write({})
- process_data = [
- ("oil extraction", "kg", "GLO", "oil"),
- ("lignite extraction", "kg", "GLO", "lignite"),
- ("steam cycle", "kWh", "GLO", "electricity"),
- ("wind turbine", "kWh", "GLO", "electricity"),
- ("e-Car", "tkm", "GLO", "transport"),
- ]
-
- for name, unit, location, ref_product in process_data:
- act = technosphere_db.new_activity(name)
- act["unit"] = unit
- act["location"] = location
- act["name"] = name
- act["reference product"] = ref_product
- act.new_exchange(amount=1.0, input=act.key, type="production").save()
- act.save()
-
- exchange_data = [
- [e_car_key, oil_extraction_key, 0.03, 'technosphere'],
- [e_car_key, lignite_extraction_key, 0.03, 'technosphere'],
- [oil_extraction_key, steam_cycle_key, 0.5, 'technosphere'],
- [lignite_extraction_key, steam_cycle_key, 0.5, 'technosphere'],
- [steam_cycle_key, e_car_key, 0.5, 'technosphere'],
- [wind_turbine_key, e_car_key, 0.5, 'technosphere'],
- [e_car_key, wind_turbine_key, 0.03, 'technosphere'],
- [co2_key, oil_extraction_key, 0.2, 'biosphere'],
- [co2_key, lignite_extraction_key, 0.3, 'biosphere'],
- [co2_key, steam_cycle_key, 1, 'biosphere'],
- [co2_key, wind_turbine_key, 0.1, 'biosphere'],
- [ch4_key, oil_extraction_key, 0.01, 'biosphere'],
- [ch4_key, lignite_extraction_key, 0.02, 'biosphere'],
- [pm_key, steam_cycle_key, 2.0, 'biosphere'],
- [pm_key, wind_turbine_key, 1.5, 'biosphere'],
- [h2o_irrigation_key, steam_cycle_key, 2.0, 'biosphere'],
- [h2o_irrigation_key, wind_turbine_key, 5.0, 'biosphere'],
- [pm_key, e_car_key, 0.1, 'biosphere'],
- [h2o_irrigation_key, e_car_key, 0.1, 'biosphere'],
- ]
-
- for input, target, amount, type in exchange_data:
- act = [act for act in technosphere_db if act.key==target][0]
- act.new_exchange(amount=amount, input=input, type=type).save()
- act.save()
-
- # Loop through the list of methods and deregister each one
- # Create a copy of the methods list
- methods_copy = copy.deepcopy(bd.methods)
- # Loop through the copy of methods and deregister each one
- for method in methods_copy:
- bd.Method(method).deregister()
-
- # Define LCIA methods and CFs
- methods_data = [
- ("climate change", "kg CO2eq", 2, "cc", "climate change CFs", "climate_change", "CO2", [(co2_key, 1), (ch4_key, 29.7)]),
- ("air quality", "ppm", 1, "aq", "air quality CFs", "air_quality", "PM", [(ch4_key, 29.7)]),
- ("resources", "m3", 1, "rc", "resource CFs", "resources", "H2O_irrigation", [(h2o_irrigation_key,1)]),
- ]
-
- for method_name, unit, num_cfs, abbreviation, description, filename, flow_code, flow_list in methods_data:
- method = bd.Method(("my project", method_name))
- method.register(**{
- "unit": unit,
- "num_cfs": num_cfs,
- "abbreviation": abbreviation,
- "description": description,
- "filename": filename,
- })
- method.write(flow_list)
-
-def sample_lcia():
- # Load the technosphere database
- bd.projects.set_current('sample_project')
- technosphere_db = bd.Database("technosphere")
- # Perform LCA with FU 1 for all activities
- act = {act.key: 1 for act in technosphere_db}
- # Perform Multi-LCA
- bd.calculation_setups['multiLCA'] = {'inv': [act], 'ia': list(bd.methods)}
- myMultiLCA = bd.MultiLCA('multiLCA')
- results = [round(x, 5) for x in myMultiLCA.results[0]]
- return results
-
-def test_database_import():
- result = sample_lcia()
- assert result == [4.22308, 1.5937, 11.1567] # Example assertion
-
-def test_import_data():
- # Test if the import works and has the expected structure
- methods = {
- "('my project', 'climate change')": 1,
- "('my project', 'air quality')": 1,
- "('my project', 'resources')": 1,
- }
-
- result = import_data('sample_project', 'technosphere', methods, 'biosphere')
-
- assert [idx for idx in result] == ['matrices', 'intervention_matrix', 'technology_matrix', 'process_map', 'intervention_map']
- assert result['technology_matrix'].shape == (5, 5)
- assert result['intervention_matrix'].shape == (4, 5)
- assert result['process_map'] == {('technosphere', 'oil extraction'): 0, ('technosphere', 'lignite extraction'): 1, ('technosphere', 'steam cycle'): 2, ('technosphere', 'wind turbine'): 3, ('technosphere', 'e-Car'): 4, 2: 'steam cycle | electricity | GLO', 1: 'lignite extraction | lignite | GLO', 0: 'oil extraction | oil | GLO', 3: 'wind turbine | electricity | GLO', 4: 'e-Car | transport | GLO'}
-
-def test_retrieve_activities():
- key = retrieve_processes('sample_project', 'technosphere', keys=["('technosphere', 'wind turbine')"])
- name = retrieve_processes('sample_project', 'technosphere', activities=['e-Car'])
- location = retrieve_processes('sample_project', 'technosphere', locations=['GLO'])
- assert key[0]['name'] == "wind turbine"
- assert name[0]['name'] == "e-Car"
- assert len(location) == 5
-
-def test_retrieve_methods():
- single_result = retrieve_methods('sample_project', ['climate'])
- multi_result = retrieve_methods('sample_project', ['project'])
- assert single_result == [('my project', 'climate change')]
- assert multi_result == [('my project', 'climate change'), ('my project', 'air quality'), ('my project', 'resources')]
-
-def test_retrieve_envflows():
- result = retrieve_env_interventions('sample_project', intervention_matrix='biosphere', keys="('biosphere', 'PM')")
- assert result[0]['name'] == 'Particulate matter, industrial'
-
-def test_pulpo():
- project = 'sample_project'
- database = 'technosphere'
- methods = {"('my project', 'climate change')": 1,
- "('my project', 'air quality')": 1,
- "('my project', 'resources')": 0}
-
- worker = pulpo.PulpoOptimizer(project, database, methods, '')
- worker.intervention_matrix = 'biosphere'
- worker.get_lci_data()
- eCar = worker.retrieve_activities(reference_products='transport')
- demand = {eCar[0]: 1}
- elec = worker.retrieve_activities(reference_products='electricity')
- choices = {'electricity': {elec[0]: 100, elec[1]: 100}}
- worker.instantiate(choices=choices, demand=demand)
- worker.solve()
- result_obj = round(worker.instance.OBJ(), 6)
- result_aux = round(worker.instance.impacts_calculated["('my project', 'resources')"].value, 5)
- assert result_obj == 0.103093
- assert result_aux == 5.25773
-
- upper_limit = {eCar[0]: 1}
- lower_limit = {eCar[0]: 1}
- worker.instantiate(choices=choices, upper_limit=upper_limit, lower_limit=lower_limit)
- worker.solve()
- result_obj = round(worker.instance.OBJ(), 6)
- result_aux = round(worker.instance.impacts_calculated["('my project', 'resources')"].value, 5)
- assert result_obj == 0.1
- assert result_aux == 5.1
-
-def setup():
- test_import_data()
- test_database_import()
- test_retrieve_activities()
- test_retrieve_envflows()
- test_retrieve_methods()
- test_pulpo()
- print('\nAll tests passed successfully. You are good to go!')
\ No newline at end of file
diff --git a/pulpo/utils/utils.py b/pulpo/utils/utils.py
deleted file mode 100644
index c2dd014..0000000
--- a/pulpo/utils/utils.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import bw2data as bd
-import bw2calc as bc
-from packaging import version
-
-def is_bw25():
- """Check if the installed Brightway packages adhere to bw25 versions."""
- # Define version thresholds
- THRESHOLDS = {
- "bw2calc": "2.0.dev5",
- "bw2data": "4.0.dev11",
- }
-
- try:
- for pkg, threshold in {"bw2calc": bc, "bw2data": bd}.items():
- pkg_version = ".".join(map(str, threshold.__version__)) if isinstance(threshold.__version__,
- tuple) else str(
- threshold.__version__)
- if version.parse(pkg_version) < version.parse(THRESHOLDS[pkg]):
- return False
- return True
- except Exception as e:
- raise RuntimeError(f"Error checking Brightway versions: {e}")
\ No newline at end of file
diff --git a/py-modindex.html b/py-modindex.html
new file mode 100644
index 0000000..8f5f3dc
--- /dev/null
+++ b/py-modindex.html
@@ -0,0 +1,625 @@
+
+
+
+
+
+
+
+
+
+
Python Module Index — pulpo documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Python Module Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index fff1cf5..0000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,61 +0,0 @@
-[build-system]
-requires = ["setuptools>=65.5", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[project]
-name = "pulpo-dev"
-version = "0.1.5"
-description = "Pulpo package for optimization in LCI databases"
-authors = [
- { name="Fabian Lechtenberg", email="fabian.lechtenberg@chem.ethz.ch" }
-]
-maintainers = [
- { name="Fabian Lechtenberg", email="fabian.lechtenberg@chem.ethz.ch" }
-]
-readme = "README.md"
-requires-python = ">=3.10,<=3.12"
-license = { text = "BSD License" }
-classifiers = [
- "Programming Language :: Python :: 3",
- "License :: OSI Approved :: BSD License",
- "Operating System :: OS Independent"
-]
-dependencies = [
- "fs==2.4.16",
- "pyomo<=6.6.2",
- "highspy==1.8.0",
- "ipython==8.14.0",
- "jupyterlab",
- "numpy<2.0.0",
- "pandas",
- "scipy<=1.14.1",
- "tqdm",
- "xlsxwriter"
-]
-
-[project.optional-dependencies]
-bw2 = [
- "bw2calc<=1.8.2",
- "bw2data<=3.9.9"
-]
-bw25 = [
- "bw2calc>=2.0.0",
- "bw2data>=4.0.0"
-]
-
-[project.urls]
-homepage = "https://github.com/flechtenberg/pulpo"
-repository = "https://github.com/flechtenberg/pulpo"
-
-[tool.setuptools]
-include-package-data = true
-packages = ["pulpo"]
-
-[tool.flake8]
-max_line_length = 88
-exclude = [
- ".tox",
- "build",
- "dist",
- ".eggs"
-]
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index d877da3..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-bw2calc==2.0.1
-bw2data==4.3.0
-fs==2.4.16
-pyomo==6.5.0
-highspy==1.8.0
-ipython==8.14.0
-jupyter
-tqdm
-xlsxwriter
\ No newline at end of file
diff --git a/search.html b/search.html
new file mode 100644
index 0000000..cb51c18
--- /dev/null
+++ b/search.html
@@ -0,0 +1,599 @@
+
+
+
+
+
+
+
+
+
Search - pulpo documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to top
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Search
+
+
+
Error
+
Please activate JavaScript to enable the search functionality.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/searchindex.js b/searchindex.js
new file mode 100644
index 0000000..7f67213
--- /dev/null
+++ b/searchindex.js
@@ -0,0 +1 @@
+Search.setIndex({"alltitles": {"1. Correction": [[10, "correction"]], "2. Warning": [[10, "warning"]], "3. Temporary Ban": [[10, "temporary-ban"]], "4. Permanent Ban": [[10, "permanent-ban"]], "
Biosphere Matrix B ": [[14, "biosphere-matrix-b"]], "
Characterization Factor Matrix Q ": [[14, "characterization-factor-matrix-q"]], "
Technosphere Matrix A ": [[14, "technosphere-matrix-a"]], "API Reference": [[0, "api-reference"]], "Adding Constraints": [[20, "adding-constraints"]], "Attribution": [[10, "attribution"]], "Cauldron": [[23, "cauldron"]], "Changelog": [[9, "changelog"]], "Choice Capacity Constraints \u2194": [[14, "choice-capacity-constraints"]], "Choices": [[15, "choices"]], "Choices in PULPO": [[15, "choices-in-pulpo"]], "Classes": [[2, "classes"]], "Constraints": [[16, "constraints"]], "Contribute to the Project": [[23, "contribute-to-the-project"]], "Contributing": [[11, "contributing"]], "Contributing to the code, examples or documentation": [[11, "contributing-to-the-code-examples-or-documentation"]], "Contributor Covenant Code of Conduct": [[10, "contributor-covenant-code-of-conduct"]], "D\u00e9part de Sentier Membership": [[23, "depart-de-sentier-membership"]], "Elementary Flows": [[12, "elementary-flows"]], "Enforcement": [[10, "enforcement"]], "Enforcement Guidelines": [[10, "enforcement-guidelines"]], "Enforcement Responsibilities": [[10, "enforcement-responsibilities"]], "Example Collection": [[13, "example-collection"]], "Example Usage:": [[20, "example-usage"]], "Full Nomenclature": [[24, "full-nomenclature"]], "Functional Unit": [[17, "functional-unit"]], "Functions": [[2, "functions"], [3, "functions"], [4, "functions"], [6, "functions"], [7, "functions"], [8, "functions"]], "Getting Started": [[18, "getting-started"]], "Installation": [[21, "installation"]], "Instantiate": [[20, "instantiate"]], "Instantiate the worker": [[12, "instantiate-the-worker"]], "LCA to Optimization": [[24, "lca-to-optimization"]], "License": [[22, "license"]], "Life Cycle Optimization (LCO) with PULPO": [[25, "life-cycle-optimization-lco-with-pulpo"]], "Linear Programming": [[24, "linear-programming"]], "Module Contents": [[2, "module-contents"], [3, "module-contents"], [4, "module-contents"], [6, "module-contents"], [7, "module-contents"], [8, "module-contents"]], "Multiple Objectives": [[19, "multiple-objectives"]], "Objective": [[19, "objective"]], "Optimization": [[24, "optimization"]], "Optimize / Solve": [[20, "optimize-solve"]], "Optimize and Interpret Results": [[20, "optimize-and-interpret-results"]], "Our Pledge": [[10, "our-pledge"]], "Our Standards": [[10, "our-standards"]], "PULPO Electricity Showcase": [[12, "pulpo-electricity-showcase"]], "Passing activity name (\u2699\ufe0f), reference_product (\ud83d\udce6) and/or location (\ud83d\uddfa\ufe0f)": [[12, "passing-activity-name-reference-product-and-or-location"]], "Passing keys \ud83d\udd11": [[12, "passing-keys"]], "Problem Formulation": [[14, "problem-formulation"]], "Rectangular Matrix Construction": [[24, "rectangular-matrix-construction"]], "Report bugs or errors": [[11, "report-bugs-or-errors"]], "Rice Example": [[14, "rice-example"]], "Save and summarize the results \ud83d\udcbe\ud83d\udcc8": [[12, "save-and-summarize-the-results"]], "Scope": [[10, "scope"]], "Setup": [[12, "setup"], [19, "setup"]], "Setup and Objective": [[19, "setup-and-objective"]], "Simple Example": [[24, "simple-example"]], "Simple Unconstrained Instantiation": [[20, "simple-unconstrained-instantiation"]], "Solve the instance": [[12, "solve-the-instance"]], "Specification in PULPO": [[16, "specification-in-pulpo"], [17, "specification-in-pulpo"]], "Specify the choices": [[12, "specify-the-choices"]], "Specify the functional unit": [[12, "specify-the-functional-unit"]], "Submodules": [[1, "submodules"], [5, "submodules"]], "Subpackages": [[1, "subpackages"]], "Summarize / Interpret Results": [[20, "summarize-interpret-results"]], "Summary of Cases:": [[14, "summary-of-cases"]], "Support Brightway": [[23, "support-brightway"]], "Technosphere Flows": [[12, "technosphere-flows"]], "Theory": [[24, "theory"]], "Updating pulpo": [[21, "updating-pulpo"]], "Upper Limit on Wood Pellet Boiler": [[14, "upper-limit-on-wood-pellet-boiler"]], "Upper Limits \u2b06": [[14, "upper-limits"]], "Visualization and Iteration": [[20, "visualization-and-iteration"]], "You want more interaction?": [[18, null]], "[0.0.1] - 2023-10-10": [[9, "id4"]], "[0.1.3] - 2024-12-01": [[9, "id3"]], "[0.1.4] - 2025-01-05": [[9, "id2"]], "[0.1.5] - 2025-01-??": [[9, "id1"]], "pulpo": [[1, "module-pulpo"]], "pulpo.pulpo": [[2, "module-pulpo.pulpo"]], "pulpo.utils": [[5, "module-pulpo.utils"]], "pulpo.utils.bw_parser": [[3, "module-pulpo.utils.bw_parser"]], "pulpo.utils.converter": [[4, "module-pulpo.utils.converter"]], "pulpo.utils.optimizer": [[6, "module-pulpo.utils.optimizer"]], "pulpo.utils.saver": [[7, "module-pulpo.utils.saver"]], "pulpo.utils.utils": [[8, "module-pulpo.utils.utils"]], "\u2728 Capabilities": [[25, "capabilities"]], "\ud83d\udcac Support": [[25, "support"]], "\ud83e\udd47 Fix an error yourself": [[11, "fix-an-error-yourself"]], "\ud83e\udd48 Report an error": [[11, "report-an-error"]]}, "docnames": ["content/api/index", "content/api/pulpo/index", "content/api/pulpo/pulpo/index", "content/api/pulpo/utils/bw_parser/index", "content/api/pulpo/utils/converter/index", "content/api/pulpo/utils/index", "content/api/pulpo/utils/optimizer/index", "content/api/pulpo/utils/saver/index", "content/api/pulpo/utils/utils/index", "content/changelog", "content/codeofconduct", "content/contributing", "content/examples/electricity_showcase", "content/examples/index", "content/examples/rice_example", "content/getting_started/choices", "content/getting_started/constraints", "content/getting_started/functional_unit", "content/getting_started/index", "content/getting_started/objective", "content/getting_started/optimize_and_interpret", "content/installation", "content/license", "content/other/support", "content/theory", "index"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1}, "filenames": ["content/api/index.rst", "content/api/pulpo/index.rst", "content/api/pulpo/pulpo/index.rst", "content/api/pulpo/utils/bw_parser/index.rst", "content/api/pulpo/utils/converter/index.rst", "content/api/pulpo/utils/index.rst", "content/api/pulpo/utils/optimizer/index.rst", "content/api/pulpo/utils/saver/index.rst", "content/api/pulpo/utils/utils/index.rst", "content/changelog.md", "content/codeofconduct.md", "content/contributing.md", "content/examples/electricity_showcase.ipynb", "content/examples/index.md", "content/examples/rice_example.ipynb", "content/getting_started/choices.md", "content/getting_started/constraints.md", "content/getting_started/functional_unit.md", "content/getting_started/index.md", "content/getting_started/objective.md", "content/getting_started/optimize_and_interpret.md", "content/installation.md", "content/license.md", "content/other/support.md", "content/theory.md", "index.md"], "indexentries": {"calculate_inv_flows() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.calculate_inv_flows", false]], "calculate_methods() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.calculate_methods", false]], "combine_inputs() (in module pulpo.utils.converter)": [[4, "pulpo.utils.converter.combine_inputs", false]], "convert_to_dict() (in module pulpo.utils.converter)": [[4, "pulpo.utils.converter.convert_to_dict", false]], "create_model() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.create_model", false]], "demand_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.demand_constraint", false]], "electricity_showcase() (in module pulpo.pulpo)": [[2, "pulpo.pulpo.electricity_showcase", false]], "get_lci_data() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.get_lci_data", false]], "hydrogen_showcase() (in module pulpo.pulpo)": [[2, "pulpo.pulpo.hydrogen_showcase", false]], "impact_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.impact_constraint", false]], "import_data() (in module pulpo.utils.bw_parser)": [[3, "pulpo.utils.bw_parser.import_data", false]], "install_generic_db() (in module pulpo.pulpo)": [[2, "pulpo.pulpo.install_generic_db", false]], "install_rice_husk_db() (in module pulpo.pulpo)": [[2, "pulpo.pulpo.install_rice_husk_db", false]], "instantiate() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.instantiate", false]], "instantiate() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.instantiate", false]], "inventory_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.inventory_constraint", false]], "is_bw25() (in module pulpo.utils.utils)": [[8, "pulpo.utils.utils.is_bw25", false]], "lower_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.lower_constraint", false]], "module": [[1, "module-pulpo", false], [2, "module-pulpo.pulpo", false], [3, "module-pulpo.utils.bw_parser", false], [4, "module-pulpo.utils.converter", false], [5, "module-pulpo.utils", false], [6, "module-pulpo.utils.optimizer", false], [7, "module-pulpo.utils.saver", false], [8, "module-pulpo.utils.utils", false]], "objective_function() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.objective_function", false]], "plastic_showcase() (in module pulpo.pulpo)": [[2, "pulpo.pulpo.plastic_showcase", false]], "populate_env() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.populate_env", false]], "populate_in_and_out() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.populate_in_and_out", false]], "populate_inv() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.populate_inv", false]], "pulpo": [[1, "module-pulpo", false]], "pulpo.pulpo": [[2, "module-pulpo.pulpo", false]], "pulpo.utils": [[5, "module-pulpo.utils", false]], "pulpo.utils.bw_parser": [[3, "module-pulpo.utils.bw_parser", false]], "pulpo.utils.converter": [[4, "module-pulpo.utils.converter", false]], "pulpo.utils.optimizer": [[6, "module-pulpo.utils.optimizer", false]], "pulpo.utils.saver": [[7, "module-pulpo.utils.saver", false]], "pulpo.utils.utils": [[8, "module-pulpo.utils.utils", false]], "pulpooptimizer (class in pulpo.pulpo)": [[2, "pulpo.pulpo.PulpoOptimizer", false]], "retrieve_activities() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.retrieve_activities", false]], "retrieve_env_interventions() (in module pulpo.utils.bw_parser)": [[3, "pulpo.utils.bw_parser.retrieve_env_interventions", false]], "retrieve_envflows() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.retrieve_envflows", false]], "retrieve_methods() (in module pulpo.utils.bw_parser)": [[3, "pulpo.utils.bw_parser.retrieve_methods", false]], "retrieve_methods() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.retrieve_methods", false]], "retrieve_processes() (in module pulpo.utils.bw_parser)": [[3, "pulpo.utils.bw_parser.retrieve_processes", false]], "retrieve_processes() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.retrieve_processes", false]], "save_results() (in module pulpo.utils.saver)": [[7, "pulpo.utils.saver.save_results", false]], "save_results() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.save_results", false]], "slack_lower_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.slack_lower_constraint", false]], "slack_upper_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.slack_upper_constraint", false]], "solve() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.solve", false]], "solve_model() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.solve_model", false]], "summarize_results() (in module pulpo.utils.saver)": [[7, "pulpo.utils.saver.summarize_results", false]], "summarize_results() (pulpo.pulpo.pulpooptimizer method)": [[2, "pulpo.pulpo.PulpoOptimizer.summarize_results", false]], "upper_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.upper_constraint", false]], "upper_env_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.upper_env_constraint", false]], "upper_imp_constraint() (in module pulpo.utils.optimizer)": [[6, "pulpo.utils.optimizer.upper_imp_constraint", false]]}, "objects": {"": [[1, 0, 0, "-", "pulpo"]], "pulpo": [[2, 0, 0, "-", "pulpo"], [5, 0, 0, "-", "utils"]], "pulpo.pulpo": [[2, 1, 1, "", "PulpoOptimizer"], [2, 3, 1, "", "electricity_showcase"], [2, 3, 1, "", "hydrogen_showcase"], [2, 3, 1, "", "install_generic_db"], [2, 3, 1, "", "install_rice_husk_db"], [2, 3, 1, "", "plastic_showcase"]], "pulpo.pulpo.PulpoOptimizer": [[2, 2, 1, "", "get_lci_data"], [2, 2, 1, "", "instantiate"], [2, 2, 1, "", "retrieve_activities"], [2, 2, 1, "", "retrieve_envflows"], [2, 2, 1, "", "retrieve_methods"], [2, 2, 1, "", "retrieve_processes"], [2, 2, 1, "", "save_results"], [2, 2, 1, "", "solve"], [2, 2, 1, "", "summarize_results"]], "pulpo.utils": [[3, 0, 0, "-", "bw_parser"], [4, 0, 0, "-", "converter"], [6, 0, 0, "-", "optimizer"], [7, 0, 0, "-", "saver"], [8, 0, 0, "-", "utils"]], "pulpo.utils.bw_parser": [[3, 3, 1, "", "import_data"], [3, 3, 1, "", "retrieve_env_interventions"], [3, 3, 1, "", "retrieve_methods"], [3, 3, 1, "", "retrieve_processes"]], "pulpo.utils.converter": [[4, 3, 1, "", "combine_inputs"], [4, 3, 1, "", "convert_to_dict"]], "pulpo.utils.optimizer": [[6, 3, 1, "", "calculate_inv_flows"], [6, 3, 1, "", "calculate_methods"], [6, 3, 1, "", "create_model"], [6, 3, 1, "", "demand_constraint"], [6, 3, 1, "", "impact_constraint"], [6, 3, 1, "", "instantiate"], [6, 3, 1, "", "inventory_constraint"], [6, 3, 1, "", "lower_constraint"], [6, 3, 1, "", "objective_function"], [6, 3, 1, "", "populate_env"], [6, 3, 1, "", "populate_in_and_out"], [6, 3, 1, "", "populate_inv"], [6, 3, 1, "", "slack_lower_constraint"], [6, 3, 1, "", "slack_upper_constraint"], [6, 3, 1, "", "solve_model"], [6, 3, 1, "", "upper_constraint"], [6, 3, 1, "", "upper_env_constraint"], [6, 3, 1, "", "upper_imp_constraint"]], "pulpo.utils.saver": [[7, 3, 1, "", "save_results"], [7, 3, 1, "", "summarize_results"]], "pulpo.utils.utils": [[8, 3, 1, "", "is_bw25"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function"}, "terms": {"": [2, 3, 10, 12, 14, 15, 17, 18, 19, 24], "0": [6, 10, 12, 14, 15, 16, 17, 19, 24], "00": 14, "00x1e12": 12, "01": 24, "0105": 24, "02": 14, "03": 14, "05": [14, 24], "05s_3": 24, "08": [14, 24], "08108": 24, "09": 12, "1": [0, 6, 12, 14, 15, 17, 18, 19, 22, 24, 25], "10": [12, 14, 16, 21], "1000": [14, 24], "100000": [12, 16], "100a": [12, 19], "11": [12, 14, 17], "12": [12, 14, 15], "128": 12, "13": 14, "14": 14, "15": [12, 14], "16": 14, "170": 14, "18": [12, 14], "191744e": 12, "1e": 16, "1e10": 14, "1e16": 12, "1e20": 15, "1ex": 24, "1s_2": 24, "2": [2, 12, 14, 15, 22, 25], "20": 14, "2013": [12, 19], "2016": [13, 14], "2018": 12, "2023": 12, "2024": 22, "21": 14, "22": 12, "222": [12, 16], "23": 14, "24": [12, 14], "25": [14, 23], "27": 14, "28819e": [12, 17], "29": 14, "3": [2, 12, 13, 14, 15, 19, 21, 22], "33": 14, "35": 14, "36": 14, "360": 14, "37": 14, "3mw": [12, 15], "4": [2, 12, 14, 16, 18], "40": [12, 19], "45": 14, "47": 14, "473d4bb488e8f903b58203f3e5161636": 12, "48": 14, "5": [2, 12, 14, 18, 24], "50": 14, "54054": 24, "56": 14, "560": 14, "566": 14, "583": 24, "5883": 24, "599836e": 12, "5e12": [12, 16], "6": [12, 14], "60": 14, "65": 14, "69": 14, "69x1e13": 12, "72": 14, "739234e": 12, "76": 14, "764977e": 12, "8": [12, 13, 19], "819": 12, "859": 14, "9": [12, 14], "920967e": 12, "95": 24, "95s_3": 24, "962727b9a36bcaa186f222b29b57f6a3": 12, "97": 14, "9s_2": 24, "A": [2, 10, 11, 12, 19, 22, 24], "AND": 22, "AS": 22, "And": [12, 16], "As": [12, 14, 16, 24], "At": 14, "BE": 22, "BUT": 22, "BY": 22, "Be": 12, "Being": 10, "By": [15, 24], "FOR": 22, "For": [10, 12, 14, 15, 16, 17, 20, 21, 24], "IF": 22, "IN": 22, "If": [2, 4, 6, 11, 12, 14, 20, 23, 25], "In": [12, 14, 15, 16, 17, 18, 19, 24], "It": [12, 14, 17, 19, 23, 25], "Its": 24, "NO": 22, "NOT": 22, "No": 10, "OF": 22, "ON": 22, "OR": 22, "On": 21, "SUCH": 22, "Such": 15, "THE": 22, "TO": 22, "The": [2, 6, 7, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 24, 25], "There": 12, "These": [12, 16, 19, 24], "To": [14, 16, 19, 20, 21, 24], "Will": 2, "With": [12, 14, 16, 19], "_": 14, "_1": 24, "_2": 24, "_i": 24, "a_": 24, "abbrevi": 23, "about": [10, 14], "abov": [12, 15, 16, 22], "abstract": [6, 20], "abstractmodel": 6, "abus": 10, "academ": 23, "accept": [10, 14], "access": [14, 18, 20], "accord": 12, "accordingli": [4, 17], "account": [10, 12, 14, 15, 24, 25], "achiev": [14, 19], "acidif": 19, "across": 15, "act": 10, "action": 10, "activ": [2, 3, 6, 14, 15, 16, 17, 21, 24, 25], "activit": 12, "ad": 14, "adapt": [10, 12, 14], "add": [11, 13, 14], "addit": [2, 6, 12, 14, 20, 24], "addition": [12, 19], "address": [10, 19], "adher": 8, "adjust": [12, 14, 19], "adress": 14, "advanc": [10, 12, 19], "advis": 22, "affect": 10, "after": [14, 20], "ag": 10, "again": 24, "aggress": 10, "aim": [18, 19], "air": 24, "al": [13, 14], "algorithm": 24, "align": [10, 24], "all": [3, 4, 6, 9, 10, 12, 14, 15, 16, 19, 22, 23, 24], "alloc": 16, "allow": [10, 14, 24], "almost": 12, "also": [10, 12, 14, 15, 16, 19], "altern": [12, 14, 15, 16], "although": [14, 25], "alwai": [12, 16, 24], "america": 12, "among": [15, 24], "amount": 17, "an": [4, 6, 7, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 24], "analys": [14, 24], "analysi": [20, 24], "anchor": 14, "ani": [3, 10, 11, 14, 15, 17, 19, 22, 25], "anoth": [12, 14], "answer": 10, "anticip": 14, "anymor": 12, "anyth": 13, "apart": 12, "apolog": 10, "apologi": 10, "app": [12, 19], "appear": [10, 14], "append": [12, 14], "appl": 21, "appli": [2, 7, 10, 16, 24, 25], "appoint": 10, "approach": [14, 15, 24], "appropri": [10, 21, 24], "ar": [6, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25], "area": 16, "argument": 12, "aris": 22, "arm": 21, "around": [9, 10], "arrai": [14, 24], "ask": 12, "aspect": 20, "assess": [2, 4, 6, 11, 12, 14, 15, 16, 19, 23, 25], "assign": [12, 14, 16], "associ": 23, "assum": [15, 24], "attack": 10, "attent": 10, "auto": 0, "autoapi": 0, "automat": 12, "auxiliar": [14, 24], "auxiliar_process": 14, "avail": [9, 10, 12, 14, 16, 20, 21, 24, 25], "avoid": [10, 21], "awar": 12, "ax": 24, "b": 24, "b_": 24, "b_e": 24, "background": [2, 3, 9, 12, 15, 16, 19, 25], "balanc": 14, "bar": 14, "base": [2, 3, 12, 14, 16, 17, 24, 25], "basic": [12, 18], "becaus": 12, "becom": [15, 25], "becquerel": 12, "been": [6, 12, 14, 15, 24], "befor": 12, "begin": [12, 14, 24], "behavior": 10, "behind": [12, 18], "being": 19, "below": [12, 14, 15, 18, 19, 24], "benefit": 14, "best": [10, 12, 14, 16], "between": [12, 14, 15, 19, 24], "beyond": 16, "bin": 21, "binari": [15, 22], "biospher": [2, 3, 12, 24], "biosphere3": 3, "biosphere_matrix": 2, "bodi": 10, "boiler_id": 14, "boiler_process": 14, "bool": [2, 7], "both": [9, 14, 15, 21], "bottom": [14, 24], "bound": [15, 16, 24], "boundari": [15, 16], "box": 15, "branch": 11, "break": 21, "brightwai": [8, 25], "brightway2": [2, 21], "brightway25": 21, "brightway25_nosolv": 21, "broader": [15, 16], "browser": [2, 12, 14], "bsd": 22, "bugfix": 9, "build": [6, 23, 25], "burn": 14, "busi": 22, "bw2": [9, 12, 21], "bw25": [8, 9, 12, 21], "bw_parser": [0, 1, 5], "c": [12, 14, 19, 22, 24], "calcul": [2, 6, 12, 14, 15, 19, 24], "calculate_inv_flow": 6, "calculate_method": 6, "call": [12, 15], "can": [2, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25], "capac": [6, 12, 16, 20, 24, 25], "care": 11, "caribbean": 12, "case": [12, 15, 16, 17, 18], "categori": [2, 3, 6, 12, 14, 19, 25], "caus": 22, "cdot": 24, "cellcolor": 14, "certain": [12, 16], "ch": [10, 25], "ch4": 14, "chain": 25, "chanc": 24, "chang": [9, 11, 12, 14, 15, 19, 21, 25], "channel": 10, "character": [2, 19, 24, 25], "characterist": 10, "characterization_matric": 2, "chart": 14, "check": [4, 8], "chem": [10, 25], "choic": [2, 4, 7, 16, 20, 24, 25], "choices_constrain": 14, "choos": [12, 14, 15, 24], "chosen": 15, "clarifi": 10, "clariti": 10, "class": [10, 12, 14], "claus": 22, "client": 23, "climat": [12, 14, 19], "co": 24, "co2": 14, "co2e": 14, "co2eq": 12, "coal": [12, 15, 24], "coal_act": 12, "coat": 15, "code": [12, 14, 18, 22, 23], "code_of_conduct": 10, "coeffici": 24, "collect": 14, "column": 24, "combin": [2, 4, 12, 14, 15, 19, 20], "combine_input": 4, "come": 12, "comment": 10, "commerci": [20, 23], "commit": 10, "common": [10, 24], "commun": [10, 11, 23], "compani": 23, "compat": [16, 21], "competit": 14, "complaint": 10, "complex": [19, 20, 24, 25], "composit": [14, 15], "compound": 12, "compromis": 14, "comput": 24, "concept": [16, 24], "concis": 20, "concret": 20, "concretemodel": 6, "conda": 21, "condit": [14, 15, 22], "confer": 23, "configur": [14, 15], "conflict": 21, "connect": 15, "consequ": [10, 14], "consequenti": 22, "consid": [10, 12, 14, 15, 16], "consider": 12, "consist": 25, "consol": 7, "constitut": 18, "constrain": [12, 14, 25], "constraint": [2, 4, 6, 7, 12, 24, 25], "construct": 10, "consum": [12, 17], "consumpt": [12, 24], "contact": [13, 25], "contain": [0, 2, 3, 4, 6, 12], "context": [15, 19], "continu": [10, 12, 15, 24], "contract": [22, 23], "contrast": 24, "contribut": 10, "contributor": 22, "control": 16, "conveni": [9, 17], "convert": [0, 1, 5, 14, 18, 24], "convert_to_dict": 4, "copi": [12, 14], "copyright": 22, "correct": 4, "correctli": 21, "correspond": [12, 14, 17, 24], "cost": 14, "could": [10, 12, 14, 15, 24], "coupl": 12, "cover": [15, 19], "cplex": [12, 20], "creat": [0, 2, 11, 12, 14, 19, 20, 21, 24], "create_model": 6, "criteria": [14, 17], "curiou": 14, "current": [12, 14, 21, 24], "cut": 12, "cutoff": [12, 13, 19], "cutoff38": 12, "cutoff38_foreground": 12, "cycl": [15, 19, 23, 24], "damag": 22, "darkorang": 14, "data": [2, 3, 4, 6, 7, 9, 12, 14, 17, 19, 22, 24], "databas": [2, 3, 6, 7, 9, 12, 13, 14, 15, 17, 19, 24], "datafram": [12, 14], "dd": 23, "de": [12, 15, 17], "deal": [12, 14, 15], "decis": [10, 12, 15, 19, 20, 24, 25], "deem": 10, "deepcopi": 14, "deeper": 12, "default": [2, 6], "defin": [14, 15, 16, 17, 18, 19, 24], "degre": [15, 19, 24, 25], "demand": [2, 4, 6, 7, 12, 14, 17, 20, 24, 25], "demand_constraint": 6, "demand_dict": 14, "demand_therm": 14, "demand_valu": 14, "demonstr": [10, 12, 14, 15], "densiti": 12, "departur": 24, "depend": [9, 14, 15, 19, 20, 21, 24], "depict": 15, "deriv": [14, 22, 24], "derogatori": 10, "describ": 11, "descript": 7, "design": 14, "desir": 16, "detail": 20, "determin": [10, 15, 24], "dev": [9, 21], "develop": [11, 21, 23], "deviat": 15, "diagon": 24, "dict": [2, 3, 4, 6, 7], "dictionari": [2, 3, 4, 6, 12, 14, 15, 16, 17, 19], "differ": [2, 9, 10, 12, 14, 15, 20, 24, 25], "differenti": 24, "direct": [16, 22], "directli": [11, 12, 18], "directori": [2, 7, 12, 14, 19], "dirnam": [12, 14, 19], "disabl": 10, "disclaim": [14, 22], "disconnect": 12, "discuss": 11, "disparag": 10, "displai": 12, "distanc": 17, "distinct": [15, 24], "distribut": 22, "dive": 12, "divers": 10, "divid": 14, "do": [13, 23, 25], "document": [0, 9, 22], "dodgerblu": 14, "doe": [12, 14], "don": 14, "done": [12, 14], "doubl": 12, "down": 24, "downgrad": 9, "downstream": 12, "driven": 24, "due": [14, 24], "duplic": 12, "dure": [2, 7, 10, 14], "e": [2, 10, 12, 14, 15, 19, 20, 24, 25], "each": [12, 14, 18, 21, 24], "earlier": 16, "eas": 24, "easier": 14, "ecoinv": [6, 12, 13, 19], "econom": [10, 14, 19], "ecosystem": [12, 19, 23], "edit": 10, "educ": 10, "ef": 16, "ef_categori": 14, "effect": [12, 15], "effici": [15, 16, 24], "either": [12, 21], "ej": 24, "elec": 12, "electr": [2, 13, 14, 15, 17, 18, 24, 25], "electricity_act": [12, 15], "electricity_market": [12, 17], "electricity_showcas": 2, "electricity_showcase_result": 12, "electricity_showcase_results_elem": 12, "elem": [12, 16], "elem_limit": 12, "element": [2, 12, 14, 16], "elementari": [6, 14], "elif": 12, "elimin": 24, "els": 12, "email": 10, "emiss": [12, 16, 20], "emissio": 12, "empathi": 10, "emphas": 24, "emploi": 12, "empow": 24, "empti": 14, "enabl": [9, 15, 17, 19, 24], "encompass": 19, "end": [12, 14, 24], "endors": 22, "endpoint": [12, 19], "energi": [14, 17], "enforc": [12, 14], "engag": 23, "ensur": [6, 16, 21, 24], "enter": 12, "entir": [15, 24, 25], "entri": [12, 14], "enumer": 14, "environ": [10, 18, 21], "environment": [2, 3, 4, 6, 14, 16, 17, 20, 24, 25], "epsilon": 14, "epsilon_constraint": 14, "epsilon_list": 14, "eq": [14, 24], "equal": 24, "equat": 24, "equival": [12, 24], "especi": [15, 16], "essenc": 12, "et": [13, 14], "etc": 24, "etern": 11, "ethnic": 10, "ethz": [10, 25], "eur": 23, "evalu": [12, 15, 18], "even": [15, 22, 24], "event": [10, 22], "everi": 14, "everyon": 10, "evid": 12, "ex": [12, 19], "exampl": [2, 10, 12, 15, 16, 17, 18, 19], "excel": [7, 12, 20], "exemplari": [15, 22], "exemplifi": 15, "exist": 12, "expand": [19, 24], "expect": [4, 11], "experi": 10, "explain": 18, "explan": 10, "explicit": 10, "explor": [14, 15, 24], "exponenti": 15, "exposur": 16, "express": [10, 22], "extend": [13, 14, 17], "extern": 10, "extract": [12, 14, 17], "extrem": 14, "f": [12, 14, 24], "f_i": 24, "fabian": [10, 12, 22, 25], "facilit": [9, 19], "factor": [2, 19, 24, 25], "factori": 14, "fail": 12, "fair": 10, "fairli": 10, "fall": 16, "fals": 2, "faq": 10, "far": 14, "farm": 14, "fashion": 14, "favor": 24, "featur": 11, "feedback": [10, 15], "few": 15, "file": [2, 7, 9, 12, 20], "filenam": 12, "filter": [2, 3, 17], "final": [12, 14, 24, 25], "final_demand_valu": 14, "financ": 23, "find": [14, 24], "fine": 12, "firebrick": 14, "first": [12, 14, 15, 20], "fit": 22, "fix": 6, "flechtenberg": 13, "flow": [2, 3, 6, 14, 16, 20, 24], "focu": [23, 24], "focus": [10, 15], "fold": 12, "folder": 12, "follow": [10, 11, 12, 14, 16, 18, 19, 20, 21, 22, 24, 25], "foral": 24, "fore": [9, 15, 19, 25], "foreground": [2, 3, 12, 15, 16], "foreground_inventori": 19, "foreground_market": 12, "fork": [11, 12], "form": [12, 22, 24], "format": [4, 12], "formul": [9, 24], "fossil": 12, "found": [11, 23], "four": 12, "frac": [14, 24], "framework": 25, "free": 10, "freedom": [15, 19, 24, 25], "frequent": 21, "from": [2, 3, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24], "front": 14, "fuel": [12, 16], "fulfil": 24, "full": [12, 14, 15, 16], "fulli": 19, "function": [14, 15, 19, 24], "further": [15, 20], "futur": [2, 12, 24], "g": [2, 6, 12, 14, 15, 19, 20, 25], "ga": 14, "gain": 20, "gam": [2, 6, 12, 19, 20], "gams_path": [2, 6, 12, 19, 20], "gender": 10, "gener": [0, 2, 12, 15, 16, 19, 24], "generic_db": 2, "generic_db_project": 2, "geq": 24, "german": [12, 13, 17, 18], "germani": 12, "get": [11, 24], "get_lci_data": [2, 12, 14, 19], "getcwd": [12, 14, 19], "github": 11, "give": 10, "given": [2, 14, 15], "glo": [12, 16], "global": [14, 16, 18, 19, 20], "go": 14, "goal": [14, 18, 19, 24, 25], "goe": 23, "good": [19, 22], "gracefulli": 10, "graphic": 24, "grate": 11, "greater": 24, "green": 15, "grow": 15, "growth": 15, "gt": 14, "guarante": 21, "guid": [16, 18, 23], "gw_categori": 14, "gwh": 12, "gwp": [12, 14, 18, 19, 24], "gwp100": 14, "h": [6, 24], "ha": [6, 12, 14, 15, 24, 25], "hand": [12, 24], "happen": [12, 14, 18], "harass": 10, "hard": [12, 15], "harm": 10, "have": [10, 11, 13, 15, 24, 25], "he": 24, "health": [12, 16, 19], "healthi": 10, "heat": 14, "help": 25, "henc": 14, "here": [12, 13, 14, 16, 17, 21, 24, 25], "hesit": 25, "high": [6, 12, 14, 15, 16, 17, 24], "higher": 12, "highlight": [14, 15, 16], "highspi": [9, 20], "hline": 14, "holder": 22, "hood": 18, "how": [12, 13, 14, 15, 18, 19], "howev": [14, 15, 16, 21, 22, 24], "html": 10, "http": 10, "human": [12, 16, 19], "husk": [2, 14], "hydrogen": 2, "hydrogen_showcas": 2, "hypothet": 15, "i": [2, 4, 6, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], "id": [7, 14], "ident": 10, "identifi": [15, 16, 24], "ignor": 14, "ij": 24, "illustr": [14, 15, 16, 18, 24], "imageri": 10, "impact": [2, 4, 6, 10, 12, 14, 15, 16, 17, 19, 20, 24, 25], "impact_constraint": 6, "impacts_calcul": 14, "implement": [14, 16, 24], "impli": 22, "import": [2, 3, 12, 14, 15, 19, 24], "import_data": 3, "impos": 6, "inaccess": 24, "inappropri": 10, "incid": 10, "incident": 22, "includ": [2, 7, 10, 16, 22, 23, 24], "inclus": [10, 24], "increas": [14, 15], "index": 15, "indic": [6, 12, 14, 19, 20, 24], "indirect": 22, "indirectli": 12, "individu": [10, 24], "ineffici": 15, "infinit": 15, "influenc": 15, "inform": [10, 12, 18, 23], "inher": [14, 16], "initi": [2, 9, 12, 14], "inner": [12, 15], "input": [2, 4, 6, 12, 15, 18, 20], "input_data": 4, "insight": [20, 24, 25], "inspect": 12, "inspir": 10, "instal": [8, 9, 14], "install_generic_db": 2, "install_rice_husk_db": [2, 14], "instanc": [6, 7, 9, 10, 14, 15, 24], "instanti": [2, 6, 14, 16], "instead": [6, 12, 14, 21, 24, 25], "institut": 23, "insult": 10, "int": [2, 3], "integ": 12, "integr": [14, 15, 19, 24], "intend": 25, "intent": 14, "interact": [10, 14], "interconnect": [15, 18], "interest": 25, "intern": [14, 24], "interpret": [15, 16, 18, 24, 25], "interrupt": 22, "intervent": [3, 4, 6, 7], "intervention_matrix": [3, 12], "intervention_matrix_nam": 3, "introduc": [12, 14, 15, 21, 24], "intuit": 14, "invalid": 12, "inventori": [2, 15, 24, 25], "inventory_constraint": 6, "invers": 24, "invert": 24, "investig": [10, 14], "invetig": 12, "invis": 10, "involv": [10, 14, 15, 24], "ionis": 16, "ipcc": [12, 19], "ipopt": 6, "is_bw25": 8, "issu": [9, 10, 11, 14], "iter": 14, "itervention_map": 7, "its": [6, 14, 17, 21, 22, 24], "j": [6, 24], "join": [12, 14, 19], "jupyt": [12, 18], "just": [10, 14, 20], "k": 12, "keep": 12, "kei": [2, 3, 14, 20], "kg": [12, 14, 24], "kind": [10, 14, 23], "km": 14, "knowledg": 14, "known": [14, 19, 24], "kwh": 24, "k\u00e4telh\u00f6n": [13, 14], "l": 24, "label": [14, 15, 24], "ladder": 10, "land": 16, "languag": 10, "larg": [15, 25], "largest": 12, "last": 12, "later": [12, 14, 24], "latin": 12, "lca": [15, 16, 17, 20, 23, 25], "lci": [2, 3, 4, 6, 12, 13, 14, 15, 17, 19], "lci_data": [4, 6, 14], "lcia": 19, "lco": [14, 18, 19, 24], "lcso": 19, "lead": [10, 14, 15, 25], "leader": 10, "learn": 10, "lechtenberg": [10, 12, 22, 25], "left": [15, 20], "leq": 24, "let": [12, 14], "level": [10, 12], "leverag": 24, "liabil": 22, "liabl": 22, "librari": 14, "licenc": 12, "life": [15, 19, 23, 24], "lightblu": 14, "lightcor": 14, "lightsalmon": 14, "lignit": [12, 15], "lignite_act": 12, "like": [10, 12, 20, 23, 24], "limit": [2, 4, 6, 12, 16, 22, 25], "linear": 12, "link": [2, 12], "linspac": 14, "linux": 21, "list": [2, 3, 4, 6, 14, 21, 22], "load": 19, "locat": [2, 3, 15, 16, 17], "login": 18, "long": [12, 16], "longer": [12, 24], "look": [12, 24], "loop": [14, 15], "loss": 22, "low": [12, 24], "lower": [2, 4, 12, 14, 24], "lower_constraint": 6, "lower_impact": 14, "lower_limit": [2, 4, 12], "lp": [12, 24], "m": 21, "machin": 15, "maco": 21, "made": [12, 14], "magnitud": 12, "mai": [10, 11, 12, 20, 21, 22, 24], "mail": 10, "main": 3, "make": [10, 11, 14, 15, 20, 24, 25], "manag": [9, 21], "mani": [24, 25], "manifold": 25, "manner": 16, "manual": [14, 15, 25], "manufactur": 15, "map": [4, 6, 7, 14], "market": [12, 13, 14, 15, 16, 17, 18, 24], "match": [2, 3, 12, 14], "materi": [12, 22, 25], "mathbf": 24, "mathemat": 19, "matric": [2, 4, 6, 24], "matrix": [2, 3, 16], "max_colwidth": 12, "maxim": 19, "maximum": [2, 6], "mean": [14, 24], "measur": [17, 19], "media": 10, "mediumorchid": 14, "meet": [14, 24], "member": [10, 11], "mention": 16, "merchant": 22, "met": 22, "metal": [15, 25], "method": [2, 3, 4, 6, 12, 14, 19, 20, 24], "methodologi": 16, "million": [14, 24], "min": 24, "min_": 24, "mind": 12, "minim": [12, 14, 18, 19, 24], "minimum": [6, 12, 14], "mistak": 10, "mix": [12, 15, 18, 24], "model": [2, 4, 6, 7, 12, 13, 14, 15, 20, 24, 25], "model_data": 6, "model_inst": 6, "moder": 10, "modif": 22, "modifi": 24, "modul": 12, "modular": 24, "monei": 23, "more": [3, 9, 14, 15, 16, 19, 23, 24], "moreov": 12, "most": [12, 18, 20], "move": 14, "mox": [12, 16], "mozilla": 10, "mt": 14, "multi": [14, 24], "multipl": [14, 17], "multipli": 24, "must": [12, 14, 15, 17, 18, 20, 21, 22, 24], "my": 14, "n": 21, "n_flow": 2, "n_input": 2, "n_method": 2, "n_proc": 2, "n_prod": 2, "n_reg": 2, "name": [2, 3, 7, 14, 17, 19, 20, 22], "nan": 14, "nation": 10, "natur": [10, 14], "natural_gas_boil": 14, "ndarrai": 2, "necessari": [12, 14, 19, 20], "need": [2, 12, 14, 16, 24, 25], "neg": [9, 24], "neglig": 22, "neither": 22, "nest": 15, "new": [11, 12, 14, 21, 24], "newer": 21, "next": [16, 19], "ng": 14, "non": [23, 24], "none": [2, 3, 6, 12, 14], "nor": 22, "normal": [14, 17], "notabl": 9, "notbeook": 12, "note": 15, "notebook": [2, 12], "notebook_dir": [12, 14, 19], "notic": 22, "notion": 14, "now": [9, 12, 14, 24], "np": [2, 14], "ntnu": 23, "nuclear": [12, 15, 16], "nuclear_fuel": [12, 16], "num": 14, "number": [2, 15], "numer": 24, "numpi": 14, "o": [12, 14, 19], "obj": 14, "object": [6, 12, 14, 20, 24], "objective_funct": 6, "oblig": 10, "observ": [12, 14], "obsolet": 2, "obtain": [12, 24], "occasion": 20, "off": [14, 19], "offens": 10, "offer": [15, 24], "offici": 10, "offlin": 10, "often": [16, 19], "omit": 12, "onc": [9, 19], "one": [3, 12, 14, 15, 17, 25], "ones": 24, "ongo": 19, "onli": [12, 14, 15, 21, 25], "onlin": 10, "onshor": [12, 15], "open": [2, 10, 11, 18, 20, 23], "opinion": 10, "optim": [0, 1, 2, 4, 5, 7, 9, 12, 13, 14, 15, 16, 18, 19], "optimum": [14, 24], "option": [2, 3, 6, 9, 11, 12, 14, 15, 16, 19, 20, 24], "orang": 14, "order": [12, 17, 18], "org": 10, "organ": 23, "orient": 10, "origin": [12, 14, 15, 24, 25], "other": [10, 12, 15, 16, 19, 22], "otherwis": [10, 22], "our": [11, 12], "out": [12, 14, 22], "outer": 15, "outlin": 21, "output": [6, 17, 24], "outsid": 14, "over": [6, 14], "overal": [10, 12], "overview": 20, "packag": [8, 9, 12, 18, 21, 25], "page": 0, "panda": [12, 14], "paper": [14, 24], "paramet": [2, 3, 4, 6, 7, 12, 14, 24], "pareto": 14, "pareto_front": 14, "parser": 18, "part": [12, 14, 15], "partial": 12, "particip": 10, "particular": 22, "particularli": [15, 24], "pass": [4, 20], "path": [2, 6, 12, 14, 19, 20], "pattern": 10, "pd": [12, 14], "peachpuff": 14, "peopl": 10, "per": [2, 14], "perform": [14, 15, 17, 18, 19, 20], "period": 10, "permiss": [10, 22], "permit": 22, "person": 10, "physic": 10, "pillar": 19, "pip": [9, 21], "place": 12, "plan": 14, "plant": [14, 24], "plastic": [2, 15], "plastic_showcas": 2, "platform": [24, 25], "pleas": [11, 12, 13], "plot": 14, "plot_cas": 14, "plot_demand": 14, "plot_funct": 14, "plot_pareto": 14, "plug": 24, "pmatrix": 24, "point": 14, "pointer": 19, "polici": 16, "polit": 10, "popul": 12, "populate_env": 6, "populate_in_and_out": 6, "populate_inv": 6, "pose": 24, "posit": 10, "possibl": [12, 14, 15, 19, 22, 24], "post": [6, 10], "potenti": [14, 18, 19, 20], "power": [12, 14, 24], "pr": 11, "practition": [15, 24], "prefer": 12, "prepar": 12, "pressur": [12, 15, 16], "previou": [12, 14, 16], "previous": [12, 24], "price": 14, "primari": [3, 14], "print": [7, 12, 14], "prior": 22, "priorit": 16, "privaci": 10, "privat": 10, "problem": [9, 12, 15, 16, 18, 19, 20, 24], "proce": 14, "process": [2, 6, 7, 12, 14, 15, 16, 17, 24], "process_map": [7, 14], "procur": 22, "produc": [12, 17, 24], "product": [2, 3, 6, 12, 14, 15, 17, 18, 22, 24, 25], "profession": 10, "profit": [22, 23], "profound": 14, "project": [2, 3, 7, 9, 12, 14, 19, 21], "promin": 18, "promot": 22, "prompt": 25, "promptli": 10, "provid": [6, 10, 14, 20, 22, 24], "public": [10, 14, 15, 23], "publish": 10, "pull": 11, "pulpo": [0, 9, 11, 13, 14, 18, 19, 24], "pulpo_bw25": [12, 19], "pulpo_env": 21, "pulpo_work": [12, 14, 15, 16, 17, 19, 20], "pulpo_worker_multi": 14, "pulpooptim": [2, 12, 14, 19], "pure": 15, "purpos": [12, 14, 22], "put": 16, "py": 9, "pyomo": [6, 7, 9, 25], "pyproject": 9, "python": [12, 18, 21, 25], "q": 24, "q_": 24, "qb": 24, "quad": 24, "qualiti": [12, 19], "quantifi": [17, 19], "quantit": [17, 19], "question": [10, 11, 25], "r": [12, 19], "race": 10, "radiat": 16, "radon": [12, 16], "rais": [4, 12], "random": 2, "rang": [14, 15, 24], "rather": 12, "ration": 14, "rational": 12, "raw": [12, 25], "re": 20, "reach": 14, "reactor": [12, 15, 16], "readi": 21, "realist": 24, "realiz": 14, "reason": 10, "recip": [12, 19], "recommend": [21, 25], "recycl": 15, "redistribut": 22, "reduct": 14, "refer": [2, 3, 12, 14, 15, 17, 19], "reference_product": [2, 3, 14, 15, 16, 17], "refin": 20, "regardless": 10, "region": [2, 12, 14, 25], "regul": 25, "regular": 17, "reject": 10, "rel": 16, "relat": 6, "relax": [12, 24], "releas": 21, "relev": [14, 25], "reli": [15, 24], "religion": 10, "remain": [14, 24], "remov": 10, "renku": 18, "repeat": 14, "replac": [12, 14], "report": 10, "repositori": [11, 12], "repres": [10, 15, 16, 19, 24], "represent": 19, "reproduc": [2, 22], "request": [10, 11], "requir": [9, 12, 14, 15, 18, 24], "rer": 12, "reserv": 22, "resolut": [14, 24], "resolv": [9, 11, 14, 18], "resourc": [12, 15, 16, 19, 20, 25], "respect": [10, 15, 19], "rest": [6, 14], "restrict": [12, 16], "result": [2, 6, 7, 14, 15, 18, 24], "results_df": 14, "results_list": 14, "retain": 22, "retriev": [2, 3, 9, 12, 14, 15, 17, 19], "retrieve_act": [2, 12, 15, 16, 17], "retrieve_env_intervent": 3, "retrieve_envflow": [2, 12, 16], "retrieve_method": [2, 3], "retrieve_process": [2, 3, 14, 17], "return": [2, 3, 4, 6, 12], "return_data": 2, "review": 10, "revolv": 9, "reward": 23, "rice": [2, 13], "rice_example_unconstrain": 14, "rice_factori": 14, "rice_husk_boil": 14, "rice_husk_collect": 14, "rice_husk_exampl": 14, "rice_husk_example_db": 14, "rice_husk_process": 14, "rice_husk_zone_": 14, "right": [10, 15, 22], "rise": 14, "rla": 12, "row": [14, 24], "run": [12, 18, 21], "s_2": 24, "s_3": 24, "s_j": 24, "said": 14, "same": [2, 12, 17], "satisfi": 24, "save": [2, 7, 14, 20, 24], "save_result": [2, 7, 12, 14, 20], "saver": [0, 1, 5], "scale": [12, 14, 15, 16, 20, 24, 25], "scaling_vector": 14, "scenario": [15, 16, 20, 25], "scienc": 23, "scipi": 9, "scope": [14, 18, 25], "script": 21, "scriptsiz": 14, "seamlessli": 16, "search": [2, 3, 12, 14], "secondari": 14, "section": [12, 14, 16, 18, 19, 24], "secur": 10, "see": [10, 12, 14, 23], "seed": 2, "seen": [12, 14], "select": [6, 12, 14, 15, 16], "self": 24, "sens": [15, 25], "separ": [9, 21], "seri": 10, "seriou": 10, "serv": 25, "server": 23, "servic": 22, "session": 18, "set": [2, 10, 12, 14, 15, 16, 17, 19, 24], "set_opt": 12, "setup": 9, "sever": [9, 12, 23], "sex": 10, "sexual": 10, "shall": 22, "share": [11, 12, 13, 18, 24], "shift": [15, 24], "should": [12, 15], "show": [16, 18], "showcas": [2, 13], "shown": [12, 14, 15, 24], "signific": [14, 15], "significantli": 25, "silicon": 21, "similar": [12, 16, 24], "similarli": 15, "simpl": 14, "simplest": 24, "simplex": 24, "simpli": 12, "simplifi": [14, 24], "simultan": [9, 14, 15, 24], "sinc": [12, 24], "singl": [10, 12, 19], "situat": [12, 16], "size": 10, "slack": [6, 9, 12, 24], "slack_lower_constraint": 6, "slack_upper_constraint": 6, "slight": 14, "slightli": 14, "slower": 20, "smaller": 12, "so": [12, 14, 23], "social": [10, 19], "socio": 10, "softwar": [21, 22, 23], "sole": 24, "solut": [9, 11, 12, 14, 24], "solv": [2, 6, 9, 14, 16, 24], "solve_model": 6, "solver": [2, 6, 12, 20], "solver_nam": [2, 6], "some": [11, 13], "someth": 11, "somewher": 12, "sort": 10, "sourc": [2, 3, 4, 6, 7, 8, 12, 14, 15, 20, 21, 22], "space": [10, 15], "span": 15, "special": 22, "specif": [6, 12, 15, 19, 22, 24], "specifi": [2, 3, 6, 9, 10, 14, 15, 16, 17, 19, 20, 24, 25], "sphinx": 0, "squar": [14, 24], "standard": [14, 24], "start": [9, 14, 24], "state": 14, "statu": 10, "step": [14, 18, 19, 20, 21, 24], "store": [12, 14], "str": [2, 3, 4, 6, 7, 12, 16], "strict": 22, "string": 2, "structur": [14, 24], "struggl": 20, "student": 23, "studi": [6, 12, 14, 17, 18, 24, 25], "sub_str": 3, "subsequ": 24, "substitut": [12, 14, 15, 22], "substr": 3, "suitabl": 12, "sum": [6, 14, 19, 24], "sum_": 24, "sum_h": 24, "sum_j": 24, "summar": [2, 7, 14], "summari": [2, 7, 12], "summarize_result": [2, 7, 12, 14, 20], "superstructur": [14, 15], "suppli": [6, 12, 14, 24, 25], "support": [21, 24], "sustain": [10, 19, 23], "swiss": 23, "switch": [9, 24], "sy": [12, 14], "syntax": 14, "system": [12, 13, 14, 15, 16, 17, 19, 20, 24, 25], "t": [14, 21, 24], "tackl": 24, "take": [10, 11, 12], "tangibl": [16, 25], "task": [24, 25], "tcm": [14, 24], "teach": 23, "technic": [14, 15, 16], "techniqu": 24, "technolog": 14, "technologi": [12, 14, 15, 18, 24, 25], "technospher": [2, 15, 24], "technosphere_matrix": 2, "tediou": 15, "term": [10, 12, 16], "test": 12, "text": [14, 24], "textcolor": 14, "than": [9, 12, 14, 20, 24], "thei": [10, 12, 16], "them": [7, 12, 20, 24], "theori": [18, 22], "thermal": 14, "thi": [0, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24], "think": 24, "thistl": 14, "those": 10, "thousand": 24, "threaten": 10, "three": [14, 19], "threshold": 16, "through": [10, 12, 15, 16, 18, 24], "throughout": 25, "time": [10, 11, 12, 14], "tno": 23, "toml": 9, "tool": 23, "top": [6, 24, 25], "tort": 22, "total": [12, 14, 17, 19, 24], "total_boil": 14, "total_zon": 14, "touch": 11, "toward": 10, "trace": 9, "trade": [14, 19], "tradit": [15, 16, 20, 24], "translat": 10, "transport": [12, 14], "travel": 17, "treat": 24, "troll": 10, "trough": 12, "truck": 14, "true": [2, 12, 14], "try": 21, "tum": 23, "tune": 12, "tupl": [2, 6], "turbin": [12, 15], "tutori": 12, "twh": 14, "two": [2, 11, 14, 15], "type": [2, 3, 4, 6, 12, 14, 24], "typic": [6, 20], "u": [10, 13, 25], "u235": 16, "unaccept": 10, "unconstrain": [12, 14, 15, 16, 24], "unconvent": 14, "uncov": 24, "under": [16, 17, 18], "underdetermin": 24, "union": [2, 3, 4], "uniqu": [12, 24], "unit": [14, 15, 19], "unless": 6, "unprocess": 14, "unprofession": 10, "unsolicit": 10, "unwelcom": 10, "uo2": [12, 16], "up": [2, 12, 14, 16, 24], "updat": [6, 12], "upgrad": 21, "upload": 12, "upper": [2, 4, 6, 12, 15, 16, 24], "upper_constraint": 6, "upper_elem_limit": [2, 12, 16, 20], "upper_env_constraint": 6, "upper_imp_constraint": 6, "upper_imp_limit": [2, 4, 14, 16, 20], "upper_impact": 14, "upper_inv_limit": 4, "upper_limit": [2, 4, 12, 14, 16, 20], "upstream": [12, 15], "us": [2, 6, 7, 9, 10, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 24], "user": [9, 12, 14, 15, 16, 17, 18, 20, 24], "usual": 12, "util": [0, 1, 15], "utilitii": 12, "v": 12, "v3": 16, "valid": 12, "valu": [2, 6, 7, 9, 12, 14, 15, 16, 20, 24, 25], "valuabl": [15, 16], "valueerror": [4, 12], "vari": [14, 25], "variabl": [6, 12, 14, 19, 24], "variat": 14, "variou": [14, 24], "vast": 15, "vector": [6, 12, 14, 15, 20, 24], "venv": 21, "veri": [12, 14, 15, 16, 18], "verifi": 21, "versatil": 24, "version": [2, 8, 9, 10, 12, 21], "via": [9, 10, 14, 21, 24], "viewpoint": 10, "vii_constraint1": 24, "vii_constraint2": 24, "vii_constraint3": 24, "vii_constraint4": 24, "vii_constraint5": 24, "vii_constraint6": 24, "vii_op1": 24, "violat": 10, "visibl": 10, "vision": 24, "visual": [12, 14, 19], "voltag": [12, 15, 17], "w": 24, "w_h": 24, "wa": [10, 12], "wai": [10, 22, 23, 24], "walk": 24, "want": [11, 13], "warm": [14, 18, 19, 20], "warranti": 22, "water": [12, 15, 16], "we": [10, 11, 12, 14, 16, 17, 21, 23, 24], "web": 2, "weight": [4, 6, 14, 19, 24], "welcom": [10, 11, 23], "well": [10, 12, 14, 18, 20, 24, 25], "were": 10, "what": [10, 12, 14, 18], "when": [10, 12, 14, 15, 16, 19, 21, 24, 25], "where": [2, 6, 11, 12, 14, 15, 16, 24], "whether": [2, 7, 22, 24], "which": [10, 12, 14, 15, 16, 17, 19, 23, 24, 25], "while": [12, 14, 15, 19, 20, 24], "white": 14, "whole": 14, "why": 10, "wide": 24, "wiki": 10, "win64": [12, 19], "wind": [12, 15, 24], "window": 21, "within": [6, 10, 12, 15, 16, 25], "without": [10, 14, 22], "wood_pellet_boil": 14, "wood_pellet_suppli": 14, "work": [2, 11, 12, 14, 16, 19, 21], "worker": 14, "workflow": [11, 18, 20], "would": [12, 15, 23, 24, 25], "write": 17, "written": [10, 12, 22], "www": 10, "x": [14, 24], "x64": 21, "xlsx": [12, 14, 20], "xlx": 2, "y": 24, "year": 23, "yellow": 15, "yield": 24, "you": [11, 12, 13, 14, 16, 20, 21, 23, 25], "your": [11, 12, 14, 21], "yourself": 18, "z_": 24, "z_h": 24, "zero": [2, 7, 12, 14], "zip": 14, "zone": 14, "zone_id": 14}, "titles": ["API Reference", "
pulpo
", "
pulpo.pulpo
", "
pulpo.utils.bw_parser
", "
pulpo.utils.converter
", "
pulpo.utils
", "
pulpo.utils.optimizer
", "
pulpo.utils.saver
", "
pulpo.utils.utils
", "Changelog", "Contributor Covenant Code of Conduct", "Contributing", "PULPO Electricity Showcase", "Example Collection", "Rice Example", "Choices", "Constraints", "Functional Unit", "Getting Started", "Setup and Objective", "Optimize and Interpret Results", "Installation", "License", "Support Brightway", "Theory", "Life Cycle Optimization (LCO) with
PULPO
"], "titleterms": {"0": 9, "01": 9, "05": 9, "1": [9, 10], "10": 9, "12": 9, "2": 10, "2023": 9, "2024": 9, "2025": 9, "3": [9, 10], "4": [9, 10], "5": 9, "A": 14, "activ": 12, "ad": 20, "an": 11, "api": 0, "attribut": 10, "b": 14, "ban": 10, "biospher": 14, "boiler": 14, "brightwai": 23, "bug": 11, "bw_parser": 3, "capabl": 25, "capac": 14, "case": 14, "cauldron": 23, "changelog": 9, "character": 14, "choic": [12, 14, 15], "class": 2, "code": [10, 11], "collect": 13, "conduct": 10, "constraint": [14, 16, 20], "construct": 24, "content": [2, 3, 4, 6, 7, 8], "contribut": [11, 23], "contributor": 10, "convert": 4, "correct": 10, "coven": 10, "cycl": 25, "de": 23, "document": 11, "d\u00e9part": 23, "electr": 12, "elementari": 12, "enforc": 10, "error": 11, "exampl": [11, 13, 14, 20, 24], "factor": 14, "fix": 11, "flow": 12, "formul": 14, "full": 24, "function": [2, 3, 4, 6, 7, 8, 12, 17], "get": 18, "guidelin": 10, "instal": 21, "instanc": 12, "instanti": [12, 20], "interact": 18, "interpret": 20, "iter": 20, "kei": 12, "lca": 24, "lco": 25, "licens": 22, "life": 25, "limit": 14, "linear": 24, "locat": 12, "matrix": [14, 24], "membership": 23, "modul": [2, 3, 4, 6, 7, 8], "more": 18, "multipl": 19, "name": 12, "nomenclatur": 24, "object": 19, "optim": [6, 20, 24, 25], "our": 10, "pass": 12, "pellet": 14, "perman": 10, "pledg": 10, "problem": 14, "program": 24, "project": 23, "pulpo": [1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16, 17, 21, 25], "q": 14, "rectangular": 24, "refer": 0, "reference_product": 12, "report": 11, "respons": 10, "result": [12, 20], "rice": 14, "save": 12, "saver": 7, "scope": 10, "sentier": 23, "setup": [12, 19], "showcas": 12, "simpl": [20, 24], "solv": [12, 20], "specif": [16, 17], "specifi": 12, "standard": 10, "start": 18, "submodul": [1, 5], "subpackag": 1, "summar": [12, 20], "summari": 14, "support": [23, 25], "technospher": [12, 14], "temporari": 10, "theori": 24, "u": 14, "unconstrain": 20, "unit": [12, 17], "updat": 21, "upper": 14, "usag": 20, "util": [3, 4, 5, 6, 7, 8], "visual": 20, "want": 18, "warn": 10, "wood": 14, "worker": 12, "you": 18, "yourself": 11}})
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/generic_database.py b/tests/generic_database.py
deleted file mode 100644
index 4b859e2..0000000
--- a/tests/generic_database.py
+++ /dev/null
@@ -1,489 +0,0 @@
-import copy
-import numpy as np
-np.NaN = np.nan
-import bw2data as bd
-
-# Helper function to convert integers to Latin letters
-def int_to_latin(num):
- """Converts an integer to a Latin letter (e.g., 1 -> 'A', 2 -> 'B')."""
- return chr(64 + num) # Converts 1 to 'A', 2 to 'B', etc.
-
-# Helper function to convert integers to Greek letters
-def int_to_greek(num):
- """Converts an integer to a Greek letter (e.g., 1 -> 'α', 2 -> 'β')."""
- greek_letters = ['α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ']
- return greek_letters[num - 1] if num <= len(greek_letters) else str(num)
-
-class Process:
- """Represents a production process for a specific product in a specific region."""
-
- def __init__(self, product_id, technology_id, region_id):
- """Initializes a process with product, technology, and region identifiers."""
- self.product_id = product_id
- self.technology_id = int_to_latin(technology_id)
- self.region_id = int_to_greek(region_id)
- self.process_id = f"{product_id}_{self.technology_id}_{self.region_id}"
- self.inputs = [] # List of tuples [(input_market_id, quantity), ...]
- self.environmental_flows = [] # List of tuples [(flow_id, quantity), ...]
-
- def add_input(self, input_market, quantity):
- """Adds an input market with a specified quantity to the process."""
- self.inputs.append((input_market.market_id, quantity))
-
- def add_environmental_flow(self, flow_id, quantity):
- """Adds an environmental flow with a specified quantity to the process."""
- self.environmental_flows.append((flow_id, quantity))
-
- def generate_inputs(self, potential_inputs, n_inputs):
- """Randomly generates and normalizes inputs for the process from potential markets."""
- if len(potential_inputs) < n_inputs:
- num_inputs = len(potential_inputs)
- else:
- num_inputs = np.random.randint(0, n_inputs + 1)
-
- if num_inputs > 0:
- selected_inputs = np.random.choice(potential_inputs, num_inputs, replace=False)
-
- # Generate random quantities for each selected input
- quantities = np.random.rand(num_inputs)
-
- # Normalize to ensure the sum is <= 1 (in order to have an M-matrix --- diagonal dominance)
- normalized_quantities = quantities / quantities.sum()
-
- # Scale down to ensure the sum is strictly smaller than 1
- scaling_factor = np.random.rand() # A random factor between 0 and 1
- normalized_quantities *= scaling_factor
-
- for inp, quantity in zip(selected_inputs, normalized_quantities):
- self.add_input(inp, quantity)
-
- def generate_environmental_flows(self, flow_ids, n_flows):
- """Randomly generates environmental flows for the process."""
- num_flows = np.random.randint(1, n_flows + 1)
- selected_flows = np.random.choice(flow_ids, num_flows, replace=False)
- for flow_id in selected_flows:
- quantity = np.random.rand()
- self.add_environmental_flow(str(flow_id), quantity)
-
- def __repr__(self):
- return (f"Process(product_id={self.product_id}, "
- f"technology_id={self.technology_id}, "
- f"region_id={self.region_id}, "
- f"inputs={self.inputs}, "
- f"environmental_flows={self.environmental_flows})")
-
-class Market:
- """Represents a market for a specific product in a specific region."""
-
- def __init__(self, product_id, region_id):
- """Initializes a market with product and region identifiers."""
- self.product_id = product_id
- self.region_id = int_to_greek(region_id)
- self.market_id = f"{product_id}_{self.region_id}"
- self.composition = [] # List of tuples [(process_id, share), ...]
-
- def add_process(self, process, share):
- """Adds a process with a specified share to the market composition."""
- self.composition.append((process.process_id, share))
-
- def generate_market_composition(self, candidate_processes):
- """Randomly generates a market composition from candidate processes."""
- included_processes = []
- for process in candidate_processes:
- if np.random.rand() < 0.75:
- share = np.random.rand()
- included_processes.append((process, share))
-
- # Ensure at least one process is included
- if not included_processes:
- process = np.random.choice(candidate_processes)
- share = np.random.rand()
- included_processes.append((process, share))
-
- for process, share in included_processes:
- self.add_process(process, share)
-
- # Normalize shares to sum to 1
- total_share = sum(share for _, share in self.composition)
- if total_share > 0:
- self.composition = [(pid, share / total_share) for pid, share in self.composition]
-
- def __repr__(self):
- return (f"Market(product_id={self.product_id}, "
- f"region_id={self.region_id}, "
- f"composition={self.composition})")
-
-def create_system(n_prod, n_proc, n_reg, n_inputs, n_flows, seed=None):
- """
- Creates the technosphere and biosphere components for the system.
-
- Args:
- n_prod (int): Number of products.
- n_proc (int): Maximum number of processes per product.
- n_reg (int): Number of regions.
- n_inputs (int): Maximum number of inputs per process.
- n_flows (int): Number of environmental flows.
- seed (int, optional): Seed for reproducibility.
-
- Returns:
- processes (list): List of Process instances.
- markets (list): List of Market instances.
- flow_ids (list): List of environmental flow IDs.
- """
- if seed is not None:
- np.random.seed(seed)
-
- processes = []
- markets = []
- flow_ids = [f"e{i}" for i in range(1, n_flows + 1)] # Environmental flow IDs: e1, e2, e3, ...
-
- # Step 1: Initialize Processes
- for product_id in range(1, n_prod + 1):
- regions = list(range(1, n_reg + 1))
- np.random.shuffle(regions)
- active_regions = regions[:np.random.randint(1, n_reg + 1)]
-
- for region_id in active_regions:
- technologies = list(range(1, n_proc + 1))
- np.random.shuffle(technologies)
- active_technologies = technologies[:np.random.randint(1, n_proc + 1)]
-
- for technology_id in active_technologies:
- proc = Process(product_id, technology_id, region_id)
- proc.generate_environmental_flows(flow_ids, n_flows)
- processes.append(proc)
-
- # Step 2: Generate Markets
- for product_id in range(1, n_prod + 1):
- regions = list(range(1, n_reg + 1))
- np.random.shuffle(regions)
-
- for region_id in regions:
- candidate_processes = [proc for proc in processes if proc.product_id == product_id and proc.region_id == int_to_greek(region_id)]
- if candidate_processes:
- market = Market(product_id, region_id)
- market.generate_market_composition(candidate_processes)
- markets.append(market)
-
- # Step 3: Assign Inputs to Processes
- for proc in processes:
- potential_inputs = [market for market in markets if market.region_id == proc.region_id]
- if potential_inputs:
- proc.generate_inputs(potential_inputs, n_inputs)
-
- return processes, markets, flow_ids
-
-def assemble_technosphere_matrix(processes, markets):
- """
- Assembles the technosphere matrix from processes and markets.
-
- Args:
- processes (list): List of Process instances.
- markets (list): List of Market instances.
-
- Returns:
- np.ndarray: Technosphere matrix.
- """
- n = len(processes) + len(markets)
- A = np.zeros((n, n))
-
- process_index = {proc.process_id: idx for idx, proc in enumerate(processes)}
- market_index = {market.market_id: idx + len(processes) for idx, market in enumerate(markets)}
-
- # Fill in the technosphere matrix
- for proc in processes:
- i = process_index[proc.process_id]
- A[i, i] = 1 # Diagonal element for the process
-
- for market_id, qty in proc.inputs:
- j = market_index[market_id]
- A[j, i] = -qty # Negative value for input
-
- for market in markets:
- i = market_index[market.market_id]
- A[i, i] = 1 # Diagonal element for the market
-
- for process_id, share in market.composition:
- j = process_index[process_id]
- A[j, i] = -share # Market composition values
-
- return A
-
-def assemble_biosphere_matrix(processes, flow_ids):
- """
- Assembles the biosphere matrix from processes and environmental flows.
-
- Args:
- processes (list): List of Process instances.
- flow_ids (list): List of environmental flow IDs.
-
- Returns:
- np.ndarray: Biosphere matrix.
- """
- n = len(processes) + len(flow_ids)
- B = np.zeros((len(flow_ids), len(processes)))
-
- process_index = {proc.process_id: idx for idx, proc in enumerate(processes)}
- flow_index = {flow_id: idx for idx, flow_id in enumerate(flow_ids)}
-
- # Fill in the biosphere matrix
- for proc in processes:
- j = process_index[proc.process_id]
- for flow_id, qty in proc.environmental_flows:
- i = flow_index[flow_id]
- B[i, j] = qty # Positive value for environmental flow
-
- return B
-
-class CharacterizationFactor:
- """Represents a characterization factor for an environmental flow under a specific method."""
-
- def __init__(self, method_id, flow_id, factor):
- """Initializes a characterization factor with a method, flow, and factor value."""
- self.method_id = method_id # ID of the method (e.g., m1, m2, etc.)
- self.flow_id = flow_id # ID of the environmental flow (e.g., e1, e2, etc.)
- self.factor = factor # Characterization factor value
-
- def __repr__(self):
- return (f"CharacterizationFactor(method_id={self.method_id}, "
- f"flow_id={self.flow_id}, "
- f"factor={self.factor})")
-
-def create_characterization_factors(n_methods, n_flows, seed=None):
- """
- Creates characterization factors for each method and environmental flow.
-
- Args:
- n_methods (int): Number of impact assessment methods.
- n_flows (int): Number of environmental flows.
- seed (int, optional): Seed for reproducibility.
-
- Returns:
- methods (list): List of method IDs.
- characterization_factors (list): List of CharacterizationFactor instances.
- """
- if seed is not None:
- np.random.seed(seed)
-
- methods = [f"m{i}" for i in range(1, n_methods + 1)] # Method IDs: m1, m2, m3, ...
- characterization_factors = []
-
- for method_id in methods:
- num_factors = np.random.randint(1, n_flows + 1) # Randomly determine the number of factors for this method
- selected_flows = np.random.choice([f"e{i}" for i in range(1, n_flows + 1)], num_factors, replace=False)
- for flow_id in selected_flows:
- factor = np.random.rand() # Generate a random factor value
- characterization_factors.append(CharacterizationFactor(method_id, flow_id, factor))
-
- return methods, characterization_factors
-
-def assemble_characterization_matrices(characterization_factors, flow_ids, methods):
- """
- Assembles characterization factor matrices for each method.
-
- Args:
- characterization_factors (list): List of CharacterizationFactor instances.
- flow_ids (list): List of environmental flow IDs.
- methods (list): List of method IDs.
-
- Returns:
- dict: Characterization matrices keyed by method ID.
- """
- n_methods = len(methods)
- n_flows = len(flow_ids)
- C_matrices = {method: np.zeros((n_flows, 1)) for method in methods} # Initialize matrices
-
- flow_index = {flow_id: idx for idx, flow_id in enumerate(flow_ids)}
-
- for cf in characterization_factors:
- method_id = cf.method_id
- flow_id = cf.flow_id
- factor = cf.factor
- i = flow_index[flow_id]
- C_matrices[method_id][i, 0] = factor
-
- return C_matrices
-
-def setup_biosphere_db(flow_ids):
- """Setup or update the biosphere database with environmental flows."""
-
- # Create biosphere database if it doesn't exist
- if 'biosphere3' not in bd.databases:
- biosphere_db = bd.Database('biosphere3')
- biosphere_data = {}
-
- # Define environmental flows
- for flow_id in flow_ids:
- biosphere_data[('biosphere3', flow_id)] = {
- 'name': f'Environmental flow {flow_id}',
- 'categories': ('environmental impact', ''),
- 'type': 'emission',
- 'unit': 'kg',
- }
-
- biosphere_db.write(biosphere_data)
- print('Biosphere database created')
- else:
- print('Biosphere database already exists')
-
-def setup_technosphere_db(database, processes, markets):
- """Setup the technosphere database with generated processes and markets."""
- if 'generated_technosphere_db' not in bd.databases:
- technosphere_db = bd.Database(database)
- technosphere_db.write({})
-
- # Register each process
- for proc in processes:
- act = technosphere_db.new_activity(proc.process_id)
- act['unit'] = 'unit' # Define the unit appropriately
- act['location'] = proc.region_id
- act['name'] = f'Process {proc.process_id}'
- act['reference product'] = f'Product {proc.product_id}'
- act.new_exchange(amount=1.0, input=act.key, type='production').save()
- act.save()
-
- # Register each market
- for market in markets:
- act = technosphere_db.new_activity(market.market_id)
- act['unit'] = 'unit' # Define the unit appropriately
- act['location'] = market.region_id
- act['name'] = f'Market {market.market_id}'
- act['reference product'] = f'Product {market.product_id}'
- act.new_exchange(amount=1.0, input=act.key, type='production').save()
- act.save()
-
- print('Technosphere database created')
- else:
- print('Technosphere database already exists')
-
-def add_exchanges_to_db(database, processes, markets):
- """Add exchanges to the technosphere and market activities in the database."""
- technosphere_db = bd.Database(database)
- biosphere_db = bd.Database('biosphere3')
-
- # Add exchanges for processes
- for proc in processes:
- act = technosphere_db.get(proc.process_id)
-
- # Add market inputs
- for market_id, qty in proc.inputs:
- market_act = technosphere_db.get(market_id)
- act.new_exchange(amount=qty, input=market_act.key, type='technosphere').save()
-
- # Add environmental flows (biosphere exchanges)
- for flow_id, qty in proc.environmental_flows:
- flow_act = biosphere_db.get(flow_id)
- act.new_exchange(amount=qty, input=flow_act.key, type='biosphere').save()
-
- act.save()
-
- # Add exchanges for markets
- for market in markets:
- act = technosphere_db.get(market.market_id)
-
- # Add process contributions to the market
- for process_id, share in market.composition:
- process_act = technosphere_db.get(process_id)
- act.new_exchange(amount=share, input=process_act.key, type='technosphere').save()
-
- act.save()
-
- print('Exchanges added to the technosphere and market activities in the database')
-
-def setup_lcia_methods(characterization_factors, methods):
- """Setup LCIA methods based on generated characterization factors."""
- # Deregister existing methods
- methods_copy = copy.deepcopy(bd.methods)
- for method in methods_copy:
- bd.Method(method).deregister()
-
- # Register new LCIA methods
- for method_id in methods:
- method = bd.Method(('generated_system_example', method_id))
- method.register()
-
- cfs = []
- for cf in characterization_factors:
- if cf.method_id == method_id:
- flow_key = ('biosphere3', cf.flow_id)
- cfs.append((flow_key, cf.factor))
-
- method.write(cfs)
-
- print('LCIA methods and CFs defined')
-
-def setup_generated_system(project, database, processes, markets, flow_ids, characterization_factors, methods):
- """Main function to set up the entire Brightway2 database."""
- bd.projects.set_current(project)
- setup_biosphere_db(flow_ids)
- setup_technosphere_db(database, processes, markets)
- add_exchanges_to_db(database, processes, markets)
- setup_lcia_methods(characterization_factors, methods)
-
-
-def setup_generic_db(project, database, n_prod, n_proc, n_reg, n_inputs, n_flows, n_methods, seed=None,
- return_data=False):
- """
- Sets up a generic LCI database in Brightway2 with specified parameters.
-
- Args:
- project (str): Name of the Brightway2 project to create or use.
- database (str): Name of the Brightway2 database to create or use.
- n_prod (int): Number of products to generate.
- n_proc (int): Maximum number of processes per product.
- n_reg (int): Number of regions where processes can be active.
- n_inputs (int): Maximum number of inputs per process.
- n_flows (int): Number of environmental flows to generate.
- n_methods (int): Number of impact assessment methods to create.
- seed (int, optional): Seed for reproducibility of random data generation.
- return_data (bool): If True, returns the generated matrices (technosphere, biosphere, and
- characterization).
-
- Returns:
- tuple: If `return_data` is True, returns a tuple containing:
- - technosphere_matrix (np.ndarray): The technosphere matrix.
- - biosphere_matrix (np.ndarray): The biosphere matrix.
- - characterization_matrices (dict): A dictionary of characterization factor matrices.
- """
-
- # Set the project, deleting existing databases if the project exists
- if project in bd.projects:
- bd.projects.set_current(project)
- print(f"Project '{project}' already exists. Deleting existing databases.")
- if database in bd.databases:
- del bd.databases[database]
- if 'biosphere3' in bd.databases:
- del bd.databases['biosphere3']
- else:
- bd.projects.set_current(project)
- print(f"Project '{project}' does not exist. Creating new project.")
-
- print("Proceeding with creating both technosphere and biosphere databases.")
-
- # Step 1: Create the technosphere and biosphere components
- processes, markets, flow_ids = create_system(n_prod, n_proc, n_reg, n_inputs, n_flows, seed=seed)
-
- # Step 2: Assemble the technosphere matrix
- technosphere_matrix = assemble_technosphere_matrix(processes, markets)
-
- # Step 3: Assemble the biosphere matrix
- biosphere_matrix = assemble_biosphere_matrix(processes, flow_ids)
-
- # Step 4: Create the characterization factors for impact assessment methods
- methods, characterization_factors = create_characterization_factors(n_methods, n_flows, seed=seed)
-
- # Step 5: Assemble the characterization factor matrices
- characterization_matrices = assemble_characterization_matrices(characterization_factors, flow_ids, methods)
-
- # Set up the Brightway2 database using the generated data
- setup_generated_system(project, database, processes, markets, flow_ids, characterization_factors, methods)
-
- if return_data:
- return technosphere_matrix, biosphere_matrix, characterization_matrices
-
-
-def main():
- setup_generic_db(project="generic_db_project", database="generic_db", n_prod=5, n_proc=3, n_reg=3, n_inputs=4, n_flows=4, n_methods=2, seed=None, return_data=False)
-
-if __name__ == '__main__':
- main()
diff --git a/tests/rice_database.py b/tests/rice_database.py
deleted file mode 100644
index 8d7d07f..0000000
--- a/tests/rice_database.py
+++ /dev/null
@@ -1,183 +0,0 @@
-import copy
-import numpy as np
-import bw2data as bd
-
-np.NaN = np.nan # Ensures compatibility with the latest NumPy versions
-
-def setup_rice_husk_db():
- # Set the current project to "rice_husk_example"
- bd.projects.set_current("rice_husk_example")
-
- # Biosphere keys
- co2_key = ('biosphere3', 'CO2')
- ch4_key = ('biosphere3', 'CH4')
- ef_key = ('biosphere3', 'EF')
-
- # Define biosphere flows and create the 'biosphere3' database if it doesn't exist
- if 'biosphere3' not in bd.databases:
- biosphere_db = bd.Database('biosphere3')
- biosphere_data = {
- ('biosphere3', 'CO2'): {
- 'name': 'Carbon dioxide, fossil',
- 'categories': ('climate change', 'GWP 100a'),
- 'type': 'emission',
- 'unit': 'Mt',
- },
- ('biosphere3', 'CH4'): {
- 'name': 'Methane, agricultural',
- 'categories': ('climate change', 'GWP 100a'),
- 'type': 'emission',
- 'unit': 'Mt',
- },
- ('biosphere3', 'EF'): {
- 'name': 'Economic Flow',
- 'categories': ('economic flow', 'dollar'),
- 'type': 'emission',
- 'unit': 'million dollar',
- },
- }
- biosphere_db.write(biosphere_data)
-
- print('Elementary flow database created')
-
- # Technosphere keys
- rice_factory_key = ('rice_husk_example_db', 'Rice factory')
- rice_farming_key = ('rice_husk_example_db', 'Rice farming')
- rice_husk_boiler_key = ('rice_husk_example_db', 'Rice husk boiler')
- natural_gas_boiler_key = ('rice_husk_example_db', 'Natural gas boiler')
- wood_pellet_boiler_key = ('rice_husk_example_db', 'Wood pellet boiler')
- rice_husk_market_key = ('rice_husk_example_db', 'Rice husk market')
- rice_husk_collection1_key = ('rice_husk_example_db', 'Rice husk collection 1')
- rice_husk_collection2_key = ('rice_husk_example_db', 'Rice husk collection 2')
- rice_husk_collection3_key = ('rice_husk_example_db', 'Rice husk collection 3')
- rice_husk_collection4_key = ('rice_husk_example_db', 'Rice husk collection 4')
- rice_husk_collection5_key = ('rice_husk_example_db', 'Rice husk collection 5')
- natural_gas_supply_key = ('rice_husk_example_db', 'Natural gas supply')
- wood_pellet_supply_key = ('rice_husk_example_db', 'Wood pellet supply')
- burning_rice_husk_key = ('rice_husk_example_db', 'Burning of rice husk')
- power_plant_key = ('rice_husk_example_db', 'Power plant')
- transportation_key = ('rice_husk_example_db', 'Transportation by truck')
-
- # Create the "rice_husk_example_db" database if it doesn't exist
- if 'rice_husk_example_db' not in bd.databases:
- rice_husk_db = bd.Database('rice_husk_example_db')
- rice_husk_db.write({})
-
- process_data = [
- ('Rice factory', 'Mt', 'GLO', 'Processed rice (in Mt)'),
- ('Rice farming', 'Mt', 'GLO', 'Unprocessed rice (in Mt)'),
- ('Rice husk boiler', 'TWh', 'GLO', 'Thermal energy from husk boiler (in TWh)'),
- ('Natural gas boiler', 'TWh', 'GLO', 'Thermal energy from natural gas boiler (in TWh)'),
- ('Wood pellet boiler', 'TWh', 'GLO', 'Thermal energy from wood pellet boiler (in TWh)'),
- ('Rice husk market', 'Mt', 'GLO', 'Rice husk at farm (Mt)'),
- ('Rice husk collection 1', 'Mt', 'GLO', 'Rice husk from region 1 (in Mt)'),
- ('Rice husk collection 2', 'Mt', 'GLO', 'Rice husk from region 2 (in Mt)'),
- ('Rice husk collection 3', 'Mt', 'GLO', 'Rice husk from region 3 (in Mt)'),
- ('Rice husk collection 4', 'Mt', 'GLO', 'Rice husk from region 4 (in Mt)'),
- ('Rice husk collection 5', 'Mt', 'GLO', 'Rice husk from region 5 (in Mt)'),
- ('Natural gas supply', 'TWh', 'GLO', 'Natural gas (in TWh)'),
- ('Wood pellet supply', 'Mt', 'GLO', 'Wood pellets (in Mt)'),
- ('Burning of rice husk', 'Mt', 'GLO', 'Burned rice husk (in Mt)'),
- ('Power plant', 'TWh', 'GLO', 'Electricity (in TWh)'),
- ('Transportation by truck', 'Gt*km', 'GLO', 'Transportation (in Gt*km)'),
- ]
-
- # Register each process
- for name, unit, location, ref_product in process_data:
- act = rice_husk_db.new_activity(name)
- act['unit'] = unit
- act['location'] = location
- act['name'] = name
- act['reference product'] = ref_product
- act.new_exchange(amount=1.0, input=act.key, type='production').save()
- act.save()
-
- # Define the technosphere exchanges
- exchange_data = [
- # Format: [input_key, target_key, amount, exchange_type]
- [rice_farming_key, rice_factory_key, 1.15, 'technosphere'],
- [natural_gas_boiler_key, rice_factory_key, 2.2, 'technosphere'],
- [power_plant_key, rice_factory_key, 0.08, 'technosphere'],
- [transportation_key, rice_factory_key, 0.35, 'technosphere'],
- [rice_husk_market_key, rice_farming_key, -0.6, 'technosphere'],
- [rice_husk_collection1_key, rice_husk_boiler_key, 0.23, 'technosphere'],
- [natural_gas_supply_key, natural_gas_boiler_key, 1.1, 'technosphere'],
- [wood_pellet_supply_key, wood_pellet_boiler_key, 0.25, 'technosphere'],
- [rice_husk_market_key, rice_husk_collection1_key, 1, 'technosphere'],
- [rice_husk_market_key, rice_husk_collection2_key, 1, 'technosphere'],
- [rice_husk_market_key, rice_husk_collection3_key, 1, 'technosphere'],
- [rice_husk_market_key, rice_husk_collection4_key, 1, 'technosphere'],
- [rice_husk_market_key, rice_husk_collection5_key, 1, 'technosphere'],
- [transportation_key, rice_husk_collection1_key, 0.12, 'technosphere'],
- [transportation_key, rice_husk_collection2_key, 0.24, 'technosphere'],
- [transportation_key, rice_husk_collection3_key, 0.36, 'technosphere'],
- [transportation_key, rice_husk_collection4_key, 0.48, 'technosphere'],
- [transportation_key, rice_husk_collection5_key, 0.60, 'technosphere'],
- [rice_husk_market_key, burning_rice_husk_key, 2, 'technosphere'],
- [burning_rice_husk_key, rice_husk_market_key, 1, 'technosphere'],
- [co2_key, rice_farming_key, 6.14e-1, 'biosphere'],
- [ch4_key, rice_farming_key, 1.33e-3, 'biosphere'],
- [co2_key, natural_gas_boiler_key, 2.27e-1, 'biosphere'],
- [ch4_key, natural_gas_boiler_key, 1.47e-3, 'biosphere'],
- [co2_key, natural_gas_supply_key, 3.21e-2, 'biosphere'],
- [ch4_key, natural_gas_supply_key, 1.50e-3, 'biosphere'],
- [co2_key, wood_pellet_supply_key, 1.50e-1, 'biosphere'],
- [ch4_key, wood_pellet_supply_key, 2.56e-4, 'biosphere'],
- [co2_key, power_plant_key, 1.10e-0, 'biosphere'],
- [ch4_key, power_plant_key, 9.15e-4, 'biosphere'],
- [co2_key, transportation_key, 5.76e-2, 'biosphere'],
- [ch4_key, transportation_key, 6.97e-5, 'biosphere'],
- [ef_key, rice_factory_key, 5.00e1, 'biosphere'],
- [ef_key, rice_farming_key, 3.60e2, 'biosphere'],
- [ef_key, natural_gas_supply_key, 1.3e1, 'biosphere'],
- [ef_key, wood_pellet_supply_key, 7.20e1, 'biosphere'],
- [ef_key, rice_husk_collection1_key, 4.50e1, 'biosphere'],
- [ef_key, rice_husk_collection2_key, 3.60e1, 'biosphere'],
- [ef_key, rice_husk_collection3_key, 2.90e1, 'biosphere'],
- [ef_key, rice_husk_collection4_key, 2.30e1, 'biosphere'],
- [ef_key, rice_husk_collection5_key, 1.80e1, 'biosphere'],
- [ef_key, power_plant_key, 6.50e1, 'biosphere'],
- [ef_key, transportation_key, 1.70e2, 'biosphere'],
- ]
-
- # Add the exchanges to the activities
- for input_key, target_key, amount, exchange_type in exchange_data:
- act = [act for act in rice_husk_db if act.key == target_key][0]
- act.new_exchange(amount=amount, input=input_key, type=exchange_type).save()
- act.save()
-
- print('Process database created')
-
- # Loop through the list of methods and deregister each one
- # Create a copy of the methods list
- methods_copy = copy.deepcopy(bd.methods)
- # Loop through the copy of methods and deregister each one
- for method in methods_copy:
- bd.Method(method).deregister()
-
- # Define LCIA methods and CFs
- methods_data = [
- ('climate change', 'Mt CO2eq', 2, 'cc', 'climate change CFs', 'climate_change', 'CO2',
- [(co2_key, 1), (ch4_key, 25)]),
- ('air quality', 'ppm', 1, 'aq', 'air quality CFs', 'air_quality', 'PM', [(ch4_key, 25)]),
- ('economic flow', 'million dollar', 1, 'ef', 'economic flow CFs', 'economic_flow', 'million dollar', [(ef_key, 1)]),
- ]
-
- for method_name, unit, num_cfs, abbreviation, description, filename, flow_code, flow_list in methods_data:
- method = bd.Method(('my project', method_name))
- method.register(**{
- 'unit': unit,
- 'num_cfs': num_cfs,
- 'abbreviation': abbreviation,
- 'description': description,
- 'filename': filename,
- })
- method.write(flow_list)
-
- print('LCIA methods and CFs defined')
-
-def main():
- setup_rice_husk_db()
-
-if __name__ == '__main__':
- main()
diff --git a/tests/sample_database.py b/tests/sample_database.py
deleted file mode 100644
index 31e544c..0000000
--- a/tests/sample_database.py
+++ /dev/null
@@ -1,155 +0,0 @@
-import bw2data as bd
-import bw2calc as bc
-import copy
-from pulpo.utils.utils import is_bw25
-
-def setup_test_db():
- # Set the current project to "sample_project"
- bd.projects.set_current("sample_project_bw25" if is_bw25() else "sample_project")
-
- # Keys
- # Biosphere
- co2_key = ('biosphere', 'CO2')
- ch4_key = ('biosphere', 'CH4')
- pm_key = ('biosphere', 'PM')
- h2o_irrigation_key = ('biosphere', 'H2O_irrigation')
- # Technosphere
- wind_turbine_key = ('technosphere', 'wind turbine')
- steam_cycle_key = ('technosphere', 'steam cycle')
- lignite_extraction_key = ('technosphere', 'lignite extraction')
- oil_extraction_key = ('technosphere', 'oil extraction')
- e_car_key = ('technosphere', 'e-Car')
-
- # Define biosphere flows and create the "biosphere" database if it doesn't exist
- if "biosphere" not in bd.databases:
- biosphere_db = bd.Database("biosphere")
- biosphere_data = {
- ("biosphere", "CO2"): {
- "name": "Carbon dioxide, fossil",
- "categories": ("climate change", "GWP 100a"),
- "type": "emission",
- "unit": "kg",
- },
- ("biosphere", "CH4"): {
- "name": "Methane, agricultural",
- "categories": ("climate change", "GWP 100a"),
- "type": "emission",
- "unit": "kg",
- },
- ("biosphere", "PM"): {
- "name": "Particulate matter, industrial",
- "categories": ("air quality", "particulate matter"),
- "type": "emission",
- "unit": "g",
- },
- ("biosphere", "H2O_irrigation"): {
- "name": "Water, irrigation",
- "categories": ("water use", "irrigation"),
- "type": "resource",
- "unit": "m3",
- },
- }
- biosphere_db.write(biosphere_data)
-
- # Create the "technosphere" database if it doesn't exist
- if "technosphere" not in bd.databases:
- technosphere_db = bd.Database("technosphere")
- technosphere_db.write({})
- process_data = [
- ("oil extraction", "kg", "GLO", "oil"),
- ("lignite extraction", "kg", "GLO", "lignite"),
- ("steam cycle", "kWh", "GLO", "electricity"),
- ("wind turbine", "kWh", "GLO", "electricity"),
- ("e-Car", "tkm", "GLO", "transport"),
- ]
-
- for name, unit, location, ref_product in process_data:
- act = technosphere_db.new_activity(name)
- act["unit"] = unit
- act["location"] = location
- act["name"] = name
- act["reference product"] = ref_product
- act.new_exchange(amount=1.0, input=act.key, type="production").save()
- act.save()
-
- exchange_data = [
- [e_car_key, oil_extraction_key, 0.03, 'technosphere'],
- [e_car_key, lignite_extraction_key, 0.03, 'technosphere'],
- [oil_extraction_key, steam_cycle_key, 0.5, 'technosphere'],
- [lignite_extraction_key, steam_cycle_key, 0.5, 'technosphere'],
- [steam_cycle_key, e_car_key, 0.5, 'technosphere'],
- [wind_turbine_key, e_car_key, 0.5, 'technosphere'],
- [e_car_key, wind_turbine_key, 0.03, 'technosphere'],
- [co2_key, oil_extraction_key, 0.2, 'biosphere'],
- [co2_key, lignite_extraction_key, 0.3, 'biosphere'],
- [co2_key, steam_cycle_key, 1, 'biosphere'],
- [co2_key, wind_turbine_key, 0.1, 'biosphere'],
- [ch4_key, oil_extraction_key, 0.01, 'biosphere'],
- [ch4_key, lignite_extraction_key, 0.02, 'biosphere'],
- [pm_key, steam_cycle_key, 2.0, 'biosphere'],
- [pm_key, wind_turbine_key, 1.5, 'biosphere'],
- [h2o_irrigation_key, steam_cycle_key, 2.0, 'biosphere'],
- [h2o_irrigation_key, wind_turbine_key, 5.0, 'biosphere'],
- [pm_key, e_car_key, 0.1, 'biosphere'],
- [h2o_irrigation_key, e_car_key, 0.1, 'biosphere'],
- ]
-
- for input, target, amount, type in exchange_data:
- act = [act for act in technosphere_db if act.key==target][0]
- act.new_exchange(amount=amount, input=input, type=type).save()
- act.save()
-
- # @TODO: Add another "foreground" database, to test the import of two dbs.
-
- # Loop through the list of methods and deregister each one
- # Create a copy of the methods list
- methods_copy = copy.deepcopy(bd.methods)
- # Loop through the copy of methods and deregister each one
- for method in methods_copy:
- bd.Method(method).deregister()
-
- # Define LCIA methods and CFs
- methods_data = [
- ("climate change", "kg CO2eq", 2, "cc", "climate change CFs", "climate_change", "CO2", [(co2_key, 1), (ch4_key, 29.7)]),
- ("air quality", "ppm", 1, "aq", "air quality CFs", "air_quality", "PM", [(ch4_key, 29.7)]),
- ("resources", "m3", 1, "rc", "resource CFs", "resources", "H2O_irrigation", [(h2o_irrigation_key,1)]),
- ]
-
- for method_name, unit, num_cfs, abbreviation, description, filename, flow_code, flow_list in methods_data:
- method = bd.Method(("my project", method_name))
- method.register(**{
- "unit": unit,
- "num_cfs": num_cfs,
- "abbreviation": abbreviation,
- "description": description,
- "filename": filename,
- })
- method.write(flow_list)
-
-def sample_lcia():
- bd.projects.set_current("sample_project_bw25" if is_bw25() else "sample_project")
- technosphere_db = bd.Database("technosphere")
-
- if is_bw25():
- functional_units = {"act": {act.id: 1 for act in technosphere_db}}
- config = {"impact_categories": list(bd.methods)}
- data_objs = bd.get_multilca_data_objs(functional_units=functional_units, method_config=config)
- myMultiLCA = bc.MultiLCA(demands=functional_units, method_config=config, data_objs=data_objs)
- myMultiLCA.lci()
- myMultiLCA.lcia()
- results = [round(myMultiLCA.scores[x], 5) for x in myMultiLCA.scores]
- else:
- act = {act.key: 1 for act in technosphere_db}
- bd.calculation_setups['multiLCA'] = {'inv': [act], 'ia': list(bd.methods)}
- myMultiLCA = bc.MultiLCA('multiLCA')
- results = [round(x, 5) for x in myMultiLCA.results[0]]
- return results
-
-def main():
- setup_test_db()
- print(sample_lcia())
-
-if __name__ == "__main__":
- main()
-
-
diff --git a/tests/test_functions.py b/tests/test_functions.py
deleted file mode 100644
index d5c2049..0000000
--- a/tests/test_functions.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import pulpo as pulpo
-import unittest
-from tests.sample_database import sample_lcia, setup_test_db
-from pulpo.utils.bw_parser import import_data, retrieve_methods, retrieve_env_interventions, retrieve_processes
-from pulpo import pulpo
-
-setup_test_db()
-
-class TestParser(unittest.TestCase):
- def test_database_import(self):
- result = sample_lcia()
- self.assertEqual(result, [4.22308, 1.5937, 11.1567]) # Example assertion
-
- def test_import_data(self):
- # Test if the import works and has the expected structure
- methods = {
- "('my project', 'climate change')": 1,
- "('my project', 'air quality')": 1,
- "('my project', 'resources')": 1,
- }
-
- result = import_data('sample_project', 'technosphere', methods, 'biosphere')
-
- self.assertEqual([idx for idx in result], ['matrices', 'intervention_matrix', 'technology_matrix', 'process_map', 'intervention_map'])
- self.assertEqual(result['technology_matrix'].shape, (5, 5))
- self.assertEqual(result['intervention_matrix'].shape, (4, 5))
- self.assertEqual(result['process_map'], {('technosphere', 'oil extraction'): 0, ('technosphere', 'lignite extraction'): 1, ('technosphere', 'steam cycle'): 2, ('technosphere', 'wind turbine'): 3, ('technosphere', 'e-Car'): 4, 2: 'steam cycle | electricity | GLO', 1: 'lignite extraction | lignite | GLO', 0: 'oil extraction | oil | GLO', 3: 'wind turbine | electricity | GLO', 4: 'e-Car | transport | GLO'})
-
- # Test invalid database
- with self.assertRaises(ValueError) as context:
- import_data('sample_project', 'nothing', methods, 'biosphere')
- self.assertIn("Database 'nothing' does not exist", str(context.exception))
-
- # Test invalid project
- with self.assertRaises(ValueError) as context:
- import_data('nonexistent_project', 'technosphere', methods, 'biosphere')
- self.assertIn("Project 'nonexistent_project' does not exist", str(context.exception))
-
- # Test invalid method
- invalid_methods = {
- "('my project', 'nonexistent method')": 1,
- "('my project', 'air quality')": 1,
- }
- with self.assertRaises(ValueError) as context:
- import_data('sample_project', 'technosphere', invalid_methods, 'biosphere')
- self.assertIn("The following methods do not exist", str(context.exception))
-
- def test_retrieve_activities(self):
- key = retrieve_processes('sample_project', 'technosphere', keys=["('technosphere', 'wind turbine')"])
- name = retrieve_processes('sample_project', 'technosphere', activities=['e-Car'])
- location = retrieve_processes('sample_project', 'technosphere', locations=['GLO'])
- self.assertEqual(key[0]['name'], "wind turbine")
- self.assertEqual(name[0]['name'], "e-Car")
- self.assertEqual(len(location), 5)
-
- def test_retrieve_methods(self):
- single_result = retrieve_methods('sample_project', ['climate'])
- multi_result = retrieve_methods('sample_project', ['project'])
- self.assertEqual(single_result, [('my project', 'climate change')])
- self.assertEqual(multi_result, [('my project', 'climate change'), ('my project', 'air quality'), ('my project', 'resources')])
-
- def test_retrieve_envflows(self):
- result = retrieve_env_interventions('sample_project', intervention_matrix='biosphere', keys="('biosphere', 'PM')")
- self.assertEqual(result[0]['name'], 'Particulate matter, industrial')
-
-class TestPULPO(unittest.TestCase):
-
- def test_pulpo(self):
- project = 'sample_project'
- database = 'technosphere'
- methods = {"('my project', 'climate change')": 1,
- "('my project', 'air quality')": 1,
- "('my project', 'resources')": 0}
- # Test basic PULPO:
- worker = pulpo.PulpoOptimizer(project, database, methods, '')
- worker.intervention_matrix = 'biosphere'
- worker.get_lci_data()
- eCar = worker.retrieve_activities(reference_products='transport')
- demand = {eCar[0]: 1}
- elec = worker.retrieve_activities(reference_products='electricity')
- choices = {'electricity': {elec[0]: 100, elec[1]: 100}}
- worker.instantiate(choices=choices, demand=demand)
- worker.solve()
- result_obj = round(worker.instance.OBJ(), 6)
- result_aux = round(worker.instance.impacts_calculated["('my project', 'resources')"].value, 5)
- self.assertEqual(result_obj, 0.103093)
- self.assertEqual(result_aux, 5.25773)
- # Test supply specification:
- upper_limit = {eCar[0]: 1}
- lower_limit = {eCar[0]: 1}
- worker.instantiate(choices=choices, upper_limit=upper_limit, lower_limit=lower_limit)
- worker.solve()
- result_obj = round(worker.instance.OBJ(), 6)
- result_aux = round(worker.instance.impacts_calculated["('my project', 'resources')"].value, 5)
- self.assertEqual(result_obj, 0.1)
- self.assertEqual(result_aux, 5.1)
- # Test elementary / intervention flow constraint:
- water = worker.retrieve_envflows(activities="Water, irrigation")
- upper_elem_limit = {water[0]: 5.2}
- worker.instantiate(choices=choices, demand=demand, upper_elem_limit=upper_elem_limit)
- worker.solve()
- result_obj = round(worker.instance.OBJ(), 6)
- result_aux = round(worker.instance.impacts_calculated["('my project', 'resources')"].value, 5)
- self.assertEqual(result_obj, 0.14237)
- self.assertEqual(result_aux, 5.2)
-
-
-
-