Skip to content

Commit

Permalink
Merge pull request #17 from NREL/feature/green_steel_ammonia
Browse files Browse the repository at this point in the history
Update feature/green_steel_ammonia branch
  • Loading branch information
kbrunik committed Dec 6, 2022
2 parents 5ae9b7f + 80e852c commit 1ff0589
Show file tree
Hide file tree
Showing 273 changed files with 42,694 additions and 1,126,007 deletions.
112 changes: 112 additions & 0 deletions LCA_single_scenario.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 2 12:09:20 2022
@author: ereznic2
"""
import pandas as pd

dircambium = 'Examples/H2_Analysis/Cambium_data/StdScen21_MidCase95by2035_hourly_'

# grid_connection_scenario = 'hybrid-grid'
# atb_year = 2020
# site_name = 'TX'
# turbine_model = '6MW'
# electrolysis_scale = 'Centralized'
# policy_option = 'no policy'
# grid_price_scenario = 'retail-flat'
# electrolyzer_energy_kWh_per_kg = 55

def hydrogen_LCA_singlescenario(grid_connection_scenario,atb_year,site_name,turbine_model,electrolysis_scale,policy_option,grid_price_scenario,electrolyzer_energy_kWh_per_kg,hydrogen_hourly_results_RODeO):

#==============================================================================
# DATA
#==============================================================================
# Conversions
g_to_kg_conv = 0.001 # Conversion from grams to kilograms
kg_to_MT_conv = 0.001 # Converion from kg to metric tonnes
MT_to_kg_conv = 1000 # Conversion from metric tonne to kilogram
kWh_to_MWh_conv = 0.001 # Conversion from kWh to MWh

#------------------------------------------------------------------------------
# Renewable infrastructure embedded emission intensities
#------------------------------------------------------------------------------
system_life = 30
ely_stack_capex_EI = 0.019 # PEM electrolyzer CAPEX emissions (kg CO2e/kg H2)
wind_capex_EI = 10 # Electricity generation from wind, nominal value taken (g CO2e/kWh)
solar_pv_capex_EI = 37 # Electricity generation from solar pv, nominal value taken (g CO2e/kWh)


#------------------------------------------------------------------------------
# Hydrogen production via water electrolysis
#------------------------------------------------------------------------------

grid_trans_losses = 0.05 # Grid losses of 5% are assumed (-)
fuel_to_grid_curr = 48 # Fuel mix emission intensity for current power grid (g CO2e/kWh)
fuel_to_grid_futu = 14 # Fuel mix emission intensity for future power grid (g CO2e/kWh)

if atb_year == 2020:
cambium_year = 2025
elif atb_year == 2025:
cambium_year = 2030
elif atb_year == 2030:
cambium_year ==2035
elif atb_year == 2035:
cambium_year = 2040

# Read in Cambium data
cambiumdata_filepath = dircambium + site_name + '_'+str(cambium_year) + '.csv'
cambium_data = pd.read_csv(cambiumdata_filepath,index_col = None,header = 4,usecols = ['lrmer_co2_c','lrmer_ch4_c','lrmer_n2o_c','lrmer_co2_p','lrmer_ch4_p','lrmer_n2o_p','lrmer_co2e_c','lrmer_co2e_p','lrmer_co2e'])

cambium_data = cambium_data.reset_index().rename(columns = {'index':'Interval','lrmer_co2_c':'LRMER CO2 combustion (kg-CO2/MWh)','lrmer_ch4_c':'LRMER CH4 combustion (g-CH4/MWh)','lrmer_n2o_c':'LRMER N2O combustion (g-N2O/MWh)',\
'lrmer_co2_p':'LRMER CO2 production (kg-CO2/MWh)','lrmer_ch4_p':'LRMER CH4 production (g-CH4/MWh)','lrmer_n2o_p':'LRMER N2O production (g-N2O/MWh)','lrmer_co2e_c':'LRMER CO2 equiv. combustion (kg-CO2e/MWh)',\
'lrmer_co2e_p':'LRMER CO2 equiv. production (kg-CO2e/MWh)','lrmer_co2e':'LRMER CO2 equiv. total (kg-CO2e/MWh)'})

cambium_data['Interval']=cambium_data['Interval']+1
cambium_data = cambium_data.set_index('Interval')

# Read in rodeo data
rodeo_data = hydrogen_hourly_results_RODeO[['Interval','Input Power (MW)','Non-Ren Import (MW)','Renewable Input (MW)','Curtailment (MW)','Product Sold (units of product)']]
rodeo_data = rodeo_data.rename(columns = {'Input Power (MW)':'Electrolyzer Power (MW)','Non-Ren Import (MW)':'Grid Import (MW)','Renewable Input (MW)':'Renewable Input (MW)', 'Curtailment (MW)':'Curtailment (MW)','Product Sold (units of product)':'Hydrogen production (kg-H2)'})
# Combine RODeO and Cambium data into one dataframe
combined_data = rodeo_data.merge(cambium_data, on = 'Interval',how = 'outer')

# Calculate hourly grid emissions factors of interest. If we want to use different GWPs, we can do that here. The Grid Import is an hourly data i.e., in MWh
combined_data['Total grid emissions (kg-CO2e)'] = combined_data['Grid Import (MW)']*combined_data['LRMER CO2 equiv. total (kg-CO2e/MWh)']
combined_data['Scope 2 (combustion) grid emissions (kg-CO2e)'] = combined_data['Grid Import (MW)']*combined_data['LRMER CO2 equiv. combustion (kg-CO2e/MWh)']
combined_data['Scope 3 (production) grid emissions (kg-CO2e)'] = combined_data['Grid Import (MW)']*combined_data['LRMER CO2 equiv. production (kg-CO2e/MWh)']

# Sum total emissions
scope2_grid_emissions_sum = combined_data['Scope 2 (combustion) grid emissions (kg-CO2e)'].sum()*system_life*kg_to_MT_conv
scope3_grid_emissions_sum = combined_data['Scope 3 (production) grid emissions (kg-CO2e)'].sum()*system_life*kg_to_MT_conv
h2prod_sum = combined_data['Hydrogen production (kg-H2)'].sum()*system_life*kg_to_MT_conv
h2prod_grid_frac = combined_data['Grid Import (MW)'].sum() / combined_data['Electrolyzer Power (MW)'].sum()

if grid_connection_scenario == 'hybrid-grid' :
# Calculate grid-connected electrolysis emissions/ future cases should reflect targeted electrolyzer electricity usage
electrolysis_Scope3_EI = h2prod_grid_frac*scope3_grid_emissions_sum/h2prod_sum + wind_capex_EI * electrolyzer_energy_kWh_per_kg * g_to_kg_conv + ely_stack_capex_EI # kg CO2e/kg H2
electrolysis_Scope2_EI = h2prod_grid_frac*scope2_grid_emissions_sum/h2prod_sum
electrolysis_Scope1_EI = 0
electrolysis_total_EI = electrolysis_Scope1_EI + electrolysis_Scope2_EI + electrolysis_Scope3_EI
electrolysis_total_EI_policy_grid = electrolysis_total_EI - wind_capex_EI * electrolyzer_energy_kWh_per_kg * g_to_kg_conv - ely_stack_capex_EI
electrolysis_total_EI_policy_offgrid = 0
elif grid_connection_scenario == 'grid-only':
# Calculate grid-connected electrolysis emissions
electrolysis_Scope3_EI = scope3_grid_emissions_sum/h2prod_sum + ely_stack_capex_EI # kg CO2e/kg H2
electrolysis_Scope2_EI = scope2_grid_emissions_sum/h2prod_sum
electrolysis_Scope1_EI = 0
electrolysis_total_EI = electrolysis_Scope1_EI + electrolysis_Scope2_EI + electrolysis_Scope3_EI
electrolysis_total_EI_policy_grid = electrolysis_total_EI - ely_stack_capex_EI
electrolysis_total_EI_policy_offgrid = 0
elif grid_connection_scenario == 'off-grid':
# Calculate renewable only electrolysis emissions
electrolysis_Scope3_EI = wind_capex_EI * electrolyzer_energy_kWh_per_kg * g_to_kg_conv + ely_stack_capex_EI # kg CO2e/kg H2
electrolysis_Scope2_EI = 0
electrolysis_Scope1_EI = 0
electrolysis_total_EI = electrolysis_Scope1_EI + electrolysis_Scope2_EI + electrolysis_Scope3_EI
electrolysis_total_EI_policy_offgrid = electrolysis_total_EI - wind_capex_EI * electrolyzer_energy_kWh_per_kg * g_to_kg_conv - ely_stack_capex_EI
electrolysis_total_EI_policy_grid = 0

return(electrolysis_total_EI_policy_grid,electrolysis_total_EI_policy_offgrid,h2prod_grid_frac)


129 changes: 129 additions & 0 deletions SMR_steel_ammonia_run_scenarios.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 30 13:29:30 2022
@author: mkoleva
"""

