-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from NREL/feature/green_steel_ammonia
Update feature/green_steel_ammonia branch
- Loading branch information
Showing
273 changed files
with
42,694 additions
and
1,126,007 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
Oops, something went wrong.