Contributed by Pascal Lesage, who is exploring Brightway2
This Notebook was not produced by Chris Mutel, and probably presents some techniques that could have been done more efficiently. Any comments/suggestions are absolutely welcome and should be sent to Pascal.
This notebook explores how to conduct comparative static (or deterministic) LCA, i.e. LCA that ignores uncertainty.
Precisely, the objectives are to:
To get started, some initiating stuff, which is described in Brightway2's official Introduction notebook:
The first steps are probably common to all projects starting from scratch:
import brightway2 as bw #I like importing "as BW" to better keep track of Brightway's methods and functions
bw.projects.current = "Comparative static LCA" #Creating the project
bw.bw2setup() #Importing elementary flows, LCIA methods and some other data
Biosphere database already present!!! No setup is needed
Warning: bad escape \s
The following is specific to importing the FORWAST database, as explained in both the "Getting started" and the specific "Importing FORWAST" Notebooks found on Brightway2's site
import zipfile
import os
from bw2data.utils import download_file
if "forwast" not in bw.databases:
filepath = download_file("forwast.bw2package.zip", url="http://lca-net.com/wp-content/uploads/")
dirpath = os.path.dirname(filepath)
zipfile.ZipFile(filepath).extractall(dirpath)
bw.BW2Package.import_file(os.path.join(dirpath, "forwast.bw2package"))
Let's pull in our databases so we can use them, and print their types, just to remember what these actually are.
bioDB = bw.Database("biosphere3")
forwastDB = bw.Database("forwast")
print("The forwast DB type is ", type(forwastDB), "\nThe biosphere DB type is ", type(bioDB), "\njust so you know." )
The forwast DB type is <class 'bw2data.backends.peewee.database.SQLiteBackend'> The biosphere DB type is <class 'bw2data.backends.peewee.database.SQLiteBackend'> just so you know.
For my problem, I want to compare Danish and European milks.
I'll make my FORWAST database searchable, and then search for "dairy".
forwastDB.make_searchable()
dairy = forwastDB.search("dairy")
dairy
This database is already searchable
Warning: DisplayFormatter._ipython_display_formatter_default is deprecated: use @default decorator instead. Warning: DisplayFormatter._formatters_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._deferred_printers_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._singleton_printers_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._type_printers_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._singleton_printers_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._type_printers_default is deprecated: use @default decorator instead. Warning: PlainTextFormatter._deferred_printers_default is deprecated: use @default decorator instead.
['_20 Dairy products, DK' (kilogram, GLO, ['Input Output', 'Denmark 2003']), '_20 Dairy products, EU27' (kilogram, GLO, ['Input Output', 'EU27 2003'])]
I have found my two products. Let me create a variable for each, and then store them together in a list:
DKmilk = dairy[0]
EUmilk = dairy[1]
print("I will compare\n{} and\n{}".format(DKmilk, EUmilk))
myMilks = [DKmilk, EUmilk]
I will compare '_20 Dairy products, DK' (kilogram, GLO, ['Input Output', 'Denmark 2003']) and '_20 Dairy products, EU27' (kilogram, GLO, ['Input Output', 'EU27 2003'])
Of course, in this case, myMilks
is exactly the same as dairy
(my search result), but this is a fluke. For example, there could have been more dairy in the database.
There are many methods that were imported during bw.bwsetup(). How many? Let's find out.
len(bw.methods)
665
I just want methods that contain "ReCiPe" and (H, A) in the first element of the tuple, and "total" in the third.
Let's also exclude "single scores" (i.e. methods where "total" is the second element in the tuple) and the "without longterm" methods.
So let's create my list of methods:
myMethods = [method for method in bw.methods
if "ReCiPe" in method[0]
and "(H,A)" in method[0]
and "w/o" not in method[0]
and "total" not in method[1]
and "total" in method[2]]
myMethods
[('ReCiPe Endpoint (H,A)', 'ecosystem quality', 'total'), ('ReCiPe Endpoint (H,A)', 'human health', 'total'), ('ReCiPe Endpoint (H,A)', 'resources', 'total')]
The table I want should have one column per scenario (in this case, Danish and European milk) and one row per impact category (in this case, the three ReCiPe Endpoint (H,A) methods found in myMethods
.
# Note: Requires bw2calc version >= 1.2.1 (Released 2016-03-14) - run bw2update.bat on Windows!
results = []
for milk in myMilks:
# Building the LCA objet is relaively expensive so it is better to reuse it
lca = bw.LCA({milk:1})
lca.lci()
for method in myMethods:
lca.switch_method(method)
lca.lcia()
results.append((milk["name"].replace("_20", "").strip(), method[1].title(), lca.score))
results
[('Dairy products, DK', 'Ecosystem Quality', 0.4613055084918115), ('Dairy products, DK', 'Human Health', 0.9275230140902033), ('Dairy products, DK', 'Resources', 0.430265702086426), ('Dairy products, EU27', 'Ecosystem Quality', 0.25562829018917177), ('Dairy products, EU27', 'Human Health', 0.4607963671165396), ('Dairy products, EU27', 'Resources', 0.23386690905283167)]
import pandas as pd
results_df = pd.DataFrame(results, columns=["Name", "Method", "Score"])
results_df = pd.pivot_table(results_df, index = "Name", columns = "Method", values = "Score")
results_df
Method | Ecosystem Quality | Human Health | Resources |
---|---|---|---|
Name | |||
Dairy products, DK | 0.461306 | 0.927523 | 0.430266 |
Dairy products, EU27 | 0.255628 | 0.460796 | 0.233867 |
Let's normalise the results.
NormResults_df = results_df / results_df.max()
NormResults_df
Method | Ecosystem Quality | Human Health | Resources |
---|---|---|---|
Name | |||
Dairy products, DK | 1.000000 | 1.000000 | 1.000000 |
Dairy products, EU27 | 0.554141 | 0.496803 | 0.543541 |
What would follow would be:
Anyone willing to add these is welcome, I'm moving on to uncertainty analyses, where the real action is!