# Specify file path to PyFAST
import sys
import os
import glob
sys.path.insert(1,'../PyFAST/')
import pandas as pd
sys.path.append('../PyFAST/')
import run_pyfast_for_hydrogen_SMR
sys.path.append('')
import warnings
warnings.filterwarnings("ignore")
import hopp_tools_steel
import hopp_tools

parent_path = os.path.abspath('')
dir1 = os.getcwd()
dirin_el_prices = 'examples/H2_Analysis/'
el_prices_files = glob.glob(os.path.join(dir1 + dirin_el_prices, 'annual_average_retail_prices.csv'))
renewable_cost_path = ('examples/H2_Analysis/green_steel_site_renewable_costs_ATB.xlsx')
fin_sum_dir = parent_path + '/examples/H2_Analysis/RODeO_financial_summary_results/'

lcoh_check_all = []
lcoh = []
years_all = []
sites_all = []
policy_all = []
NG_price_all = []
scenario = dict()
scenario['Wind PTC'] = 0.0
SMR_LCOH_dic = {'Year':[], 'Location':[], 'Policy': [], 'NG price case': [], 'LCOH':[], 'LCOA':[], 'LCOS':[]}

atb_years = [2020] #[2020,2025,2030,2035]

site_selection = [
'Site 1',
#'Site 2',
#'Site 3',
#'Site 4',
]

