Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a165066
adding two new config files to update data. but
ssamkl Aug 6, 2025
9461aff
Merge branch 'NETL-RIC:development' into development
dt-woods Sep 5, 2025
506f770
add the stewicomboo testing file to 2023 config
dt-woods Sep 5, 2025
e2be39d
Merge branch 'NETL-RIC:development' into development
dt-woods Sep 5, 2025
8dba85a
fix public coal for 2023
dt-woods Sep 5, 2025
6746d63
Updates for 2023 data + other minor bug fixes
frankhanna94 Oct 9, 2025
d1dfcce
Modify 'year' parameter type and DataFrame selection
frankhanna94 Oct 14, 2025
f849bb4
Merge pull request #15 from frankhanna94/development
frankhanna94 Oct 14, 2025
794c7e8
Natural Gas Upstream update - Addresses issue #260
frankhanna94 Oct 16, 2025
5f1b99a
Updated ng model from basin to region basis
frankhanna94 Oct 20, 2025
2726c60
Minor edits to natural_gas_upstream.py
frankhanna94 Oct 20, 2025
e739bde
updated yaml documentation
frankhanna94 Nov 7, 2025
93ac549
yaml documentation quickfix
frankhanna94 Nov 7, 2025
e7f5997
process metadata - Yaml file minor edit
frankhanna94 Nov 7, 2025
d2496dc
fix spacing
dt-woods Nov 21, 2025
ebc5c67
Merge pull request #16 from frankhanna94/development
dt-woods Nov 21, 2025
004ef75
Merge branch 'development' of https://github.com/KeyLogicLCA/Electric…
dt-woods Nov 21, 2025
85c7fa3
update stewicombo file for latest data; addresses #275
dt-woods Nov 24, 2025
e0ff84b
HOTFIX - t&d download links
frankhanna94 Nov 24, 2025
ecbea96
Fix URL construction for year 2024
frankhanna94 Nov 25, 2025
8d0e1e0
Update t&d links setup following TWD comment
frankhanna94 Nov 25, 2025
930c11d
Merge pull request #17 from frankhanna94/development
dt-woods Nov 25, 2025
4c6e634
Merge branch 'development' of https://github.com/KeyLogicLCA/Electric…
dt-woods Nov 25, 2025
5bbbcdd
add version 2.1 config options
dt-woods Dec 4, 2025
7cbabd4
add ELCI_2023 run to comments
dt-woods Dec 4, 2025
f313565
fixes to inline comments and formatting
dt-woods Dec 4, 2025
aa2cdb7
formatting and style fixes
dt-woods Dec 4, 2025
e2ab751
alphabetize methods
dt-woods Dec 4, 2025
99128db
fix comments
dt-woods Dec 4, 2025
15c4c97
update language for NG model parameter
dt-woods Dec 4, 2025
e49c2ca
hotfix setup for v2.1
dt-woods Dec 10, 2025
3e4df8b
Merge branch 'development' into development
dt-woods Dec 10, 2025
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ electricitylci/output/*
!electricitylci/data/*.yml

# Whitelist everything except this!
electricitylci/data/EFs/.DS_Store
electricitylci/data/EFs/.DS_Store

Notes.txt
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ The `main()` method has four steps:
* ELCI_2020
* ELCI_2021
* ELCI_2022
- Version 2.1 baselines include:
* ELCI_2023
* ELCI_2024
- These configurations statically change the module, model_config.py, which is an object read by other modules.
- To change configuration values, edit the YAML before running the code.
2. `run_generation()`
Expand Down
22 changes: 15 additions & 7 deletions electricitylci/coal_upstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
transportation, but still mainly represents 2016.

Last updated:
2025-06-09
2025-09-05
"""
__all__ = [
"basin_codes", # Globals
Expand Down Expand Up @@ -436,7 +436,8 @@ def eia_7a_download(year, save_path):
see https://github.com/USEPA/ElectricityLCI/issues/230 for a solution.
"""
eia7a_base_url = 'http://www.eia.gov/coal/data/public/xls/'
name = 'coalpublic{}.xls'.format(year)
name = ('coalpublic{}.xls'.format(year) if year <= 2022 else
'coalpublic{}.xlsx'.format(year))
url = eia7a_base_url + name
try:
os.makedirs(save_path)
Expand Down Expand Up @@ -1675,11 +1676,18 @@ def read_eia7a_public_coal(year):
return_name=False)
# If you're here, then see the following for hotfix:
# https://github.com/USEPA/ElectricityLCI/issues/230
eia7a_df = pd.read_excel(
eia7a_path,
sheet_name='Hist_Coal_Prod',
skiprows=3
)
try:
eia7a_df = pd.read_excel(
eia7a_path,
sheet_name='Hist_Coal_Prod',
skiprows=3
)
except ValueError:
raise ValueError(
f'Error reading {eia7a_path}. Please see '
'https://github.com/USEPA/ElectricityLCI/issues/230 '
'for a solution'
)
eia7a_df = _clean_columns(eia7a_df)

return eia7a_df
Expand Down
20 changes: 10 additions & 10 deletions electricitylci/combinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def concat_map_upstream_databases(eia_gen_year, *arg, **kwargs):
# Hoping to reduce memory usage or at least make more of it available
# for the later groupby.
del(arg)
# See https://github.com/USEPA/fedelemflowlist
# See https://github.com/FLCAC-admin/fedelemflowlist
# The mapping data includes a conversion factor to convert everything into
# standard units (e.g., kg, MJ, m2*a). Note that 'SourceFlowContext' is
# already in lowercase letters, which is why no change happens below.
Expand Down Expand Up @@ -415,7 +415,7 @@ def concat_map_upstream_databases(eia_gen_year, *arg, **kwargs):
# columns to be converted to objects, so undoing that here
for col in actual_quant_columns:
upstream_mapped_df[col]=upstream_mapped_df[col].astype(float)

# Preserve unmapped resource flows;
# copy over the flow name, compartment and units and
# set conversion factor equal to 1.0.
Expand Down Expand Up @@ -492,7 +492,7 @@ def concat_map_upstream_databases(eia_gen_year, *arg, **kwargs):
"Source",
"Year",
] + actual_quant_columns

if "input" in upstream_columns:
final_columns = final_columns + ["input"]

Expand Down Expand Up @@ -587,9 +587,9 @@ def concat_clean_upstream_and_plant(pl_df, up_df):
)
# 3/19/2025 MBJ: more memory management. When this process is called from
# __init__.combine_upstream_and_gen_df the up_df is 12GB big. Previously
# we used a merge to add all the regional columns, but that requires a
# tremendous amount of memory. Invidually assigning columns will be a bit
# slower but will greatly reduce memory usage...and ultimately end up
# we used a merge to add all the regional columns, but that requires a
# tremendous amount of memory. Individually assigning columns will be a bit
# slower but will greatly reduce memory usage...and ultimately end up
# faster if your computer tends to run out of memory using the previous
# merge.
for col in existing_region_cols:
Expand All @@ -598,10 +598,10 @@ def concat_clean_upstream_and_plant(pl_df, up_df):
# HOTFIX: during the merge, a lot eGRID_IDs are unmatched, so fill them in!
# NOTE: triggers a pandas futurewarning on downcasting object datatypes.
# 3/19/2025 - these would be instances where there is a plant_id in up_df
# but not a matching eGRID_ID. With the new, by-column mapping performed above
# eGRID_ID does not exist so no Nans to fill. In previous versions, I believe
# the use of fillnans with plant_id being the source would result in the
# same thing as below.
# but not a matching eGRID_ID. With the new, by-column mapping performed
# above eGRID_ID does not exist so no Nans to fill. In previous versions,
# I believe the use of fillnans with plant_id being the source would result
# in the same thing as below.
up_df['eGRID_ID'] = up_df['plant_id'].astype("int")

# NOTE: the only columns in up_df not in pl_df should be:
Expand Down
13 changes: 7 additions & 6 deletions electricitylci/data/process_metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -857,15 +857,16 @@ coal_upstream:
gas_upstream:

techno_intro: &gas_upstream_techno_intro
- 'The cradle-to-gate inventory for production of gas aggregated to basin. '
- 'The cradle-to-gate inventory for production of gas aggregated to basin or region, depending on the year selected in the model configuration. '

techno_process: &gas_upstream_techno_process
- 'The NETL natural gas life cycle model includes parameters to generate inventories for natural gas extraction based on basin and geology which determines the gas extraction type (e.g., Appalachian Shale using hydraulic fracturing).
2016 natural gas production then informs the amount of each type of technology/region that form the mix in the regions.
- 'The NETL natural gas life cycle model includes parameters to generate inventories for natural gas extraction based on region or basin and geology which determines the gas extraction type (e.g., Appalachian Shale using hydraulic fracturing).
2016 or 2020 natural gas production then informs the amount of each type of technology/region that form the mix in the regions, depending on the year selected in the model configuration.
These can be further aggregated to a US average.
More details are in the natural gas upstream report at the link below

https://www.netl.doe.gov/energy-analysis/details?id=3198'
More details are in the natural gas upstream report at the following links.
Link for 2016: https://www.netl.doe.gov/energy-analysis/details?id=4f43cb3f-c0d7-482e-bf01-39995a7c7497
Link for 2020: https://www.netl.doe.gov/energy-analysis/details?id=546d4009-c43b-43f5-bcc9-64d5e63fc8d5
'

Description:
- *gas_upstream_techno_intro
Expand Down
1 change: 1 addition & 0 deletions electricitylci/egrid_emissions_and_waste_by_facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def get_combined_stewicombo_file(model_specs):
emissions_and_wastes_by_facility = get_combined_stewicombo_file(
model_config)
len(emissions_and_wastes_by_facility)
# for 'ELCI_2023': 90238 [251125; TWD]
# for 'ELCI_2020': 88005 [250416; TWD]
# for 'ELCI_1': 106284 (recorded as 88310 [250416;TWD])

Expand Down
1 change: 1 addition & 0 deletions electricitylci/egrid_facilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def make_egrid_subregion_ref(year):
# Rename columns. NOTE: missing names resolved
# (https://github.com/USEPA/standardizedinventories/issues/153)
egrid_facilities.rename(columns={
'Plant primary fuel category': 'FuelCategory', # added for 2023 STEWI data
'Plant primary coal/oil/gas/ other fossil fuel category': 'FuelCategory',
'Plant primary fuel': 'PrimaryFuel',
'eGRID subregion acronym': 'Subregion',
Expand Down
47 changes: 17 additions & 30 deletions electricitylci/eia_trans_dist_grid_loss.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,16 @@ def eia_trans_dist_download_extract(year):

Parameters
----------
year : str
year : str, int
Analysis year

Returns
-------
pandas.DataFrame
"""
# check in case year is passed as an int
if isinstance(year,int):
year = str(year)
eia_trans_dist_loss = pd.DataFrame()
old_path = os.getcwd()
if os.path.exists(f"{paths.local_path}/t_and_d_{year}"):
Expand All @@ -96,38 +99,22 @@ def eia_trans_dist_download_extract(year):
filename = f"{STATE_ABBREV[key]}.xlsx"
if not os.path.exists(filename):
logging.info(f"Downloading archive data for {STATE_ABBREV[key]}")
# HOTFIX: URLs for two-word states have space omitted.
url_a = (
"https://www.eia.gov/electricity/state/archive/"
+ year
+ "/"
+ key.replace(" ", "")
+ "/xls/"
+ filename
)
url_b = (
"https://www.eia.gov/electricity/state/"
+ key.replace(" ", "")
+ "/xls/"
+ filename
)

url_key = key.replace(" ", "")
url = f"https://www.eia.gov/electricity/state/archive/{year}/{url_key}/xls/"
if int(year) > 2023:
url = url.replace(f"/archive/{year}/{url_key}/", "/")
url += "SEP%20Tables%20for%20" + f"{STATE_ABBREV[key].upper()}.xlsx"
elif int(year) == 2023:
url += "SEP%20Tables%20for%20" + f"{STATE_ABBREV[key].upper()}.xlsx"
else:
url += f"{STATE_ABBREV[key]}.xlsx"

r = requests.get(url, timeout=20)
# HOTFIX: https://github.com/USEPA/ElectricityLCI/issues/235
#adding 20s timeout to avoid long delays due to server issues.
r = requests.get(url_a, timeout=20)
r_head = r.headers.get("Content-Type", "")
if not r.ok or r_head.startswith("text"):
logging.info(f"Trying alternative site {STATE_ABBREV[key]}")
#adding 20s timeout to avoid long delays due to server issues.
r = requests.get(url_b, timeout=20)
r_head = r.headers.get("Content-Type", "")

if r.ok and not r_head.startswith("text"):
with open(filename, 'wb') as f:
with open (filename, "wb") as f:
f.write(r.content)
else:
logging.error(
f"No TD loss data for {STATE_ABBREV[key]} {year}")

try:
df = pd.read_excel(
filename,
Expand Down
4 changes: 3 additions & 1 deletion electricitylci/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,9 @@ def create_generation_process_df():
# numbers and maps them to eGRID facility numbers.
# NOTE: there are unmatched facilities that are found in FRS_bridge,
# but not in EIA (e.g., EGRID, RCRA).
emissions_and_wastes_by_facility = get_combined_stewicombo_file(model_specs)
emissions_and_wastes_by_facility = get_combined_stewicombo_file(
model_specs
)
ewf_df = pd.merge(
left=emissions_and_wastes_by_facility,
right=eia860_FRS,
Expand Down
2 changes: 2 additions & 0 deletions electricitylci/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@
RENEWABLE_VINTAGES = [2016, 2020]
'''list : The valid years for renewable inventories (i.e., 2016 and 2020).'''

NG_MODEL_YEARS = [2016, 2020]
'''list : The valid years for natural gas model (i.e., 2016 and 2020).'''

##############################################################################
# FUNCTIONS
Expand Down
13 changes: 13 additions & 0 deletions electricitylci/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from electricitylci.globals import output_dir
from electricitylci.globals import COAL_MODEL_YEARS
from electricitylci.globals import RENEWABLE_VINTAGES
from electricitylci.globals import NG_MODEL_YEARS


##############################################################################
Expand Down Expand Up @@ -141,6 +142,8 @@ class ModelSpecs:
Absolute path to JSON-LD zip output file.
File name includes the model name and current time stamp and is
located by default in the output directory (see globals.py).
ng_model_year : int
The natural gas model year (e.g., 2016 or 2020).
"""
def __init__(self, model_specs, model_name):
"""Class initialization.
Expand Down Expand Up @@ -201,6 +204,7 @@ def __init__(self, model_specs, model_name):
f"{output_dir}/{model_name}_jsonld_"
f"{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
)
self.ng_model_year = model_specs["ng_model_year"]


##############################################################################
Expand Down Expand Up @@ -330,9 +334,18 @@ def check_model_specs(model_specs):
err_str += " or ".join([str(x) for x in COAL_MODEL_YEARS])
err_str += " not %s!" % model_specs['coal_model_year']
raise ConfigurationError(err_str)

if not model_specs['renewable_vintage'] in RENEWABLE_VINTAGES:
err_str = "The renewable inventory vintage must be one of "
err_str += " or ".join([str(x) for x in RENEWABLE_VINTAGES])
err_str += " not %s!" % model_specs['renewable_vintage']
raise ConfigurationError(err_str)

if not model_specs['ng_model_year'] in NG_MODEL_YEARS:
err_str = "The natural gas model year must be one of "
err_str += " or ".join([str(x) for x in NG_MODEL_YEARS])
err_str += " not %s!" % model_specs['ng_model_year']
raise ConfigurationError(err_str)

logging.info("Checks passed!")

8 changes: 8 additions & 0 deletions electricitylci/modelconfig/ELCI_1_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ replace_egrid: true
# construction LCI.
coal_model_year: 2020

# The NG baseline model year is used to determine which NG inventory to use.
# This impacts the upstream NG emissions for production, gathering and boosting,
# processing, transmission, storage, and distribution.
# Select between 2016 and 2020 model inventories:
# 2016 model: https://doi.org/10.2172/1529553
# 2020 model: https://doi.org/10.18141/2568690
ng_model_year: 2016

# NETL developed profiles for renewable generation to capture construction
# and O&M impacts (e.g., solar PV manufacturing and power plant operations).
# There are two vintages for renewable inventories: 2016 and 2020. The 2016
Expand Down
8 changes: 8 additions & 0 deletions electricitylci/modelconfig/ELCI_2020_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ replace_egrid: true
# construction LCI.
coal_model_year: 2023

# The NG baseline model year is used to determine which NG inventory to use.
# This impacts the upstream NG emissions for production, gathering and boosting,
# processing, transmission, storage, and distribution.
# Select between 2016 and 2020 model inventories:
# 2016 model: https://doi.org/10.2172/1529553
# 2020 model: https://doi.org/10.18141/2568690
ng_model_year: 2020

# NETL developed profiles for renewable generation to capture construction
# and O&M impacts (e.g., solar PV manufacturing and power plant operations).
# There are two vintages for renewable inventories: 2016 and 2020. The 2016
Expand Down
8 changes: 8 additions & 0 deletions electricitylci/modelconfig/ELCI_2021_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ replace_egrid: true
# construction LCI.
coal_model_year: 2023

# The NG baseline model year is used to determine which NG inventory to use.
# This impacts the upstream NG emissions for production, gathering and boosting,
# processing, transmission, storage, and distribution.
# Select between 2016 and 2020 model inventories:
# 2016 model: https://doi.org/10.2172/1529553
# 2020 model: https://doi.org/10.18141/2568690
ng_model_year: 2020

# NETL developed profiles for renewable generation to capture construction
# and O&M impacts (e.g., solar PV manufacturing and power plant operations).
# There are two vintages for renewable inventories: 2016 and 2020. The 2016
Expand Down
8 changes: 8 additions & 0 deletions electricitylci/modelconfig/ELCI_2022_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ replace_egrid: true
# construction LCI.
coal_model_year: 2023

# The NG baseline model year is used to determine which NG inventory to use.
# This impacts the upstream NG emissions for production, gathering and boosting,
# processing, transmission, storage, and distribution.
# Select between 2016 and 2020 model inventories:
# 2016 model: https://doi.org/10.2172/1529553
# 2020 model: https://doi.org/10.18141/2568690
ng_model_year: 2020

# NETL developed profiles for renewable generation to capture construction
# and O&M impacts (e.g., solar PV manufacturing and power plant operations).
# There are two vintages for renewable inventories: 2016 and 2020. The 2016
Expand Down
Loading