Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v1.1.4 #128

Merged
merged 25 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2f964e5
add back develop tags
bl-young May 13, 2024
a803d19
add zenodo data #113
bl-young May 14, 2024
447d9b5
use `.to_ref()` to avoid unnecessary data for flows within ImpactFact…
bl-young May 14, 2024
6cfbac3
Merge pull request #117 from USEPA/issue_114
bl-young Jun 5, 2024
8fec31f
Merge pull request #116 from USEPA/zenodo
bl-young Jun 5, 2024
21cee65
add initial draft CED method
bl-young Jul 15, 2024
33e8aa8
:heavy_check_mark: implement test to check method urls
bl-young Nov 6, 2024
a2bff15
update recipe url resolves #121
bl-young Nov 6, 2024
6bb2ad3
Merge pull request #122 from USEPA/url_testing
bl-young Nov 11, 2024
18a179f
update ced method and add metadata
bl-young Nov 13, 2024
7dad16e
fix typo in `Ecosystem damage` #124; add missing space for endopint `…
bl-young Nov 18, 2024
7cdc854
Merge pull request #125 from USEPA/issue_124
bl-young Dec 3, 2024
1dfb65c
fix FutureWarning of mismatched dtypes
bl-young Dec 4, 2024
ce98823
only add mapping description for methods that require mapping
bl-young Dec 4, 2024
b0c1a41
update urls to be more specific
bl-young Dec 4, 2024
a5d7c33
cleanup and add to Readme
bl-young Dec 4, 2024
aa0d144
Merge pull request #126 from USEPA/ced
bl-young Dec 4, 2024
946e70f
differentiate package version and flowlist version
bl-young Dec 4, 2024
acd3c87
use tool_version instead of package_version
bl-young Dec 4, 2024
f619c58
point back to develop
bl-young Dec 4, 2024
8201e21
Merge pull request #127 from USEPA/version
bl-young Dec 4, 2024
add5b78
avoid adding CED to base FEDEFL_Inv method; bump v to account for new…
bl-young Dec 5, 2024
b5be424
:bookmark: bump to v1.1.4
bl-young Dec 5, 2024
9f966c7
drop develop tags
bl-young Dec 28, 2024
8aacb54
add python 3.12 and 3.13 to tests
bl-young Dec 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
py-version: ['3.9', '3.10', '3.11']
py-version: ['3.9', '3.10', '3.11', '3.12', '3.13']

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_methods.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Update pip & install testing pkgs
run: |
Expand Down
38 changes: 38 additions & 0 deletions .zenodo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"description": "Standardizes the format and flows of life cycle impact assessment (LCIA) data.",
"license": "MIT",
"title": "LCIA Formatter",
"upload_type": "software",
"creators": [
{
"affiliation": "Eastern Research Group, Inc.",
"name": "Ben Young",
"orcid": "https://orcid.org/0000-0001-6276-8670"
},
{
"affiliation": "GreenDelta",
"name": "Michael Srocka"
},
{
"affiliation": "US Environmental Protection Agency",
"name": "Wesley Ingwersen",
"orcid": "https://orcid.org/0000-0002-9614-701X"
},
{
"affiliation": "Eastern Research Group, Inc.",
"name": "Ben Morelli",
"orcid": "https://orcid.org/0000-0002-7660-6485"
},
{
"affiliation": "Eastern Research Group, Inc.",
"name": "Sarah Cashman",
"orcid": "https://orcid.org/0000-0001-9859-9557"
},
{
"affiliation": "Eastern Research Group, Inc.",
"name": "Andrew Henderson",
"orcid": "https://orcid.org/0000-0003-2436-7512"
}
],
"access_right": "open"
}
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# LCIA formatter
[![DOI](https://joss.theoj.org/papers/10.21105/joss.03392/status.svg)](https://doi.org/10.21105/joss.03392)
[![JOSS](https://joss.theoj.org/papers/10.21105/joss.03392/status.svg)](https://doi.org/10.21105/joss.03392)
[![DOI](https://zenodo.org/badge/188049640.svg)](https://zenodo.org/doi/10.5281/zenodo.7400857)
[![build](https://github.com/USEPA/LCIAformatter/actions/workflows/python-package.yml/badge.svg)](https://github.com/USEPA/LCIAformatter/actions/workflows/python-package.yml)

The LCIA formatter, or `lciafmt`, is a Python tool for standardizing the format and flows of life cycle impact assessment (LCIA) data. The tool acquires LCIA data transparently from its original
Expand All @@ -18,6 +19,7 @@ The LCIA Formatter v1 was peer-reviewed internally at USEPA and externally throu
|ImpactWorld+ Endpoint*|International Reference Center for Life Cycle of Products, Services and Systems (CIRAIG)|[ImpactWorld+](http://www.impactworldplus.org/en/team.php)|
|IPCC GWP|Intergovernmental Panel on Climate Change (IPCC)| |
|FEDEFL Inventory Methods|US Environmental Protection Agency|[FEDEFL Inventory Methods](https://github.com/USEPA/LCIAformatter/wiki/Inventory-Methods)|
|Cumulative Energy Demand|Federal LCA Commons|[FEDEFL Inventory Methods](https://github.com/USEPA/LCIAformatter/wiki/Inventory-Methods)|

\* only works on Windows installations

Expand Down
4 changes: 4 additions & 0 deletions lciafmt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import pandas as pd

import lciafmt.cache as cache
import lciafmt.ced as ced
import lciafmt.fmap as fmap
import lciafmt.jsonld as jsonld
import lciafmt.traci as traci
Expand All @@ -34,6 +35,7 @@ class Method(Enum):
TRACI = "TRACI 2.1"
RECIPE_2016 = "ReCiPe 2016"
FEDEFL_INV = "FEDEFL Inventory"
CED = "Cumulative Energy Demand"
ImpactWorld = "ImpactWorld"
IPCC = "IPCC"

Expand Down Expand Up @@ -122,6 +124,8 @@ def get_method(method_id, add_factors_for_missing_contexts=True,
return ipcc.get()
if method_id == Method.FEDEFL_INV:
return fedefl_inventory.get(subset)
if method_id == Method.CED:
return ced.get()


def clear_cache():
Expand Down
60 changes: 60 additions & 0 deletions lciafmt/ced.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ced.py (lciafmt)
# !/usr/bin/env python3
# coding=utf-8
"""
Generate method for Cumulative Energy Demand (CED)
"""

import numpy as np
import pandas as pd

import lciafmt
from lciafmt.util import store_method


def get() -> pd.DataFrame():

inv_orig = lciafmt.get_method(method_id = 'FEDEFL_INV', subset = ['ced'])
inv = inv_orig.copy()
inv['Indicator'] = ''
inv['Method'] = 'Cumulative Energy Demand'

conditions = [
inv['Flowable'].isin(['Wood, primary forest']),
inv['Flowable'].isin(['Biomass', 'Softwood', 'Hardwood', 'Wood']),
inv['Flowable'].isin(['Energy, hydro']),
inv['Flowable'].str.contains('|'.join(['wind', 'solar', 'geothermal'])),
inv['Flowable'].str.contains('Uranium'),
inv['Flowable'].str.contains('|'.join(['Coal', 'Oil', 'Crude',
'gas', 'Methane'])),
]

indicators = ['Non-renewable, biomass',
'Renewable, biomass',
'Renewable, water',
'Renewable, wind, solar, geothermal',
'Non-renewable, nuclear',
'Non-renewable, fossil',
]
inv['Indicator'] = np.select(conditions, indicators, default='')

## Original CED Method included the
# "Energy, fossil, unspecified" technosphere flow;
# this has been dropped
# https://www.lcacommons.gov/lca-collaboration/National_Renewable_Energy_Laboratory/USLCI_Database_Public/dataset/FLOW/46dc4693-2f24-39d2-b69f-dd059737fd5e

## Original CED Method used HHV for biomass/wood flows
# Some wood flows were removed after the original method in FEDEFLv1.0.8

# Dropped flows from FEDEFL inv method: "Hydrogen", "Energy, heat"
inv = inv.query('Indicator != ""').reset_index(drop=True)

return inv


if __name__ == "__main__":
method = lciafmt.Method.CED
df = get()
store_method(df, method)
lciafmt.util.save_json(method, df)
# lciafmt.util.save_json(method, df, write_flows=True)
4 changes: 2 additions & 2 deletions lciafmt/data/ReCiPe2016_endpoint_to_midpoint.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
,Toxicity - Human health (non-cancer),Human noncarcinogenic toxicity,Human health
,Water consumption - human health,Water consumption,Human health
,Global Warming - Terrestrial ecosystems,Global Warming,Terrestrial ecosystems
,Photochemical ozone formation - Terrestrial ecosystems,Ecosyste damage ozone formation,Terrestrial ecosystems
,Photochemical ozone formation - Terrestrial ecosystems,Ecosystem damage ozone formation,Terrestrial ecosystems
,Acidification - Terrestrial ecosystems,Terrestrial acidification,Terrestrial ecosystems
,Toxicity - Terrestrial ecosystems,Terrestrial ecotoxicity,Terrestrial ecosystems
,Water consumption - terrestrial ecosystems,Water consumption,Terrestrial ecosystems
,Land use - occupation and transformation,Land occupation,Terrestrial ecosystems
,Global Warming - Freshwater ecosystems,Global Warming,Freshwater ecosystems
,Eutrophication - Freshwater ecosystems,Freshwater eutrophication,Freshwater ecosystems
,Toxicity - Freshwater ecosystems,Freshwater ecotoxicity,Freshwater ecosystems
,Water consumption -aquatic ecosystems,Water consumption,Freshwater ecosystems
,Water consumption - aquatic ecosystems,Water consumption,Freshwater ecosystems
,Toxicity - Marine ecosystems,Marine ecotoxicity,Marine ecosystems
,Eutrophication - Marine ecosystems,Marine eutrophication,Marine ecosystems
,Mineral resource scarcity,Mineral resource scarcity,Resources
Expand Down
4 changes: 3 additions & 1 deletion lciafmt/data/description.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
base: >+
[Method][version] is built from LCIA Formatter v[LCIAfmt_version] and
flows from the Federal Elementary Flow List (FEDEFL) v[FEDEFL_version]
flows from v[FEDEFL_version] of the Federal Elementary Flow List (FEDEFL),
using fedelemflowlist v[fedelemflowlist_version].

description: >+
[Method] source file: [url]

Source citation: [citation]

mapping: >+
[Method] flowable and context input files are maintained in the FEDEFL
GitHub Repository: https://github.com/USEPA/fedelemflowlist

Expand Down
9 changes: 9 additions & 0 deletions lciafmt/data/lcia.bib
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,12 @@ @incollection{smith_earths_2021
author = {Smith, Chris and Nicholls, Zebedee R. J. and Armour, Kyle and Collins, William and Forster, Piers and Meinshausen, Malte and Palmer, Matthew D. and Watanabe, Masahiro},
year = {2021},
}

@report{frischknecht_implementation_2007,
title = {Implementation of life cycle impact assessment methods},
url = {https://esu-services.ch/fileadmin/download/publicLCI/03_LCIA-Implementation.pdf},
number = {ecoinvent report No. 3},
author = {Frischknecht, Rolf and Jungbluth, Niels and Althaus, H. J. and Bauer, C. and Doka, G. and Dones, R. and Hischier, R. and Hellweg, S. and Humbert, S. and Köllner, T.},
urldate = {2024-11-13},
year = {2007},
}
19 changes: 15 additions & 4 deletions lciafmt/data/methods.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
"ReCiPe 2016 - Midpoint/E":"ReCiPe 2016 v1.1 midpoint method, Egalitarian version. The typical ReCiPe midpoint method used is the Hierarchist version."},
"path": "recipe",
"case_insensitivity": "True",
"url": "http://www.rivm.nl/sites/default/files/2018-11/ReCiPe2016_CFs_v1.1_20180117.xlsx",
"url": "https://www.rivm.nl/sites/default/files/2024-10/ReCiPe2016_CFs_v1.1_20180117.xlsx",
"bib_id": "huijbregts_recipe_2017",
"citation": "Huijbregts 2017",
"source_type": "Excel file"
},
{
"id": "FEDEFL_INV",
"name": "FEDEFL Inventory",
"version": "1.0.0",
"version": "1.1.0",
"path": "fedefl",
"url": "http://www.github.com/usepa//Federal-LCA-Commons-Elementary-Flow-List",
"url": "https://github.com/USEPA/fedelemflowlist/blob/master/fedelemflowlist/subset_list.py",
"citation": "",
"source_type": "FEDEFL Python function"
},
Expand All @@ -49,7 +49,7 @@
"ImpactWorld+ - Endpoint":"This method includes all global endpoint flows and their attributes."},
"path": "impactworld",
"case_insensitivity": "False",
"url": "http://www.impactworldplus.org/en/writeToFile.php",
"url": "https://www.dropbox.com/sh/2sdgbqf08yn91bc/AABIGLlb_OwfNy6oMMDZNrm0a/IWplus_public_v1.3.accdb?dl=1",
"citation": "Bulle, Cecile, Manuele Margni, Laure Patouillard, Anne-Marie Boulay, Guillaume Bourgault, Vincent De Bruille, Viet Cao, et al. IMPACT World+: A Globally Regionalized Life Cycle Impact Assessment Method. The International Journal of Life Cycle Assessment 24, no. 9 (September 2019), 1653–74. https://doi.org/10.1007/s11367-019-01583-0",
"source_type": "Access file"
},
Expand All @@ -67,6 +67,17 @@
},
"citation": "Forster and Ramaswamy 2007 (AR4), Myhre and Shindell 2013 (AR5), Forster and Storelvmo 2021 (AR6)",
"source_type": "csv"
},
{
"id": "CED",
"name": "Cumulative Energy Demand",
"version": "1.0",
"detail_note": "All heating values are per the FEDEFL, and the list of external references is found on the EPA FEDEFL GitHub at: https://github.com/USEPA/fedelemflowlist. This CED method is based on the categorization scheme used in Frischknecht et al. (2007) found in the ecoinvent report 'Implementation of Life Cycle Impact Assessment Methods.'",
"path": "fedefl",
"bib_id": "frischknecht_implementation_2007",
"url": "https://github.com/USEPA/fedelemflowlist/blob/master/fedelemflowlist/subset_list.py",
"citation": "Frischknecht et al. 2007",
"source_type": ""
}

]
8 changes: 6 additions & 2 deletions lciafmt/fedefl_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def get(subset=None) -> pd.DataFrame:
method['Characterization Factor'])

if subset is None:
list_of_inventories = subsets.get_subsets()
list_of_inventories = [s for s in subsets.get_subsets() if s
not in ('ced')]
else:
list_of_inventories = subset

Expand All @@ -39,7 +40,7 @@ def get(subset=None) -> pd.DataFrame:
axis=1, inplace=True)
flows['Indicator'] = inventory
flows['Indicator unit'] = subsets.get_inventory_unit(inventory)
flows['Characterization Factor'] = 1
flows['Characterization Factor'] = 1.0

# Apply unit conversions where flow unit differs from indicator unit
flows_w_conversion = pd.merge(flows, alt_units, how='left',
Expand All @@ -56,3 +57,6 @@ def get(subset=None) -> pd.DataFrame:

method['Method'] = 'FEDEFL Inventory'
return method

if __name__ == "__main__":
df = get()
14 changes: 9 additions & 5 deletions lciafmt/iw.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import pandas as pd
import lciafmt
import lciafmt.cache as cache
import lciafmt.df as dfutil
from lciafmt.util import log, format_cas
Expand Down Expand Up @@ -38,13 +39,10 @@ def get(file=None, url=None, region=None) -> pd.DataFrame:
"Please install drivers to remotely connect to Access Database. "
"Drivers only available on windows platform. For instructions visit: "
"https://github.com/mkleehammer/pyodbc/wiki/Connecting-to-Microsoft-Access")

method_meta = lciafmt.Method.ImpactWorld.get_metadata()
f = file
if f is None:
fname = "Impact_World.accdb"
if url is None:
url = "https://www.dropbox.com/sh/2sdgbqf08yn91bc/AABIGLlb_OwfNy6oMMDZNrm0a/IWplus_public_v1.3.accdb?dl=1"
f = cache.get_or_download(fname, url)
f = _get_file(method_meta, url)
df = _read(f, region)

# Identify midpoint and endpoint records and differentiate in data frame.
Expand All @@ -58,6 +56,12 @@ def get(file=None, url=None, region=None) -> pd.DataFrame:

return df

def _get_file(method_meta, url=None):
fname = "Impact_World.accdb"
if url is None:
url = method_meta['url']
f = cache.get_or_download(fname, url)
return f

def _read(access_file: str, region) -> pd.DataFrame:
"""Read the Access database at passed access_file into DataFrame."""
Expand Down
2 changes: 1 addition & 1 deletion lciafmt/jsonld.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def write(self, df: pd.DataFrame, write_flows=False, preferred_only=False):
indicator = self.__indicator(row)
factor = o.ImpactFactor()
unit = row['Unit']
factor.flow = self.__flow(row)
factor.flow = self.__flow(row).to_ref()
factor.flow_property = units.property_ref(unit)
factor.unit = units.unit_ref(unit)
factor.value = row['Characterization Factor']
Expand Down
23 changes: 15 additions & 8 deletions lciafmt/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pandas as pd
import openpyxl

import lciafmt
import lciafmt.cache as cache
import lciafmt.df as dfutil
import lciafmt.xls as xls
Expand Down Expand Up @@ -52,13 +53,10 @@ def get(add_factors_for_missing_contexts=True, endpoint=True,
:return: DataFrame of method in standard format
"""
log.info("getting method ReCiPe 2016")
method_meta = lciafmt.Method.RECIPE_2016.get_metadata()
f = file
if f is None:
fname = "recipe_2016.xlsx"
if url is None:
url = ("http://www.rivm.nl/sites/default/files/2018-11/" +
"ReCiPe2016_CFs_v1.1_20180117.xlsx")
f = cache.get_or_download(fname, url)
f = _get_file(method_meta, url)
df = _read(f)
if add_factors_for_missing_contexts:
log.info("adding average factors for primary contexts")
Expand Down Expand Up @@ -135,6 +133,14 @@ def get(add_factors_for_missing_contexts=True, endpoint=True,
return df


def _get_file(method_meta, url=None):
fname = "recipe_2016.xlsx"
if url is None:
url = method_meta['url']
f = cache.get_or_download(fname, url)
return f


def _read(file: str) -> pd.DataFrame:
log.info(f"read ReCiPe 2016 from file {file}")
wb = openpyxl.load_workbook(file, read_only=True, data_only=True)
Expand Down Expand Up @@ -171,7 +177,7 @@ def _read_endpoints(file: str) -> pd.DataFrame:
continue
endpoints['Method'] = "ReCiPe 2016 - Midpoint/" + perspectives[i]
endpoints['EndpointMethod'] = "ReCiPe 2016 - Endpoint/" + perspectives[i]
endpoints['EndpointIndicator'] = indicator
endpoints['EndpointIndicator'] = indicator.replace(' -a', ' - a') # fix missing space
endpoints['EndpointUnit'] = indicator_unit
endpoints['EndpointConversion'] = val
endpoint = pd.concat(
Expand Down Expand Up @@ -215,6 +221,7 @@ def _read_mid_points(sheet: openpyxl.worksheet.worksheet.Worksheet,
cas_col = _find_cas_column(sheet)
indicator_unit, flow_unit, unit_col = _determine_units(sheet)
compartment, compartment_col = _determine_compartments(sheet)
sheet_title = sheet.title.replace('Ecosyste damage', 'Ecosystem damage')

perspectives = ["I", "H", "E"]
factor_count = 0
Expand All @@ -238,7 +245,7 @@ def _read_mid_points(sheet: openpyxl.worksheet.worksheet.Worksheet,
continue
dfutil.record(records,
method="ReCiPe 2016 - Midpoint/" + perspectives[i],
indicator=sheet.title,
indicator=sheet_title,
indicator_unit=indicator_unit,
flow=xls.cell_str(row[flow_col]),
flow_category=compartment,
Expand All @@ -253,7 +260,7 @@ def _read_mid_points(sheet: openpyxl.worksheet.worksheet.Worksheet,
for p in perspectives:
dfutil.record(records,
method="ReCiPe 2016 - Midpoint/" + p,
indicator=sheet.title,
indicator=sheet_title,
indicator_unit=indicator_unit,
flow=xls.cell_str(row[flow_col]),
flow_category=compartment,
Expand Down
Loading
Loading