policy_cases = ['no policy','max']
#['no policy', 'base', 'max']

''' SMR doesn't get any of the policy options below:
'''
policy_option = {
'no policy': {'Wind ITC': 0, 'Wind PTC': 0, "H2 PTC": 0, 'Storage ITC': 0},
#'base': {'Wind ITC': 0, 'Wind PTC': 0.006, "H2 PTC": 0.6, 'Storage ITC': 6},
#'max': {'Wind ITC': 0, 'Wind PTC': 0.029, "H2 PTC": 3.0, 'Storage ITC': 50},
# 'max on grid hybrid': {'Wind ITC': 0, 'Wind PTC': 0.006, "H2 PTC": 0.60, 'Storage ITC': 6},
# 'max on grid hybrid': {'Wind ITC': 0, 'Wind PTC': 0.029, "H2 PTC": 0.60, 'Storage ITC': 50},
# 'option 3': {'Wind ITC': 6, 'Wind PTC': 0, "H2 PTC": 0.6},
# 'option 4': {'Wind ITC': 30, 'Wind PTC': 0, "H2 PTC": 3},
# 'option 5': {'Wind ITC': 50, 'Wind PTC': 0, "H2 PTC": 3},
}

NG_price_case = ['default']
CCS_options = ['wCCS','woCCS']

o2_heat_integration = 1

# Site specific turbine information
xl = pd.ExcelFile(renewable_cost_path)

scenario_df = xl.parse()
scenario_df.set_index(["Parameter"], inplace = True)

for atb_year in atb_years:
for site_location in site_selection:
for policy_case in policy_cases:
for CCS_option in CCS_options:
site_df = scenario_df[site_location]
site_name = site_df['State']
hydrogen_annual_production, hydrogen_storage_duration_hr, lcoh, lcoh_breakdown, lcoe, plant_life, natural_gas_cost,\
price_breakdown_storage,price_breakdown_compression,\
price_breakdown_SMR_plant,\
price_breakdown_SMR_FOM, price_breakdown_SMR_VOM,\
price_breakdown_taxes,\
price_breakdown_water_charges,\
remaining_financial = \
run_pyfast_for_hydrogen_SMR.run_pyfast_for_hydrogen_SMR(atb_year,site_name,policy_case,NG_price_case,CCS_option)

lime_unit_cost = site_df['Lime ($/metric tonne)'] + site_df['Lime Transport ($/metric tonne)']
carbon_unit_cost = site_df['Carbon ($/metric tonne)'] + site_df['Carbon Transport ($/metric tonne)']
iron_ore_pellets_unit_cost = site_df['Iron Ore Pellets ($/metric tonne)'] + site_df['Iron Ore Pellets Transport ($/metric tonne)']
steel_economics_from_pyfast, steel_economics_summary, steel_breakeven_price, steel_annual_production_mtpy,steel_price_breakdown = \
hopp_tools_steel.steel_LCOS_SMR(lcoh,hydrogen_annual_production,
lime_unit_cost,
carbon_unit_cost,
iron_ore_pellets_unit_cost,
lcoe, scenario, natural_gas_cost, o2_heat_integration)

cooling_water_cost = 0.000113349938601175 # $/Gal
iron_based_catalyst_cost = 23.19977341 # $/kg
oxygen_cost = 0.0285210891617726 # $/kg
ammonia_economics_from_pyfast, ammonia_economics_summary, ammonia_breakeven_price, ammonia_annual_production_kgpy,ammonia_price_breakdown = \
hopp_tools_steel.levelized_cost_of_ammonia_SMR(lcoh,hydrogen_annual_production,
cooling_water_cost,
iron_based_catalyst_cost,
oxygen_cost,
lcoe, scenario)


atb_year, lcoh = hopp_tools.write_outputs_PyFAST_SMR(fin_sum_dir,atb_year,
site_name,
lcoe,
lcoh,
hydrogen_storage_duration_hr,
hydrogen_annual_production,
price_breakdown_storage,price_breakdown_compression,
price_breakdown_SMR_plant,
price_breakdown_SMR_FOM, price_breakdown_SMR_VOM,
price_breakdown_taxes,
price_breakdown_water_charges,
remaining_financial,
steel_annual_production_mtpy,
steel_breakeven_price,
steel_price_breakdown,
ammonia_annual_production_kgpy,
ammonia_breakeven_price,
ammonia_price_breakdown,policy_case,CCS_option,o2_heat_integration)

Loading

0 comments on commit 1ff0589

Please sign in to comment.