diff --git a/hopp/simulation/technologies/hydrogen/electrolysis/run_h2_PEM.py b/hopp/simulation/technologies/hydrogen/electrolysis/run_h2_PEM.py index 953149aba..547e553b9 100644 --- a/hopp/simulation/technologies/hydrogen/electrolysis/run_h2_PEM.py +++ b/hopp/simulation/technologies/hydrogen/electrolysis/run_h2_PEM.py @@ -3,7 +3,8 @@ import examples.H2_Analysis.H2AModel as H2AModel import numpy as np import pandas as pd -from hopp.simulation.technologies.hydrogen.electrolysis.run_PEM_master import run_PEM_clusters + +#from hopp.simulation.technologies.hydrogen.electrolysis.run_PEM_master import run_PEM_clusters def run_h2_PEM(electrical_generation_timeseries, electrolyzer_size, @@ -12,7 +13,7 @@ def run_h2_PEM(electrical_generation_timeseries, electrolyzer_size, use_degradation_penalty, grid_connection_scenario, hydrogen_production_capacity_required_kgphr ): - + from hopp.simulation.technologies.hydrogen.electrolysis.run_h2_PEM import run_PEM_clusters pem=run_PEM_clusters(electrical_generation_timeseries,electrolyzer_size,n_pem_clusters,electrolyzer_direct_cost_kw,useful_life,user_defined_pem_param_dictionary,use_degradation_penalty) if grid_connection_scenario!='off-grid': diff --git a/hopp/simulation/technologies/steel/README.md b/hopp/simulation/technologies/steel/README.md new file mode 100644 index 000000000..1a5199825 --- /dev/null +++ b/hopp/simulation/technologies/steel/README.md @@ -0,0 +1,181 @@ +## Intro + +The functions in this directory model green steel production. More specifically it models the mass/energy flows of a Hydrogen Direct Reduction Iron (HDRI) shaft and an Electric Arc Furnace (EAF) separately (The electrolyzer modeled in the example script but hopp results should replace the simple model). The results from the thermodynamic modeling are then used to make financial estimations on capital costs and operational costs. The basis of these models are from Abhinav Bhaskar's paper “Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." doi: https://doi.org/10.1016/j.jclepro.2022.131339. + +Author: Charles Kiefer +Date:8/31/2023 + +## How the code works + +Units are in the models. The main input for the code is steel_output_desired which is in kg/hr. The units commented throughout the model are in respect to kg/hr. It is possible to use units like tls/hr or tls, but it is not advised as the units may need to be tracked through to calculate locos. + +### Example run script + +The overview on how to use the code is found in example_steel_run_script.py. + +The first function is greensteel_run(): which identifies how to run the models and pull the individual data from each model. It is recommended that each class is given an instance variable. Then the model needed should be pulled from this variable. +For example: + +``` +eaf_model_instance = eaf_model() + +eaf_mass_outputs = eaf_model_instance.mass_model(steel_output_desired_kg_hr) + +eaf_energy_outputs = eaf_model_instance.energy_model(steel_output_desired_kg_hr) + +eaf_emission_outputs = eaf_model_instance.emission_model(steel_output_desired_kg_hr) + +eaf_financial_outputs = eaf_model_instance.financial_model(steel_out_year_tls) +``` + +The second function, h2_main_steel():, is how to use the models to calculate total costs and a method to calculate lcos. + +### Individual models + +Each plant is defined by a class. The classes are then broken into smaller models for the plant. The smaller models are a mass, energy and financial for both as well as an __init__. The HDRI class also holds the heater and recuperator (heat exchanger) model. The EAF holds an emission model. + +The models of HDRI and EAF have __init__ functions that hold all the assumptions needed for the plant. For example, all the needed temperatures of each stream are stored in the __init__. Financial assumptions are held here for each respective subsystem. Also, __init__ shows what is being calculated and the units for each calculation. + +The most common input of the models is steel_out_desired in kg/hr and steel_prod_yr in tls/yr. + +As well enthalpy_functions.py holds all the enthalpy formulas used to calculate the energy equation. + +### hdri_model.py + +The main model that drives is the mass_model. The mass_model takes steel_out_desired and determines how much hydrogen and iron ore is needed. Then it calculates the compositions of the outlets. There are 2 inlets and 2 outlets. The inlets are pure H2 gas and iron ore. The outlets are a H2/H2O stream and reduced iron. + +The energy_model runs the mass_model to gather the outlets and calculates the energy of the HDRI system using the enthalpy functions. This should always return a negative value. The negative value denotes heat is leaving the system. Mostly used as a check on the mass_model. + +The financial_model runs the mass_model with steel_prod_yr as the argument to determine yearly masses for materials. Capital cost is modeled from the yearly capacity of the plant and subsequently other costs are dependent on the capital cost. The costs calculated include capital, operational, maintenance, depreciation, iron ore, and labor. + +The recuperator_model runs the mass_model and energy_model to calculate masses and enthalpies to determine the enthalpy entering the heater. + +The last model is the heater_mass_energy_model. This model runs the mass_model and energy_model as well and calculates the needed energy to raise H2 gas to the set temp of the inlet stream. + +### eaf_model.py + +Very similar to hdri_model.py + +The driving model is the mass_model. the model takes in steel_out_desired and calculates all the masses of the primary inlets and outlets. It does not calculate the slag produced or the oxygen inputted into the EAF. The main inlet is the steel produced and the main inlets are iron, carbon and lime. The model calculates the actual steel output. There is about a 4.4% increase in steel produced as there is unintentional iron ore oxidation that in turn produces a higher mass. + +The energy_model uses the mass_model calculations to determine the energy needed. This model uses enthalpy_functions and uses an efficiency factor stored in the __init__. It returns kwh for steel output per hour as the units. The example script shows the conversion to get a value in kwh/year. + +The emission model pulls in the energy_model and the heater_mass_energy_model total energy values to calculate total direct emissions and indirect emissions. The indirect emissions are emissions from the energy pulled from the grid and are not usually paid for by the plant. + +The financial model does not need to pull in other models as the costs are all associated with the capacity of the plant which is the argument. The model calculates capital, operational, maintenance, depreciation, coal, lime, emission and labor costs. + +## Overview of Plant + +The main subsystems of the plant are the HDRI, EAF and Electrolyzer. At a high level, the main inputs of the plant are iron ore, carbon, water and electricity. + +### HDRI + +At a high level, the HDRI shaft converts iron ore (Fe2O3) into pure iron (Fe) using hydrogen gas (H2). The hydrogen gas combines with the oxygen in the iron ore and produces water in the form of steam. + +#### HDRI Detailed Level + +At a more detailed level, hydrogen gas enters the shaft at 1173 K. An electric heater and heat exchanger is used to achieve this temperature. Enthalpy functions are utilized to determine the amount of energy needed to heat up hydrogen gas. + +The main process of iron reduction in an HDRI-EAF system is the HDRI shaft. The two main producers of DRI systems are MIDREX and Energiron (International Iron Metallics Association n.d.). Each company has differences in their design, but the main reduction process is the same. Iron ore enters a shaft furnace and is reduced by a reducing agent. Reducing agents are substances, usually gases, that bond with the oxygen in the ore. Through this process, hematite (Fe2O3) reduces through many stages but finalizes itself as pure iron (Fe), also known as sponge iron. In an HDRI system, the reducing agent is hydrogen. The chemical reactions of hydrogen reduction can be seen in equations (3), (4) and (5) (Patisson and Mirgaux 2020). + +$Fe_2 O_3 + 3H_2 = 2Fe + 3H_2 O$ (3) + +$Fe_3 O_4 + 16/19 H_2 = 60/10 Fe_0.95 O + 16/19 H_2 O$ (4) + +$Fe_0.95 O + H_2 = .95Fe + H_2 O$ (5) + +Reduction rates with hydrogen are higher than that of carbon gas mixes. In addition, higher hydrogen temperatures and pressures lead to increased reduction rates (El-Geassy and Rajakumar 1985). The model in this report assumes that the hydrogen was not pressurized; it remains at atmospheric pressure. The temperature of the hydrogen is assumed to be at 1173 K. Work done previously exhibits that these parameters are satisfactory but can be more efficient (Sato, Ueda and Yasunori 1986). + +The model consists of two main inlets and two outlets. One inlet is iron ore which consists of hematite and impurities. These impurities can consist of many elements. Most of the impurities are other metallic oxides like CaO and SiO2. This model assumes that the impurities of the ore only consist of SiO2 and Al2O3. + +The other inlet in the model is the hydrogen. There is a stoichiometric amount required to reduce all the iron ore. However, a higher flow rate of hydrogen should be achieved as a buffer as some of the hydrogen will re-oxidize (Duarte and Pauluzzi 2019). To accommodate for this, the actual flow rate of the model is 20% higher than the stoichiometric requirement. + +The outlets in the system are the reduced iron ore and the exhaust of the hydrogen. The amount reduced iron is dependent on the metallization rate of the HDRI shaft. MIDREX shafts claim to have a metallization rate of 92%-96% (Midrex Technologies, Inc. 2018) (Sanjal 2015). This model assumes a metallization rate of 94% with a temperature 973 K. The exhaust consists of excess hydrogen and water, a product of reduction. The total mass of the water produced can be determined with the molecular weight ratios and mol ratios. It is assumed that all the stoichiometrically required hydrogen is consumed and the resulting temperature is 573 K. + +The following are additional assumptions of the HDRI system: + +• No heat loss in the reduced iron from the HDRI shaft to the EAF + +• Hydrogen apparent activation energy is 35 KJ/mol (Bhaskar, Mohsen and Homam, Decarbonization of the Iron and Steel Industry with Direct Reduction of Iron Ore with Green Hydrogen 2020) + +• 100% hydrogen is fed into the HDRI shaft + +• Iron Pellets are not preheated + +### EAF + +The EAF acts as the primary steelmaker in the production process. The concept of an EAF system is related to that of welding. Large electrodes in the EAF run high-voltage open currents between them generating large amount of heat. Most steel plants depend on the EAF to be the primary melting process. + +#### EAF Detailed View + +The reduced iron from the HDRI enters the EAF at a temperature of 973 K. The model assumes that there is no heat loss in the transition of HDRI Shaft and the EAF. Once in the furnace, the iron is heated to 1923 K and becomes molten. The molten stream leaves the furnace at the same temperature. + +Coke, lime, and oxygen are also added to the EAF to help reduce the FeO2, form a layer of slag, produce carbon-steel, and provide extra energy. The coke performs additional reduction in the EAF, contributing about 4.4% more steel. However, the model does not take the excess into account financially and turns it into a buffer to accommodate of 4.4% steel loss. Coke is also added to increase the carbon composition of the steel. + +The added lime is usually some sort of chemical compound containing calcium or magnesium and oxygen. It acts as a slag former as the calcium bonds with the impurities in the iron stream. This slag layer acts as an insulator, extracts unwanted impurities, and extends the electrode life (National Lime Association 2022). Slag leaves the system at a temperature of 1923 K. + +For sake of simplicity, the added energy from inputted oxygen, commonly known as oxyfuel, was not considered. The addition of oxyfuel would decrease the required electricity demand of the EAF and change the percent carbon in the steel. With these additions, there is unfortunately some sort of emissions produced. However, the emissions produced are extremely low compared to traditional routes. + +The main reactions in the EAF are the following (Hornby and Brooks 2021): + +$FeO + C = Fe + CO$ (4) + +$FeO + CO = Fe + CO_2$ (5) + +$Fe + 1/2 O_2 = FeO$ (6) + +These are the major reactions of most primary steel making processes. The secondary metallurgy process is where the composition of the steel is formed. Depending on the desired composition of the steel, other materials and elements are added into the ladle furnace. These can include the elements Si, Mn, P, S, Cr, Ni, Mo, and Cu (Camdali and Tunc 2016). These reactions look like the following (Yu, et al. 2021): + +Mn + O = MnO (7) + +Si + 2O = SiO_2 (8) + +This model did not take account in the secondary metallurgy process and subsequently these reactions. It is important to note the energy needed to facilitate these reactions varies depending on the desired compositions. Further work should be done to thermodynamically model the secondary metallurgy of each steel composition, but the scope of this work attains to a generalization of the EAF process. + +As mentioned earlier, the reactions of the coke, lime and oxygen were not thermodynamically modelled. Instead, assumptions were made on minor reactions in the EAF. The following assumptions are based off the assumptions Abhinav Bhaskar made in his work to determine validation (Bhaskar, Abhishek, et al. 2022). + +• 10 kg/tls of coke are injected + +• 50 kg/tls of lime are injected + +• 208 kg/tls of oxygen are injected + +• .113 tCO2/tls are generated + +Other assumptions of the EAF include: + +• No scrap involved, 100% pellet fed + +• 4.4% steel loss + +• EAF electrical efficiency is 60% + +### Electrolyzer + +Electrolyzer supplies the HDRI shaft with hydrogen and the EAF with oxygen. The HDRI model determines how much hydrogen is needed and then uses simple conversions to determine the amount of electricity and water required. + +## Sources + +Bhaskar, Abhinav, Assadi Mohsen, and Somehsaraei Nikpey Homam. 2020. "Decarbonization of the Iron and Steel Industry with Direct Reduction of Iron Ore with Green Hydrogen." Energies 13 (3): 758. doi: https://doi.org/10.3390/en13030758 + +Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + +Camdali, U., and M. Tunc. 2016. "Calculation of Chemical Reaction Energy in an Electric Arc Furnace and Ladle Furnace System." Metallurgist (9): 669-675. doi: https://doi.org/10.1007/s11015-016-0349-9 + +Duarte, Pablo, and Dario Pauluzzi. 2019. "Premium Quality DRI Products." https://www.energiron.com/wp-content/uploads/2019/07/Premium-Quality-DRI-Products-from-ENERGIRON.pdf + +El-Geassy, A.A., and V Rajakumar. 1985. "Gaseous Reduction of Wustite with H2, CO and CO Mixtures*." Trans. Iron Steel Institute Japan 25: 449-458. doi: https://doi.org/10.2355/isijinternational1966.25.449 + +Hornby, Sara, and Geoff Brooks. 2021. "Impact of Hydrogen DRI on EAF Steelmaking." Midrex: Iron and Steel Industry. https://www.midrex.com/tech-article/impact-of-hydrogen-dri-on-eaf-steelmaking/ + +International Iron Metallics Association. n.d. DRI Production. IIMA. Accessed July 26, 2022. https://www.metallics.org/dri-production.html. + +Midrex Technologies, Inc. 2018. "DRI Products + Applications: Providing flexibility for steelmaking." April. Accessed May 2, 2022. https://www.midrex.com/wp-content/uploads/MIdrexDRI_ProductsBrochure_4-12-18.pdf. + +National Lime Association. 2022. Lime Basics. National Lime Association. Accessed July 25, 2022. https://www.lime.org/lime-basics/uses-of-lime/metallurgical-uses-of-lime/iron-and-steel/. + +Ranzani da Costa, A, D Wagner, and F Patisson. 2013. "Modelling a new, low CO2 emissions, hydrogen steelmaking process." Journal of Cleaner Production 46: 27-35. doi: https://doi.org/10.48550/arXiv.1402.1715 + +Sanjal, Sujit. 2015. "The Value of DRI – Using the Product for Optimum Steelmaking." MIDREX. https://www.midrex.com/tech-article/the-value-of-dri-using-the-product-for-optimum-steelmaking/ + +Sato, Kyoji, Yoshinobu Ueda, and Nishikawa Yasunori. 1986. "Effect of Pressure on Reduction Rate of Iron Ore with High Pressure Fluidized Bed*." Trans. Iron Steel Institute Japan 26: 697-703. doi: https://doi.org/10.2355/isijinternational1966.26.697 \ No newline at end of file diff --git a/hopp/simulation/technologies/steel/eaf_model.py b/hopp/simulation/technologies/steel/eaf_model.py new file mode 100644 index 000000000..083fc294e --- /dev/null +++ b/hopp/simulation/technologies/steel/eaf_model.py @@ -0,0 +1,316 @@ +def establish_save_output_dict(): + """ + Establishes and returns a 'save_outputs_dict' dict + for saving the relevant analysis variables for each site. + """ + save_outputs_dict = dict() + + + save_outputs_dict['Steel Output Actual (kg)'] = list() + save_outputs_dict['Carbon Mass Needed (kg)'] = list() + save_outputs_dict['Lime Mass Needed (kg)'] = list() + save_outputs_dict['Energy needed for Electric Arc Furnance (kWh)'] = list() + save_outputs_dict['Total Indirect Emissions (Ton CO2)'] = list() + save_outputs_dict['Total Direct Emissions (Ton CO2)'] = list() + save_outputs_dict['Total Emissions (Ton CO2)'] = list() + save_outputs_dict['Shaft Total Capital Cost (Mil USD)'] = list() + save_outputs_dict['Shaft Operational Cost (Mil USD per year)'] = list() + save_outputs_dict['Shaft Maintenance Cost (Mil USD per year)'] = list() + save_outputs_dict['Shaft Depreciation Cost (Mil USD per year)'] = list() + save_outputs_dict['Total Carbon Cost (Mil USD per year)'] = list() + save_outputs_dict['Total Labor Cost (Mil USD per ton)'] = list() + save_outputs_dict['Total Emission Cost (Mil USD per year)'] = list() + save_outputs_dict['Total Lime Cost (Mil USD per year)'] = list() + + + return save_outputs_dict + + +class eaf_model(): + ''' + Author: Charles Kiefer + Date: 8/14/23 + + This class holds functions relating to the modeling of a Electronic Arc Furnace + in relation to the production of Green Steel. Pure iron, carbon and slime enter furnace, + steel and CO2 leave the system. The EAF acts a energy transfer method to allow for the energy + needed to embed carbon in iron + + Sources will be in each function + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + steel_prod_yr (ton/yr): (float) plant capacity steel produced per year. For financial outputs + + returns: + save_outputs_dict saves returns + + Steel Output Desired (kg): + ['Steel Output Actual (kg)']: + -Iron ore that wasn't reduced in the HDRI will reduce and become steel + + ['Carbon Mass Needed (kg)'] + ['Lime Mass Needed (kg)']: + -Lime is a slag former and binds with impurites in the iron to produce more pure steel + + ['Carbon Mass Not Absorbed (kg)']: + -Not all the carbon in the EAF will become steel. Excess Carbon will become CO2 + + ['Energy needed for Electric Arc Furnance (kWh)'] + ['Total Indirect Emissions (Ton CO2)']: + -Indirect emissions come from the grid emissions like coal plants and transportation + + ['Total Direct Emissions (Ton CO2)'] + ['Total Emissions (Ton CO2)'] + ['Shaft Total Capital Cost (Mil USD)'] + ['Shaft Operational Cost (Mil USD per year)'] + ['Shaft Maintenance Cost (Mil USD per year)'] + ['Shaft Depreciation Cost (Mil USD per year)'] + ['Total Carbon Cost (Mil USD per year)'] + ['Total Labor Cost (Mil USD per ton)'] + ['Total Emission Cost (Mil USD per year)'] + ['Total Lime Cost (Mil USD per year)'] + ''' + def __init__(self): + ''' + Initializes and stores needed data for functions relating to Electric Arc Furnace + for Green Steel + + Sources: + [1]: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + [2]: Chase, M.W., Jr. 1998. "NIST-JANAF Themochemical Tables, Fourth Edition." J. Phys. Chem. Ref. Data, Monograph 9 1-1951. doi:https://doi.org/10.18434/T4D303. + + ''' + self.eta_el = .6 #(%) electrical efficiency [1] + + self.stream_temp_in = 973 #(k) Temperature of metallic stream input eaf [1] + self.eaf_temp = 1923 #(k) Temperature metallic stream out. Temp needed to achieve [1] + + self.mass_carbon_tls = 10 #(kg/tls) [1] + self.mass_lime_tls = 50 #(kg/tls) [1] + + self.el_eaf = None #(kwh) + + self.eaf_co2 = 0.050 #ton/tls [1] + self.cao_emission = 0.056 #tco2/tls [1] + self.co2_eaf_electrode = 0.0070 #tco2/tls [1] + self.pellet_production = 0.12 #tco2/tls [1] + + self.steel_out_actual = None #(kg) + + self.hfe_melting = 247 #(kj/kg) Energy needed to melt iron into a liquid [1] + + self.indirect_emissions_total = None + self.direct_emissions_total = None + self.total_emissions = None + + self.lang_factor = 3 #(no units) Capital cost multiplier [1] + self.plant_life = 40 #(years) [1] + self.labor_cost_tls = 20 #(USD/ton/year) [1] $40 is flat rate for hdri and eaf together + self.eaf_total_capital_cost = None #(Million USD) + self.eaf_cost_per_ton_yr = 140 #(USD/tls/yr) + self.eaf_op_cost_tls = 32 #(USD/tls/yr of eaf) [1] + self.eaf_operational_cost_yr = None #(Million USD) + self.maintenance_cost_percent = .015 #(% of capital cost)[1] + self.eaf_maintenance_cost_yr = None #(Million USD) + self.depreciation_cost = None #(Million USD) + self.total_labor_cost_yr = None #(Million USD) + self.emission_cost = 30 #(USD/ton CO2) [1] + self.emission_factor = .413 #(ton CO2/kwh) [1] + self.carbon_cost_tls = 200 #(USD/ton coal) [1] + self.coal_total_cost_yr = None #(Mil USD/year) + self.lime_cost = 112 #(USD/ton lime) [1] + self.lime_cost_total = None #(USD/year) + + + def mass_model(self, steel_out_desired): + ''' + Mass model calculates the masses inputted and outputted of + an EAF system for output of tonne liquid steel + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + ''' + from hopp.simulation.technologies.steel.hdri_model import hdri_model + + model_instance = hdri_model() + hdri_mass_model_outputs = model_instance.mass_model(steel_out_desired) + + m3 = steel_out_desired #kg + + m2_feo = hdri_mass_model_outputs[2] + + m6 = self.mass_carbon_tls #kg/tls + m7 = self.mass_lime_tls #kg/tls + + self.carbon_total = m6*steel_out_desired/1000 #(kg) + self.lime_total = m7*steel_out_desired/1000 #(kg) + + m2_feo_reduced = (m2_feo*.7) #(kg) assumed 70% feo in EAF gets reduced + m3_actual = m2_feo_reduced + m3 #(kg) Actual steel outputted from excess iron oxidation + + self.steel_out_actual = m3_actual #(kg) + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Steel Output Actual (kg)'].append(self.steel_out_actual) + save_outputs_dict['Carbon Mass Needed (kg)'].append(self.carbon_total) + save_outputs_dict['Lime Mass Needed (kg)'].append(self.lime_total) + + return (save_outputs_dict, self.steel_out_actual, self.carbon_total, self.lime_total) + + def energy_model(self, steel_out_desired): + ''' + This function calculates the energy balance of the hdri EAF. Negative values designate + heat leaving the system. Positive values designate heat needs to enter the system. + + Energy belance values should be positive. + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + from hopp.simulation.technologies.steel.hdri_model import hdri_model + from hopp.simulation.technologies.steel.enthalpy_functions import fe_enthalpy, fe_enthalpy + + model_instance = hdri_model() + + hdri_mass_model_outputs = model_instance.mass_model(steel_out_desired) + + m2_fe = hdri_mass_model_outputs[1] + + + hfe_T2 = fe_enthalpy(self.stream_temp_in) #Enthalpy of DRI entering Eaf (kj/g) + hfe_T3 = fe_enthalpy(self.eaf_temp) #Enthalpy steel exiting EAF (kj/g) + h3 = ((hfe_T3 - hfe_T2)*m2_fe*1000) + (m2_fe*self.hfe_melting) #Total Enthalpy at output Kj + + h3_kwh = h3 / 3600 #(kwh) + + self.el_eaf = h3_kwh/self.eta_el #kwh + + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Energy needed for Electric Arc Furnance (kWh)'].append(self.el_eaf) + + return (save_outputs_dict,self.el_eaf) + + + + def emission_model(self, steel_out_desired): + ''' + This function models the emissions from the EAF. This incorporates direct and indirect emissions + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + from hopp.simulation.technologies.steel.hdri_model import hdri_model + + eaf_model.energy_model(self,steel_out_desired) + model_instance = hdri_model() + + el_heater = model_instance.heater_mass_energy_model(steel_out_desired)[1] + + indirect_emissions = ((self.el_eaf + el_heater)*self.emission_factor) #tco2 or tco2/hr + + direct_emissions = (self.eaf_co2 + self.cao_emission + self.co2_eaf_electrode + + self.pellet_production) #tco2/tls or tco2/hr/tls + + indirect_emissions_total = indirect_emissions #tco2 or tco2/hr + direct_emissions_total = direct_emissions*steel_out_desired/1000 #tco2 tco2/hr + + + self.indirect_emissions_total = indirect_emissions_total + self.direct_emissions_total = direct_emissions_total + self.total_emissions = self.indirect_emissions_total + self.direct_emissions_total + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Total Indirect Emissions (Ton CO2)'].append(self.indirect_emissions_total) + save_outputs_dict['Total Direct Emissions (Ton CO2)'].append(self.direct_emissions_total) + save_outputs_dict['Total Emissions (Ton CO2)'].append(self.total_emissions) + + return (save_outputs_dict,self.indirect_emissions_total, self.direct_emissions_total, self.total_emissions) + + + + + def financial_model(self, steel_prod_yr): + ''' + This function returns the financials for a rated capacity plant for EAF + + Args: + steel_prod_yr (ton/yr): (float) plant capacity steel produced per year. For financial outputs + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + + self.eaf_total_capital_cost = ((self.eaf_cost_per_ton_yr*steel_prod_yr)/10**6)*self.lang_factor #Mil USD + + self.eaf_operational_cost_yr = self.eaf_op_cost_tls*steel_prod_yr/10**6 #Mil USD per year + + self.eaf_maintenance_cost_yr = self.maintenance_cost_percent*self.eaf_total_capital_cost #Mil USD per year + + self.depreciation_cost = self.eaf_total_capital_cost/self.plant_life #Mil USD per year + + total_coal = self.mass_carbon_tls * steel_prod_yr/1000 #tonne coal + total_lime = self.mass_lime_tls * steel_prod_yr/1000 # tonne lime + + self.coal_total_cost_yr = (self.carbon_cost_tls * total_coal)/10**6 #(Mill USD per year) + + self.lime_cost_total = (self.lime_cost * total_lime)/10**6 + + self.total_labor_cost_yr = self.labor_cost_tls*steel_prod_yr/10**6 + + direct_emissions_tls = (self.eaf_co2 + self.cao_emission + self.co2_eaf_electrode + + self.pellet_production) #tco2/tls + + direct_emissions_yr = direct_emissions_tls * steel_prod_yr/10**6 + + self.total_emission_cost = direct_emissions_yr * self.emission_cost + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Shaft Total Capital Cost (Mil USD)'].append(self.eaf_total_capital_cost) + save_outputs_dict['Shaft Operational Cost (Mil USD per year)'].append(self.eaf_operational_cost_yr) + save_outputs_dict['Shaft Maintenance Cost (Mil USD per year)'].append(self.eaf_maintenance_cost_yr) + save_outputs_dict['Shaft Depreciation Cost (Mil USD per year)'].append(self.depreciation_cost) + save_outputs_dict['Total Carbon Cost (Mil USD per year)'].append(self.coal_total_cost_yr) + save_outputs_dict['Total Labor Cost (Mil USD per ton)'].append(self.total_labor_cost_yr) + save_outputs_dict['Total Lime Cost (Mil USD per year)'].append(self.lime_cost_total) + save_outputs_dict['Total Emission Cost (Mil USD per year)'].append(self.total_emission_cost) + + + return (save_outputs_dict, self.eaf_total_capital_cost, self.eaf_operational_cost_yr, self.eaf_maintenance_cost_yr, + self.depreciation_cost, self.coal_total_cost_yr, self.total_labor_cost_yr, self.lime_cost_total, + self.total_emission_cost) + + + +if __name__ == '__main__': + model_instance = eaf_model() + + steel_output_desired = 1000 #(kg or kg/hr) + + mass_outputs = model_instance.mass_model(steel_output_desired) + energy_outputs = model_instance.energy_model(steel_output_desired) + emission_outputs = model_instance.emission_model(steel_output_desired) + + steel_output_desired_yr = 2000000 #(ton/yr) + + financial_outputs = model_instance.financial_model(steel_output_desired_yr) + + + diff --git a/hopp/simulation/technologies/steel/enthalpy_functions.py b/hopp/simulation/technologies/steel/enthalpy_functions.py new file mode 100644 index 000000000..d8c255504 --- /dev/null +++ b/hopp/simulation/technologies/steel/enthalpy_functions.py @@ -0,0 +1,296 @@ +## Functions to calculate enthalpy of different streams + +### Hydrogen enthalpy coefficients +# The value of enthalpy returned is the specific enthalpy in kj/g +''' +Author: Charlie Kiefer +Date: 8/14/23 + +These functions calculate enthalpies of elements relating to green steel + +Sources: +Chase, M.W., Jr. 1998. "NIST-JANAF Themochemical Tables, Fourth Edition." J. Phys. Chem. Ref. Data, Monograph 9 1-1951. doi:https://doi.org/10.18434/T4D303. + Thermochemistry tab of each element + +Inputs: + T: Temperature of the element (K) + +Outputs: + H_t: Enthalpy of element at given temp (kj/g) +''' + +def h2_enthalpy(T): + mol_weight_H2=2.01588 #in grams# T1 and T2 should be in the range of 298-1000 K
+ if T < 298 or T > 2500: + raise ValueError(f"Inputted temperatute {T} for hydrogen gas is out of range of 298-2500 K") + + if T < 1000: #h2_1 # T1 and T2 should be in the range of 298-1000 K
+ t=T/1000 + A=33.066718 + B=-11.363417 + C=11.432816 + D=-2.772874 + E=-0.158558 + F=-9.980797 + G=172.707974 + H=0 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_H2 + + elif T >= 1000: #h2_2 #T in range 1000-2500 K + t=T/1000 + A=18.563083 + B=12.257357 + C=-2.859786 + D=0.268238 + E=1.977990 + F=-1.147438 + G=156.288133 + H=0 + H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_H2 + + return H_t + +#def h2_enthalpy_2(T): + #mol_weight_H2=2.01588#T in range 1000-2500 K + #t=T/1000 + #A=18.563083 + #B=12.257357 + #C=-2.859786 + #D=0.268238 + #E=1.977990 + #F=-1.147438 + #G=156.288133 + #H=0 + #H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_H2 + #return H_t +### Water enthalpy coefficients + +def h2o_enthalpy(T): # 500-1700 + + if T < 298 or T > 1700: + raise ValueError(f"Inputted temperatute {T} for H2O steam is out of range of 298-6000 K") + + mol_weight_H2O=18.0153 + + if T >=500: + t=T/1000 + A=30.09200 + B=6.832514 + C=6.793435 + D=-2.534480 + E=0.082139 + F=-250.8810 + G=223.3967 + H=-241.8264 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_H2O + + elif T < 500: + t=T/1000 + A=-203.6060 + B=1523.290 + C=-3196.413 + D=2474.455 + E=3.855326 + F=-256.5478 + G=-488.7163 + H=-285.8304 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_H2O + + return H_t + + + +def fe_enthalpy(T):#298-1809 K + mol_weight_fe=55.845 #in grams + + if T < 298 or T > 3133: + raise ValueError(f"Inputted temperatute {T} for iron is out of range of 298-3133 K") + + if T < 1809: #fe_1 298-1809 K + t=T/1000 + A=23.97449 + B=8.367750 + C=0.000277 + D=-0.000088 + E=-0.000005 + F=0.268027 + G=62.06336 + H=7.788015 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_fe + + elif T >= 1809: #fe_2 1809 - 3133K + t=T/1000 + A=46.02400 + B=-1.88467*10**(-8) + C=6.094750*10**(-9) + D=-6.640301*10**(-10) + E=-0.8246121*10**(-9) + F=-10.80543 + G=72.54094 + H=12.39052 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_fe + + return H_t + +#def fe_enthalpy_2(T):#1809 - 3133K + #mol_weight_fe=55.845 #in grams + #t=T/1000 + #A=46.02400 + #B=-1.88467*10**(-8) + #C=6.094750*10**(-9) + #D=-6.640301*10**(-10) + #E=-0.8246121*10**(-9) + #F=-10.80543 + #G=72.54094 + #H=12.39052 + #H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_fe + #return H_t + +def feo_enthalpy(T): + if T < 298 or T > 1650: + raise ValueError(f"Inputted temperatute {T} for methane gas is out of range of 298-6000 K") + + + mol_weight_feo=71.844 #in grams 298-1650 + t=T/1000 + A=45.75120 + B=18.78553 + C=-5.952201 + D=0.852779 + E=-0.081265 + F=-286.7429 + G=110.3120 + H=-272.0441 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_feo + return H_t + +def al2o3_enthalpy(T): + if T < 298 or T > 2327: + raise ValueError(f"Inputted temperatute {T} for Al2O3 is out of range of 298-2327 K") + + mol_weight_al2o3=101.9613 #in grams 298-2327 + t=T/1000 + A=106.0880 + B=36.33740 + C=-13.86730 + D=2.141221 + E=-3.133231 + F=-1705.970 + G=153.9350 + H=-1662.300 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_al2o3 + return H_t + +def sio2_enthalpy(T): + if T < 847 or T > 1996: + raise ValueError(f"Inputted temperatute {T} for SiO2 is out of range of 847-1996 K") + + mol_weight_Sio2=60.0843 #in grams 847-1996 + t=T/1000 + A=58.75 + B=10.279 + C=-0.131384 + D=0.025210 + E=0.025601 + F=-929.3292 + G=105.8092 + H=-910.8568 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_Sio2 + return H_t + +def mgo_enthalpy(T): + if T < 298 or T > 3105: + raise ValueError(f"Inputted temperatute {T} for MgO is out of range of 298-3105 K") + + mol_weight_mgo=40.3044 #in grams 298-3105 + t=T/1000 + A=47.25995 + B=5.681621 + C=-0.872665 + D=0.104300 + E=-1.053955 + F=-619.1316 + G=76.46176 + H=-601.2408 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_mgo + return H_t + +def cao_enthalpy(T): + if T < 298 or T > 3200: + raise ValueError(f"Inputted temperatute {T} for CaO is out of range of 298-3200 K") + + mol_weight_cao=56.077#in grams 298-3200 + t=T/1000 + A=49.95403 + B=4.887916 + C=-0.353056 + D=0.046187 + E=-0.825097 + F=-652.9718 + G=92.56096 + H=-635.0894 + H_t=(A*t +(B*t*t)/2 +(C*t*t*t)/3 + (D*t*t*t*t)/4-(E/t)+F-H)/mol_weight_cao + return H_t + +def ch4_enthalpy(T):# T in the range 298-1000 K + mol_weight_CH4=16.04 # in grams + if T < 298 or T > 6000: + raise ValueError(f"Inputted temperatute {T} for methane gas is out of range of 298-6000 K") + + if T <= 1000: #1 298-1300 K + t=T/1000 + A=-0.703029 + B=108.4773 + C=-42.52157 + D=5.862788 + E=0.678565 + F=-76.84376 + G=158.7163 + H=-74.87310 + H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_CH4 + + elif T >1300: #2 1300-6000 K + t=T/1000 + A=85.81217 + B=11.26467 + C=-2.114146 + D=0.138190 + E=-26.42221 + F=-153.5327 + G=224.4143 + H=-74.87310 + H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_CH4 + + return H_t + +#def ch4_enthalpy_2(T):# T in range 1300-6000 K + #mol_weight_CH4=16.04 # in grams + #t=T/1000 + #A=85.81217 + #B=11.26467 + #C=-2.114146 + #D=0.138190 + #E=-26.42221 + #F=-153.5327 + #G=224.4143 + #H=-74.87310 + #H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_CH4 + #return H_t + +def c_enthalpy(T):# T in the range 298-1000 K + if T < 298 or T > 1000: + raise ValueError(f"Inputted temperatute {T} for C is out of range of 298-1000 K") + + mol_weight_C=12.017 # in grams + t=T/1000 + A=21.17510 + B=-0.812428 + C=0.448537 + D=-0.043256 + E=-0.013103 + F=710.3470 + G=183.8734 + H=716.6690 + H_t=(A*t +(B*t**2)/2 +(C*t**3)/3 + (D*t**4)/4-(E/t)+F-H)/mol_weight_C + return H_t# The value of enthalpy returned is the specific enthalpy in kj/g + \ No newline at end of file diff --git a/hopp/simulation/technologies/steel/example_steel_run_script.py b/hopp/simulation/technologies/steel/example_steel_run_script.py new file mode 100644 index 000000000..664aa8465 --- /dev/null +++ b/hopp/simulation/technologies/steel/example_steel_run_script.py @@ -0,0 +1,657 @@ +from hopp.simulation.technologies.steel.eaf_model import eaf_model +from hopp.simulation.technologies.steel.hdri_model import hdri_model + + +#from csv import writer +import os +#from dotenv import load_dotenv +import pandas as pd + +from hopp.simulation.technologies.sites import SiteInfo +from hopp.simulation.technologies.sites import flatirons_site as sample_site +#from hopp.utilities.keys import set_developer_nrel_gov_key +#from examples.H2_Analysis.plot_reopt_results import plot_reopt_results +from examples.H2_Analysis.run_reopt import run_reopt +from examples.H2_Analysis.hopp_for_h2 import hopp_for_h2 +from examples.H2_Analysis.run_h2a import run_h2a as run_h2a +#from examples.H2_Analysis.simple_dispatch import SimpleDispatch +#import hopp.simulation.technologies.hydrogen.electrolysis.run_h2_PEM as run_h2_PEM +import numpy as np +#import numpy_financial as npf +#from lcoe.lcoe import lcoe as lcoe_calc +#import matplotlib.pyplot as plt +import warnings +#from pathlib import Path +warnings.filterwarnings("ignore") + +def greensteel_run(steel_output_desired_kg_hr=120160): + ''' + This function is an example of how to run the steel functions from eaf_model and hdri_model + + The main argument for most of the functions is steel_output_desired. + The argument needs to be in kg or kg/hr. It is recommended that a rate is + used (kg/hr) as the financials are dependent on capacity (metric ton liquid steel (tls) per year). + + Sources are in the functions + + Notes: Most steel plants run 95% of the year so the yearly hours would be 24*365*.95 + 1000 kg are in 1 metric ton + (tls) stands for tonne liquid steel + (tco2) is metric tonne of CO2 + Electric efficiency for system was assumed to be 60% + + EAF Notes: + + The steel carbon rating for this is low-carbon steel with a .07% carbon composition. Similar to that of rebar + Carbon composition is the mass of the of the carbon compare to the total mass of the steel. + In most steel plants, secondary finishing process are used to achieve higher compositions. + These processes are not modeled in this. + + Lime is a composition of moslty Silica and Magnesium oxide that bonds with impurities in the iron. + The result is slag. Slag can be used in other industiral processes like cement bases. + + HDRI: Notes + + Not all the iron ore is reduced in the HDRI shaft. Abut 95-97% of the iron ore is reduced. + + More H2 is needed than stoichiometrically required. H2 gas can be captured in the exhaust gas and + reused into the input gas. The exhaust steam could also be captured and sent back to the electrolyzer. + + Energy balance on the shaft should be negative meaning that heat is leaving the system and not being absorbed. + If values are positive, heat will need to be inputted into the shaft. Values should not be positive. Energy needed + should be supplied by the heater. + + The recuperator is the heat exhanger between the exhaust gas and input h2. Not required but is a efficiency + system. + ''' + hours = 365*24*.95 + + steel_out_year_tls = steel_output_desired_kg_hr * hours / 1000 + + eaf_model_instance = eaf_model() + hdri_model_instance = hdri_model() + + + eaf_mass_outputs = eaf_model_instance.mass_model(steel_output_desired_kg_hr) + eaf_energy_outputs = eaf_model_instance.energy_model(steel_output_desired_kg_hr) + eaf_emission_outputs = eaf_model_instance.emission_model(steel_output_desired_kg_hr) + eaf_financial_outputs = eaf_model_instance.financial_model(steel_out_year_tls) + + hdri_mass_outputs = hdri_model_instance.mass_model(steel_output_desired_kg_hr) + hdri_energy_outputs = hdri_model_instance.energy_model(steel_output_desired_kg_hr) + recuperator_outputs = hdri_model_instance.recuperator_mass_energy_model(steel_output_desired_kg_hr) + heater_outputs = hdri_model_instance.heater_mass_energy_model(steel_output_desired_kg_hr) + hdri_financial_outputs = hdri_model_instance.financial_model(steel_out_year_tls) + + + ''' + EAF model outputs + ''' + print(eaf_mass_outputs[0]) #Prints Dict list of outputs of the function with units + print(eaf_energy_outputs[0]) #Prints Dict list of outputs of the function with units + print(eaf_emission_outputs[0]) #Prints Dict list of outputs of the function with units + print(eaf_financial_outputs[0]) #Prints Dict list of outputs of the function with units + + steel_out_actual_kg = eaf_mass_outputs[1] #(kg or kg/hr) Iron ore will also reduce in EAF so more steel is produced/ + # Will produce 4% more than desired can be used as buffer for 4% steel loss. + + carbon_needed = eaf_mass_outputs[2] #(kg or kg/hr) This is the required carbon needed to create low-carbon steel + + lime_needed = eaf_mass_outputs[3] #(kg or kg/hr) This is the required lime/slag formers needed + + + electricity_needed = eaf_energy_outputs[1] #(kwh or kw) This is the energy needed in the furnace + #The units depend on the steel_desired units + #Input of kg returns kwh//Input of kg/hr returns kw + + + indirect_emissions = eaf_emission_outputs[1] #(tco2 or tco2/hr) Indirect emissions from the grid of the entire system + # Units are dependent on steel_out units (kg -> tco2, kg/hr -> tco2/hr) + # Includes heater in hdri and eaf eletric arc + #If plant is run solely on renewables, this would be 0 + + direct_emissions = eaf_emission_outputs[2] #(tco2 or tco2/hr) These are emissions directly from the EAF. + #Units are dependent on steel_out units (kg -> tco2, kg/hr -> tco2/hr). + #This includes the excess carbon turning into CO2, the CaO emissions, + # the CO2 given off by the EAF electrode and the iron ore pellet production + #Iron pellet production commonly uses fossil fuel to compact the iron ore into pellets + + total_emissions = eaf_emission_outputs[3] #(tco2 or tco2/hr) Total emissions includes direct and indirect + #Units are dependent on steel_out units (kg -> tco2, kg/hr -> tco2/hr) + + + eaf_capital_cost = eaf_financial_outputs[1] #(Mil USD) Capital cost uses a lang factor of 3. + #Estimated using capital cost rate of $140 USD/tls/yr + + eaf_operation_cost = eaf_financial_outputs[2] #(Mil USD/yr) Estimated using operational cost of $32 USD/tls/yr + + eaf_maintenance_cost = eaf_financial_outputs[3] #(Mil USD/yr) Estimated using a percentage of 1.5% of total Capital cost + + eaf_depreciation_cost = eaf_financial_outputs[4] #(Mil USD/yr) Total Capital cost divided by the plant life(40 years) + + eaf_coal_cost = eaf_financial_outputs[5] #(Mil USD/yr) Total cost of the coal needed for desired capacity + #coal cost rate is assumed $120/ton coal + + eaf_labor_cost = eaf_financial_outputs[6] #(Mil USD/yr) Total labor cost needed for desired capacity + #Labor cost rate assumed $20 USD/year + + eaf_lime_cost = eaf_financial_outputs[7] #(Mil USD/yr) Total lime cost needed for desired capacity + + eaf_total_emission_cost = eaf_financial_outputs[8] #(Mil USD/yr) Emissions multiplied by emissions cost + #Emission cost assumed to be $30 USD/tco2 + #Currently no emission costs in states that hold steel plants + + ''' + hdri model outputs + ''' + print(hdri_mass_outputs[0]) #Prints Dict of outputs of the function with units + print(hdri_energy_outputs[0]) #Prints Dict of outputs of the function with units + print(recuperator_outputs[0]) #Prints Dict of outputs of the function with units + print(heater_outputs[0]) #Prints Dict of outputs of the function with units + print(hdri_financial_outputs[0]) #Prints Dict of outputs of the function with units + + steel_out_desired = hdri_mass_outputs[3] #(kg or kg/hr) Should return inputted arg + + iron_ore_mass = hdri_mass_outputs[4] #(kg or kg/hr) Iron ore needed for desired_steel_out + + mass_h2_in = hdri_mass_outputs[5] #(kg or kg/hr) Mass of hydrogen gas needed to reduce the iron ore in + + mass_h2_out = hdri_mass_outputs[6] #(kg or kg/hr) Mass of hydrogen leaving shaft + + mass_h2o_out = hdri_mass_outputs[7] #(kg or kg/hr) Mass of water (steam) leaving shaft + + mass_pure_iron_out = hdri_mass_outputs[8] #(kg or kg/hr) Mass of the pure iron in stream leaving shaft + + mass_gas_stream_out = hdri_mass_outputs[9] #(kg or kg/hr) mass of the gas steam leaving + + mass_iron_ore_out = hdri_mass_outputs[10] #(kg or kg/hr) mass of iron ore leaving shaft + + + energy_balance = hdri_energy_outputs[1] #(kwh or kw) Energy balance of the hdri shaft (Negative denotes heat leaving system) + + + heater_electricity_needed = heater_outputs[1] #(kwh or kw) Electricity needed by the heater to heat hydrogen to needed temp to reduce iron + + + enthalpy_entering_heater = recuperator_outputs[1] #(kwh or kw) Enthalpy of the hydrogen entering heater from recuperator + + + hdri_capital_cost = hdri_financial_outputs[1] #(Mil USD) Capital cost uses a lang factor of 3. + #Estimated using capital cost rate of $80 USD/tls/yr + + hdri_operation_cost = hdri_financial_outputs[2] #(Mil USD/yr) Estimated using operational cost of $13 USD/tls/yr + + hdri_maintenance_cost = hdri_financial_outputs[3] #(Mil USD/yr) Estimated using a percentage of 1.5% of total Capital cost + + hdri_depreciation_cost = hdri_financial_outputs[4] #(Mil USD/yr) Total Capital cost divided by the plant life(40 years) + + iron_ore_cost = hdri_financial_outputs[5] #(Mil USD/yr) Total iron ore cost needed for desirec steel output per year + + hdri_labor_cost = hdri_financial_outputs[6] #(Mil USD/yr) Total labor cost needed for desired capacity + #Labor cost rate assumed $20 USD/year + + print('Iron ore mass',iron_ore_mass/steel_out_desired) + print('Lime Mass',lime_needed/steel_out_actual_kg) + print('Carbon Mass need',carbon_needed/steel_out_desired) + print('H2 needed',mass_h2_in/steel_out_desired) + print('Electricity',electricity_needed/1000) + print('Cap Cost Eaf',eaf_capital_cost) + print('Cap Cost HDRI',hdri_capital_cost) + print('Labor Cost',(eaf_labor_cost+hdri_labor_cost)) + print('Maintenance Cost',(eaf_maintenance_cost+hdri_maintenance_cost)) + return + +import os +from dotenv import load_dotenv +import pandas as pd +import json +from hopp.simulation.technologies.sites import SiteInfo +from hopp.simulation.technologies.sites import flatirons_site as sample_site +from hopp.utilities.keys import set_developer_nrel_gov_key +#from examples.H2_Analysis.plot_reopt_results import plot_reopt_results +#from examples.H2_Analysis.run_reopt import run_reopt +#from examples.H2_Analysis.hopp_for_h2 import hopp_for_h2 +from examples.H2_Analysis.run_h2a import run_h2a as run_h2a +#from examples.H2_Analysis.simple_dispatch import SimpleDispatch +#import hopp.simulation.technologies.hydrogen.electrolysis.run_h2_PEM as run_h2_PEM +import numpy as np +#import numpy_financial as npf +from lcoe.lcoe import lcoe as lcoe_calc +#import matplotlib.pyplot as plt +import warnings +#from pathlib import Path +warnings.filterwarnings("ignore") + +# Set API key +load_dotenv() +NREL_API_KEY = os.getenv("NREL_API_KEY") +set_developer_nrel_gov_key(NREL_API_KEY) # Set this key manually here if you are not setting it using the .env + + + +def h2_main_steel(lcoe=.5612,steel_output_desired=120160,efficiency=.67,MW_h2=.6,lang_factor=3,elec_spec=55.5,discount_rate=.10,lifetime=40): + """ + Example of how to call in steel models to calculate lcos (Levelized Cost of Steel) + + Electrolyzer costs should be brought in from hopp. Electrolyzer financials are calculated using simple assumptions + + Assumes constant electrical input + + Inputs: + -lcoe: levelized cost of electricity entering plant (cents/kwh) + -steel_output_desired: steel output a day (kg/day) 1 million tonnes per year is about 120160 kg/day + -efficiency: electrical efficiency of the electrolyzer (%) + -lang_factor: factor of capital costs to estimate construction and auxilliary processes + -elec_spec: specification of electrolyzer i.e. how many kilowatthours to produce 1 kilogram h2(kwh/kgh2) + -discount_rate: (%) + -lifetime: lifetime of plant (years) + """ + + + # Step 1: Establish output structure and special inputs + # save_all_runs = pd.DataFrame() + #save_outputs_dict = establish_save_output_dict() + year = 2013 + sample_site['year'] = year + useful_life = 30 + critical_load_factor_list = [1] + run_reopt_flag = False + custom_powercurve = True + storage_used = True + battery_can_grid_charge = False + grid_connected_hopp = False + interconnection_size_mw = 100 + electrolyzer_sizes = [50] + + + + eaf_model_instance = eaf_model() + hdri_model_instance = hdri_model() + + #lcoe = .5612 + + #steel_output_desired = 120160 #kg/hr or tls/hr + + energy_kwh = eaf_model_instance.energy_model(steel_output_desired) + energy_mwh = eaf_model_instance.energy_model(steel_output_desired)[1]/1000 + + lcoe_cents_kwh = lcoe + + lcoe_USDMWH = lcoe * 100 + + + #total_electricity_cost = energy_mwh * lcoe_USDMWH + + + steel_output_desired_kg_hr = steel_output_desired + hours = 365*24*.95 #hours plant runs of the time + + h2_kg_hr = hdri_model_instance.mass_model(steel_output_desired_kg_hr)[5] + + steel_out_year_tls = steel_output_desired_kg_hr * hours / 1000 #(tls/yr) + h2_yr = h2_kg_hr*365*24*.95 #(kg h2/year) + + eaf_mass_outputs = eaf_model_instance.mass_model(steel_output_desired_kg_hr) + eaf_energy_outputs = eaf_model_instance.energy_model(steel_output_desired_kg_hr) + eaf_emission_outputs = eaf_model_instance.emission_model(steel_output_desired_kg_hr) + eaf_financial_outputs = eaf_model_instance.financial_model(steel_out_year_tls) + + hdri_mass_outputs = hdri_model_instance.mass_model(steel_output_desired_kg_hr) + hdri_energy_outputs = hdri_model_instance.energy_model(steel_output_desired_kg_hr) + recuperator_outputs = hdri_model_instance.recuperator_mass_energy_model(steel_output_desired_kg_hr) + heater_outputs = hdri_model_instance.heater_mass_energy_model(steel_output_desired_kg_hr) + hdri_financial_outputs = hdri_model_instance.financial_model(steel_out_year_tls) + + ''' + Way to incorporate hopp electrolyzer financials + ''' + #from hopp.simulation.technologies.hydrogen.electrolysis.H2_cost_model import basic_H2_cost_model + + #electrolyzer_capex_kw = 1100 #(USD/kw) + #time_between_replacement = 40000 #(hours) + #electrolyzer_size_mw = electrolyzer_capacity + #electrical_generation_timeseries_kw = electrical_generation_timeseries + #hydrogen_annual_output = h2_yr + #PTC_USD_kg = .60 + #ITC_perc = 0 + #plant_life = 40 + + #electrolyzer_costs = basic_H2_cost_model(electrolyzer_capex_kw,time_between_replacement,electrolyzer_size_mw, + # plant_life, atb_year,electrical_generation_timeseries_kw, hydrogen_annual_output, PTC_USD_kg, + # ITC_perc, False, 0) + + #electrolyzer_capital_cost = electrolyzer_costs[1] + #electrolyzer_OM_cost = electrolyzer_costs[2] + + + ''' + Capital Cost for plant + ''' + #lang_factor = 3 + + hdri_capital_cost = hdri_financial_outputs[1] #(Mil USD) Capital cost uses a lang factor of 3. + #Estimated using capital cost rate of $80 USD/tls/yr + eaf_capital_cost = eaf_financial_outputs[1]#(Mil USD) Capital cost uses a lang factor of 3. + #Estimated using capital cost rate of $140 USD/tls/yr + + + lhv_h2 = 120.1 #Mj/kg h2 low heating value for hydrogen gas + h2_kg_s = h2_yr/(365*24*60*60*.95) #kg/s + #efficiency = .67 #% + + electrolyzer_capacity = h2_kg_s*lhv_h2*efficiency #MW + + #MW_h2 = .6 #Mil USD/MW electrolyzer + + electrolyzer_cap_cost = electrolyzer_capacity * MW_h2 * lang_factor #(Mil USD) + + total_cap_cost_MilUSD = (hdri_capital_cost + eaf_capital_cost + electrolyzer_cap_cost) + total_cap_cost = (hdri_capital_cost + eaf_capital_cost + electrolyzer_cap_cost)*10**6 #USD + + ''' + Operational Costs for plant + ''' + + hdri_operation_cost = hdri_financial_outputs[2] #(Mil USD/yr) Estimated using operational cost of $13 USD/tls/yr + hdri_maintenance_cost = hdri_financial_outputs[3] #(Mil USD/yr) Estimated using a percentage of 1.5% of total Capital cost + hdri_depreciation_cost = hdri_financial_outputs[4] #(Mil USD/yr) Total Capital cost divided by the plant life(40 years) + iron_ore_cost = hdri_financial_outputs[5] #(Mil USD/yr) Total iron ore cost needed for desirec steel output per year + hdri_labor_cost = hdri_financial_outputs[6] #(Mil USD/yr) Total labor cost needed for desired capacity + + + total_hdri_operating_cost = (hdri_operation_cost + hdri_maintenance_cost + hdri_depreciation_cost + +iron_ore_cost+hdri_labor_cost)*10**6#(USD) + + eaf_operation_cost = eaf_financial_outputs[2] #(Mil USD/yr) Estimated using operational cost of $32 USD/tls/yr + eaf_maintenance_cost = eaf_financial_outputs[3] #(Mil USD/yr) Estimated using a percentage of 1.5% of total Capital cost + eaf_depreciation_cost = eaf_financial_outputs[4] #(Mil USD/yr) Total Capital cost divided by the plant life(40 years) + eaf_coal_cost = eaf_financial_outputs[5] #(Mil USD/yr) Total cost of the coal needed for desired capacity + #coal cost rate is assumed $120/ton coal + eaf_labor_cost = eaf_financial_outputs[6] #(Mil USD/yr) Total labor cost needed for desired capacity + #Labor cost rate assumed $20 USD/year + eaf_lime_cost = eaf_financial_outputs[7] #(Mil USD/yr) Total lime cost needed for desired capacity + eaf_total_emission_cost = eaf_financial_outputs[8] #(Mil USD/yr) Emissions multiplied by emissions cost + #Emission cost assumed to be $30 USD/tco2 + #Currently no emission costs in states that hold steel plants + + + total_eaf_operating_cost = (eaf_operation_cost + eaf_depreciation_cost + eaf_maintenance_cost + eaf_coal_cost + eaf_labor_cost + + eaf_lime_cost + eaf_total_emission_cost)*10**6 #(USD/yr) + + + #h2_yr = h2*365*24*.95 #(kg h2/year) + + water_cost_USD_kg = .59289/1000 #(USD/kg) + water_yr = h2_yr * 11 #(kg h20/yr)11 kg water for 1 kg h2 + water_cost = water_yr * water_cost_USD_kg #(USD/yr) + + total_electrolyzer_operating_cost = water_cost + + ''' + Electricity costs for Plant + ''' + + eaf_electricity_needed = eaf_energy_outputs[1] #(kwh or kw)/yr This is the energy needed in the furnace kwh need per input tls + #The units depend on the steel_desired units + #Input of kg returns kwh//Input of kg/hr returns kw + heater_electricity_needed = heater_outputs[1] #(kwh or kw) Electricity needed by the heater to heat hydrogen to needed temp to reduce iron + + eaf_electricity_needed_mwh = eaf_electricity_needed/1000 #mwh needed for input steel in tls per day + eaf_electricity_needed_mwh_yr = eaf_electricity_needed_mwh*24*365 #mwh needed for input steel in tls per year + + + heater_electricity_needed_mwh = heater_electricity_needed/1000 #mwh needed for input steel in tls per day + heater_electricity_needed_mwh_yr = heater_electricity_needed_mwh*24*365 #mwh needed for input steel in tls per year + + ''' + Checks. Returns steel output per year + ''' + #check_1 = heater_electricity_needed_mwh_yr*1000/355 + #check_2 = eaf_electricity_needed_mwh_yr*1000/501.315 + + + #elec_spec = 55.5 #kwh/kgh2 + electrolyzer_electricity_needed = elec_spec * h2_yr/1000 #(mwh/yr) + + total_electricity_mwh = heater_electricity_needed_mwh_yr+eaf_electricity_needed_mwh_yr+electrolyzer_electricity_needed #(mwh/yr) + + total_electricity_cost = total_electricity_mwh * lcoe_USDMWH #(USD/yr) + + ''' + Total Annual Operating Costs consist of HDRI, EAF, Electrolyzer operating costs and the total electricity used by all three subsystems + ''' + + annual_operating_cost = (total_hdri_operating_cost + total_eaf_operating_cost + total_electrolyzer_operating_cost + total_electricity_cost) #(USD/yr) + + annual_operating_cost_MilUSD = (total_hdri_operating_cost + total_eaf_operating_cost + total_electrolyzer_operating_cost + total_electricity_cost)/10**6 + ''' + LCOE Assumptions + ''' + #discount_rate = .10 #% + #lifetime = 20 #years + + lcos = lcoe_calc(steel_out_year_tls,total_cap_cost,annual_operating_cost,discount_rate,lifetime) + #lcos = lcoe_calc(steel_out_year_tls,total_cap_cost,annual_operating_cost,discount_rate,lifetime) + + #print(lcos) + + ''' + ProFAST Testing + ''' + import ProFAST + + gen_inflation = 0.025 + + pf = ProFAST.ProFAST('blank') + + gen_inflation = 0.025 + + steel_output_day_tls_day = steel_output_desired_kg_hr*24/1000 + land_cost = 0.0 + + pf = ProFAST.ProFAST("blank") + pf.set_params( + "commodity", + { + "name": "Steel", + "unit": "tls", + "initial price": 0, + "escalation": gen_inflation, + }, + ) + pf.set_params( + "capacity", + steel_output_day_tls_day, + ) # tls/day + pf.set_params("maintenance", {"value": (eaf_maintenance_cost+eaf_maintenance_cost)*10**6, "escalation": gen_inflation}) + pf.set_params("analysis start year", 2021) + pf.set_params( + "operating life", lifetime + ) + pf.set_params( + "installation months", + 12) # convert from hours to months + pf.set_params( + "installation cost", + { + "value": 0, + "depr type": "Straight line", + "depr period": 4, + "depreciable": False, + }, + ) + pf.set_params("non depr assets", land_cost) + pf.set_params( + "end of proj sale non depr assets", + land_cost + * (1 + gen_inflation) ** lifetime, + ) + pf.set_params("demand rampup", 0) + pf.set_params("long term utilization", 1) # TODO should use utilization + pf.set_params("credit card fees", 0) + pf.set_params("sales tax", .025) + pf.set_params("license and permit", {"value": 00, "escalation": gen_inflation}) + pf.set_params("rent", {"value": 0, "escalation": gen_inflation}) + # TODO how to handle property tax and insurance for fully offshore? + pf.set_params( + "property tax and insurance", + .009, + ) + pf.set_params( + "admin expense", + .005, + ) + pf.set_params( + "total income tax rate", + .3850, + ) + pf.set_params( + "capital gains tax rate", + .15, + ) + pf.set_params("sell undepreciated cap", True) + pf.set_params("tax losses monetized", True) + pf.set_params("general inflation rate", gen_inflation) + pf.set_params( + "leverage after tax nominal discount rate", + discount_rate, + ) + + #pf.set_params( + # "debt equity ratio of initial financing", + # ( + # plant_config["finance_parameters"]["debt_equity_split"] + # / (100 - plant_config["finance_parameters"]["debt_equity_split"]) + # ), + #) # TODO this may not be put in right + #pf.set_params("debt type", plant_config["finance_parameters"]["debt_type"]) + #pf.set_params( + # "loan period if used", plant_config["finance_parameters"]["loan_period"] + #) + #pf.set_params( + # "debt interest rate", plant_config["finance_parameters"]["debt_interest_rate"] + #) + #pf.set_params( + # "cash onhand", plant_config["finance_parameters"]["cash_onhand_months"] + #) + + # ----------------------------------- Add capital and fixed items to ProFAST ---------------- + pf.add_capital_item( + name="HDRI Shaft", + cost=hdri_capital_cost*10**6, + depr_type="MACRS", + depr_period=10, + refurb=[0], + ) + pf.add_fixed_cost( + name="HDRI Fixed O&M Cost", + usage=1.0, + unit="$/year", + cost=hdri_operation_cost*10**6, + escalation=gen_inflation, + ) + + electrolyzer_refurbishment_schedule = np.zeros( + lifetime + ) + refurb_period = 10 + + electrolyzer_refurbishment_schedule[refurb_period : lifetime : refurb_period] = 1 + + pf.add_capital_item( + name="EAF", + cost=eaf_capital_cost*10**6, + depr_type="MACRS", + depr_period=10, + refurb=[0], + ) + pf.add_fixed_cost( + name="EAF System Fixed O&M Cost", + usage=1.0, + unit="$/year", + cost=eaf_operation_cost*10**6, + escalation=gen_inflation, + ) + + pf.add_capital_item( + name="Electrolysis System", + cost=electrolyzer_cap_cost*10**6, + depr_type="MACRS", + depr_period=10, + #refurb=[electrolyzer_refurbishment_schedule], + refurb=[0], + ) + pf.add_fixed_cost( + name="Electrolysis System Fixed O&M Cost", + usage=1.0, + unit="$/year", + cost=total_electrolyzer_operating_cost, + escalation=gen_inflation, + ) + pf.add_fixed_cost( + name="Labor Cost", + usage=1.0, + unit="$/year", + cost=(eaf_labor_cost+eaf_labor_cost)*10**6, + escalation=gen_inflation, + ) + pf.add_fixed_cost( + name="Emission Cost", + usage=1.0, + unit="$/year", + cost=eaf_total_emission_cost*10**6, + escalation=gen_inflation, + ) + # ---------------------- Add feedstocks, note the various cost options------------------- + pf.add_feedstock( + name="Water", + usage=704, + unit="kg", + cost=.59289/1000, + escalation=gen_inflation, + ) + + pf.add_feedstock( + name="Electricity", + usage=4.4, + unit="mwh", + cost=56.12, + escalation=gen_inflation, + ) + + pf.add_feedstock( + name="Coal", + usage=.01, + unit="kg", + cost=200/1000, + escalation=gen_inflation, + ) + + pf.add_feedstock( + name="Lime", + usage=.05, + unit="kg", + cost=112/1000, + escalation=gen_inflation, + ) + + pf.add_feedstock( + name="Iron Ore", + usage=1604, + unit="kg", + cost=90/1000, + escalation=gen_inflation, + ) + # ------------------------------------ solve and post-process ----------------------------- + + sol = pf.solve_price() + + df = pf.cash_flow_out_table + + lcoh = sol["price"] + + print(lcoh) + print(lcos) + + return(lcos,total_electricity_cost,total_cap_cost,annual_operating_cost) +h2_main_steel() diff --git a/hopp/simulation/technologies/steel/hdri_model.py b/hopp/simulation/technologies/steel/hdri_model.py new file mode 100644 index 000000000..2288fb81e --- /dev/null +++ b/hopp/simulation/technologies/steel/hdri_model.py @@ -0,0 +1,395 @@ +def establish_save_output_dict(): + """ + Establishes and returns a 'save_outputs_dict' dict + for saving the relevant analysis variables for each site. + """ + save_outputs_dict = dict() + + save_outputs_dict['Steel Output Desired (kg)'] = list() + save_outputs_dict['Iron Ore Mass Needed (kg)'] = list() + save_outputs_dict['Hydrogen Gas Needed (kg)'] = list() + save_outputs_dict['Hydrogen Gas Leaving Shaft (kg)'] = list() + save_outputs_dict['Mass H2O Leaving Shaft (kg)'] = list() + save_outputs_dict['Mass Pure Iron Leaving Shaft (kg)'] = list() + save_outputs_dict['Total Mass H2 H2O Leaving Shaft (kg)'] = list() + save_outputs_dict['Mass Iron Ore Leaving Shaft (kg)'] = list() + save_outputs_dict['Energy Balance of Shaft (kWh)'] = list() + save_outputs_dict['Shaft Total Capital Cost (Mil USD)'] = list() + save_outputs_dict['Shaft Operational Cost (Mil USD per year)'] = list() + save_outputs_dict['Shaft Maintenance Cost (Mil USD per year)'] = list() + save_outputs_dict['Shaft Depreciation Cost (Mil USD per year)'] = list() + save_outputs_dict['Total Iron Ore Cost (Mil USD per year)'] = list() + save_outputs_dict['Electricity Needed for Heater (kWh per desired output)'] = list() + save_outputs_dict['Total Labor Cost (Mil USD per year)'] = list() + + + return save_outputs_dict + +class hdri_model: + ''' + Author: Charles Kiefer + Date: 8/14/23 + + This class holds functions relating to the modeling of a Hydrogen Direct Reduced Iron Shaft + in relation to the production of Green Steel. Iron ore enters the shaft and is reduced by hydrogen + gas. Pure iron is the result. + + Sources will be in each function + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + steel_prod_yr (ton/yr): (float) plant capacity steel produced per year. For financial outputs + + returns: + save_outputs_dict saves returns, other returns are for EAF Model + + Steel Output Desired (kg): + ['Iron Ore Mass Needed (kg)'] + ['Hydrogen Gas Needed (kg)'] + ['Hydrogen Gas Leaving Shaft (kg)'] + ['Mass H2O Leaving Shaft (kg)'] + ['Mass Pure Iron Leaving Shaft (kg)'] + ['Total Mass H2 H2O Leaving Shaft (kg)'] + ['Mass Iron Ore Leaving Shaft (kg)'] + ['Energy Balance of Shaft (kWh)'] + ['Shaft Total Capital Cost (Mil USD)'] + ['Shaft Operational Cost (Mil USD per year)'] + ['Shaft Maintenance Cost (Mil USD per year)'] + ['Shaft Depreciation Cost (Mil USD per year)'] + ['Total Iron Ore Cost (USD per year)'] + ['Electricity Needed for Heater (kWh per desired output)']: + -Total electricity needed for whatever the desired output steel value is + ''' + def __init__(self): + ''' + Initializes and stores needed data for functions relating to HDRI Shaft furnace + for Green Steel + + Sources: + [1]: Chase, M.W., Jr. 1998. "NIST-JANAF Themochemical Tables, Fourth Edition." J. Phys. Chem. Ref. Data, Monograph 9 1-1951. doi:https://doi.org/10.18434/T4D303. + [2]: Midrex Technologies, Inc. 2018. "DRI Products + Applications: Providing flexibility for steelmaking." April. Accessed May 2, 2022. https://www.midrex.com/wp-content/uploads/MIdrexDRI_ProductsBrochure_4-12-18.pdf. + [3]: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + [4]: haskar, Abhinav, Assadi Mohsen, and Somehsaraei Nikpey Homam. 2020. "Decarbonization of the Iron and Steel Industry with Direct Reduction of Iron Ore with Green Hydrogen." Energies 13 (3): 758. doi: https://doi.org/10.3390/en13030758 + ''' + + self.mol_weight_fe = 55.845 #(grams/mol) [1] + self.mol_weight_fe2o3 = 159.69 #(grams/mol) [1] + self.mol_weight_h2 = 2.01588 #(grams/mol) [1] + self.mol_weight_h2o = 18.0153 #(grams/mol) [1] + + self.metallization_rate = .94 #(%) Metallization rate of DRI [2] + self.lambda_h2 = 1.2 #(No Units) Multiplier Extra H2 is needed. Lambda is ratio of actual over stoichiometric requirement + + self.fe2o3_pure = 0.95 #(%) ammount of Fe2O3 in raw material. accounts for 5% impurities in raw material [2] + self.sio2_percent = 0.03 #(%) percent sio2 in raw materials [2] + self.al2o3_percent = 0.02 #(%) percent al2o3 in raw materials [2] + + self.h2_per_mol = 3/2 #(no units) 3 mol of H2 per 2 mol Fe stoichiometry + + self.steel_out_desired = None #(kg) standard is 1000 kg or one metric tonne + + self.mass_iron_ore_input = None #(kg) + self.mass_pure_fe_output = None #(kg) + self.mass_h2_input = None #(kg) + self.mass_h2_output = None #(kg) + self.mass_h2o_output = None #(kg) + self.mass_h2_h2o_output = None #(kg) + self.mass_iron_ore_output = None #(kg) + self.mass_sio2 = None #(kg) + self.mass_al2o3 = None #(kg) + + self.h2_temp_in = 1173 #(K) h2 temp needed into shaft [3] + self.h2_temp_out = 573 #(K) H2/H20 stream exiting DRI/entering recuperator [3] + self.stream_temp_out = 973 #(K) 95% reduced Iron exiting DRI/Entering EAF !!Assuming 0 heat Losses!! [3] + self.h2_temp_elec = 343 #(K) Temp of hydrogen leaving electrolyzer [3] + self.temp_stream_exit_recup = 393 #(K) Stream leaving recuperator/entering condenser [3] + self.temp_input_heater = 413 #(K) H2 entering heater from recuperator [3] + + self.enthalpy_h2_input = None #(kJ/kg) + self.enthalpy_out_stream = None #(kJ/kg) + self.enthalpy_stream_output = None #(kJ/kg) + + self.h_activation = 35 #(kJ/mol) activation energy of hydrogen [4] + self.h_endothermic = 99.5 #(kJ/mol) reaction energy absorbed of hydrogen [4] + self.energy_balance = None #(kWh) Energy Equation (Negative denotes heat leaving system) + + self.eta_el_heater = .6 #(%) efficiency of electricl heater + self.el_needed_heater = None #(kWh) electricity need by heater + + self.lang_factor = 3 #(no units) Capital cost multiplier [3] + self.plant_life = 40 #(years) [3] + self.hdri_total_capital_cost = None #(Million USD) + self.hdri_cost_per_ton_yr = 80 #(USD/tls/yr) + self.hdri_op_cost_tls = 13 #(tls/yr of dri) + self.hdri_operational_cost_yr = None #(Million USD) + self.maintenance_cost_percent = .015 #(% of capital cost)[3] + self.hdri_maintenance_cost_yr = None #(Million USD) + self.depreciation_cost = None #(Million USD) + self.iron_ore_cost_tls = 90 #(USD/ton) [3] + self.iron_ore_total_cost_yr = None #(Million USD) + self.total_labor_cost_yr = None #(Million USD) + self.labor_cost_tls = 20 #(USD/ton/year) [3] $40 is flat rate for hdri and eaf together + + + + def mass_model(self,steel_out_desired): + ''' + Mass model calculates the masses inputted and outputted of + an HDRI oxidation system of iron ore in the greensteel process for output of tonne liquid steel + + Args: + steel_out_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + ''' + + + m3 = steel_out_desired + + self.steel_out_desired = m3 #kg + + + alpha = self.metallization_rate #Metallization rate of DRI + + fe_o_ratio = ((2*self.mol_weight_fe)/self.mol_weight_fe2o3) #ratio of fe weight to fe2o3 weight + + m1 = m3/(self.fe2o3_pure*fe_o_ratio*alpha) #kg fe2o3 amount of raw material needed for tonne steel, kg + m2_feo = (m1*self.fe2o3_pure*fe_o_ratio*(1 - alpha)) #kg fe2o3 amount of IronOxide not ocidized + + sio2_percent = self.sio2_percent #percent sio2 in raw materials + al2o3_percent = self.al2o3_percent #percent al2o3 in raw materials + + m1_sio2 = (sio2_percent*m1) #kg sio2 mass of sio2 in raw materials kg per input + m1_al2o3 = (al2o3_percent*m1) #kg al2o3 mass of al2o3 in raw materials kg per desired output + + m2_fe = (m1 - (m1_sio2 + m1_al2o3 + m2_feo))*fe_o_ratio # kg fe mass metallic iron out of DRI per tonne steel + + self.mass_sio2 = m1_sio2 + self.mass_al2o3 = m1_al2o3 + self.mass_iron_ore_output = m2_feo + self.mass_pure_fe_output = m2_fe + self.mass_iron_ore_input = m1 + + h2_weight_per_mol = (self.h2_per_mol*self.mol_weight_h2) #g h2 per 1 mol fe + mol_per_input_fe = (m3*1000)/self.mol_weight_fe #mols of iron in a input kg of fe + m4_stoich = (h2_weight_per_mol*mol_per_input_fe)/1000 #kg h2stoich minimum mass of H2 needed per tonne steel + + m4 = m4_stoich*self.lambda_h2 #kg h2 mass of hydrogen inputted into DRI in Kg per tonne steel + + self.mass_h2_input = m4 + + water_mass = ((3*self.mol_weight_h2o)/(2*self.mol_weight_fe))*m3 #water produced per tonne liquid steel + + m5_h2 = (m4_stoich*(self.lambda_h2 - 1)) #mass of hyrdogen remaing in exhaust after DRI in kg + m5_h2o = water_mass #Mass water produced in DRI in kg + m5 = (m5_h2 + m5_h2o) #Total Mass of exhaust in kg + + self.mass_h2_output = m5_h2 + self.mass_h2o_output = m5_h2o + self.mass_h2_h2o_output = m5 + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Steel Output Desired (kg)'].append(self.steel_out_desired) + save_outputs_dict['Iron Ore Mass Needed (kg)'].append(self.mass_iron_ore_input) + save_outputs_dict['Hydrogen Gas Needed (kg)'].append(self.mass_h2_input) + save_outputs_dict['Hydrogen Gas Leaving Shaft (kg)'].append(self.mass_h2_output) + save_outputs_dict['Mass H2O Leaving Shaft (kg)'].append(self.mass_h2o_output) + save_outputs_dict['Mass Pure Iron Leaving Shaft (kg)'].append(self.mass_pure_fe_output) + save_outputs_dict['Total Mass H2 H2O Leaving Shaft (kg)'].append(self.mass_h2_h2o_output) + save_outputs_dict['Mass Iron Ore Leaving Shaft (kg)'].append(self.mass_iron_ore_output) + + return (save_outputs_dict, m2_fe, m2_feo, self.steel_out_desired, self.mass_iron_ore_input, self.mass_h2_input, + self.mass_h2_output, self.mass_h2o_output, self.mass_pure_fe_output, self.mass_h2_h2o_output, self.mass_iron_ore_output) + + def energy_model(self, steel_out_desired): + ''' + This function calculates the energy balance of the hdri shaft. Negative values designate + heat leaving the system. Positive values designate heat needs to enter the system. + + Energy belance values should be negative. + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + + ''' + from hopp.simulation.technologies.steel.enthalpy_functions import h2_enthalpy, h2_enthalpy, h2o_enthalpy, sio2_enthalpy, al2o3_enthalpy, feo_enthalpy ,fe_enthalpy + + hdri_model.mass_model(self,steel_out_desired) + + mass_h2_input = self.mass_h2_input + mass_h2o_output = self.mass_h2o_output + mass_h2_output = self.mass_h2_output + + + h4 = (h2_enthalpy(self.h2_temp_in)*mass_h2_input*1000) #kJ + #h4_kwh = h4/3600 #3600 kJ in 1 kWh + + self.enthalpy_h2_input = h4 #kJ + + h5_h20 = (mass_h2o_output*h2o_enthalpy(self.h2_temp_out)*1000) #kJ Enthalpyof h20 in exhaust + h5_h2 = (mass_h2_output*h2_enthalpy(self.h2_temp_out)*1000) #kJ Enthalpy of H2 in exhaust + + h5 = (h5_h20 + h5_h2) #kJ Enthalpy of exhaust + #h5_kwh = h5/3600 #Conversion Kj to Kwh + + self.enthalpy_out_stream = h5 + + h_reaction = self.h_activation + self.h_endothermic #energy needed per 1 mol + h_reaction_total = (h_reaction*self.mass_iron_ore_input*1000*self.fe2o3_pure)/self.mol_weight_fe2o3 #total energy per tonne steel + #h_reaction_total_kwh=h_reaction_total/3600 #kJ to kwh conversion + + + h2 = 1000*((fe_enthalpy(self.stream_temp_out)*self.mass_pure_fe_output) + + (feo_enthalpy(self.stream_temp_out)*self.mass_iron_ore_output) + + (sio2_enthalpy(self.stream_temp_out)*self.mass_sio2) + + (al2o3_enthalpy(self.stream_temp_out)*self.mass_al2o3)) #Enthalpy of metallic stream exiting DRI/exiting EAF in kj/kg + + #h2_kwh=h2/3600 #conversion kj to kwh + + self.enthalpy_stream_output = h2 + + q_dri = ((self.enthalpy_h2_input) - (self.enthalpy_out_stream + h2 + h_reaction_total))/3600 #Enthalpy of Hydrogen minus enthalpy of exhaust, metal stream, reaction enthalpy + + self.energy_balance = q_dri #kwh + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Energy Balance of Shaft (kWh)'].append(self.energy_balance) + + return (save_outputs_dict, self.energy_balance) + + def financial_model(self,steel_prod_yr): + ''' + This function returns the financials for a rated capacity plant for HDRI shaft + + Args: + steel_prod_yr (ton/yr): (float) plant capacity steel produced per year. For financial outputs + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + hdri_model.mass_model(self,steel_prod_yr) + + self.hdri_total_capital_cost = ((self.hdri_cost_per_ton_yr*steel_prod_yr)/10**6)*self.lang_factor #Mil USD + + self.hdri_operational_cost_yr = self.hdri_op_cost_tls*steel_prod_yr/(10**6) #Mil USD per year + + self.hdri_maintenance_cost_yr = self.maintenance_cost_percent*self.hdri_total_capital_cost #Mil USD per year + + self.depreciation_cost = self.hdri_total_capital_cost/self.plant_life #Mil USD per year + + total_iron_ore = self.mass_iron_ore_input #tonne FeO + + self.iron_ore_total_cost_yr = self.iron_ore_cost_tls * total_iron_ore/10**6 #USD per ton + + self.total_labor_cost_yr = self.labor_cost_tls*steel_prod_yr/10**6 + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Shaft Total Capital Cost (Mil USD)'].append(self.hdri_total_capital_cost) + save_outputs_dict['Shaft Operational Cost (Mil USD per year)'].append(self.hdri_operational_cost_yr) + save_outputs_dict['Shaft Maintenance Cost (Mil USD per year)'].append(self.hdri_maintenance_cost_yr) + save_outputs_dict['Shaft Depreciation Cost (Mil USD per year)'].append(self.depreciation_cost) + save_outputs_dict['Total Iron Ore Cost (Mil USD per year)'].append(self.iron_ore_total_cost_yr) + save_outputs_dict['Total Labor Cost (Mil USD per year)'].append(self.total_labor_cost_yr) + + #labour costs will need to be done separately as they are flat rate + + return (save_outputs_dict, self.hdri_total_capital_cost, self.hdri_operational_cost_yr, self.hdri_maintenance_cost_yr, + self.depreciation_cost, self.iron_ore_total_cost_yr, self.total_labor_cost_yr) + + def recuperator_mass_energy_model(self,steel_out_desired): + ''' + Accessory process for heat exchanger. Currently has no outputs as recuperator doesn't change masses + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + from hopp.simulation.technologies.steel.enthalpy_functions import h2o_enthalpy, h2_enthalpy + + hdri_model.mass_model(self,steel_out_desired) + hdri_model.energy_model(self,steel_out_desired) + + m10 = self.mass_h2_input #hydrogen from electrolyzer = hydrogen into DRI + + m12_h2o = self.mass_h2o_output #Mass h2o of exhaust stream = mass h2o to condensor + m12_h2 = self.mass_h2_output #Mass h2 of exhaust stream = mass h2 + #m13 = m12_h2o #Mass h2o from condenser to electrolyzer + + h12_h2o = (m12_h2o*h2o_enthalpy(self.temp_stream_exit_recup)*1000) #exit h20 in recuperator to condenser stream + h12_h2 = (m12_h2*h2_enthalpy(self.temp_stream_exit_recup)*1000) #exit h2 in recuperator to condenser stream + h12 = (h12_h2 + h12_h2o) #total enthalpy in exit of recuperator to condensor + h12_kwh = h12/3600 #conversion kj to kwh + + h10 = (h2_enthalpy(self.h2_temp_elec)*m10*1000) #electrolyzer to recuperator + h10_kwh = (h10/3600) #conversion kj to kwh + + h11 = ((self.enthalpy_out_stream - h12) + h10)/3600 + + save_outputs_dict = establish_save_output_dict() + + + return (save_outputs_dict, h11) + + def heater_mass_energy_model(self,steel_out_desired): + ''' + Function returns the energy needed to heat up gas to needed temp for oxidation + + Args: + steel_output_desired (kg) or (kg/hr): (float) resulting desired steel output + + Sources: + Model derived from: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + + ''' + from hopp.simulation.technologies.steel.enthalpy_functions import h2_enthalpy + + hdri_model.mass_model(self,steel_out_desired) + hdri_model.energy_model(self,steel_out_desired) + + T11_heat_in = self.temp_input_heater #Assumes 30 degree heat loss from recuperator to heater + m11_heat_in = self.mass_h2_input #mass of hydrogen into heater = mass hydrogen into recuperator + + h11_heat_in = (h2_enthalpy(T11_heat_in)*m11_heat_in*1000) #enthalpy of stream into heater + #h11_heat_in_kwh = (h11_heat_in/3600) #kj to kwh conversion + + #eta_rec = ((h11_heat_in - h10)/(h5-h12)) #recuperator efficiency + q_heater = (self.enthalpy_h2_input - h11_heat_in)/3600 #energy needed to be provided to heater + + eta_el_heater = self.eta_el_heater #Efficiency of heater + el_heater = (q_heater/eta_el_heater) #electricity need at heater + + self.el_needed_heater = el_heater #kWh or kw + + save_outputs_dict = establish_save_output_dict() + + save_outputs_dict['Electricity Needed for Heater (kWh per desired output)'].append(self.el_needed_heater) + + return(save_outputs_dict,self.el_needed_heater) + +if __name__ == '__main__': + + model_instance = hdri_model() + + steel_output_desired = 1000 #(kg or kg/hr) + + mass_outputs = model_instance.mass_model(steel_output_desired) + energy_outputs = model_instance.energy_model(steel_output_desired) + recuperator_outputs = model_instance.recuperator_mass_energy_model(steel_output_desired) + heater_outputs = model_instance.heater_mass_energy_model(steel_output_desired) + + steel_output_desired_yr = 2000000 #(ton/yr) + + financial_outputs = model_instance.financial_model(steel_output_desired_yr) + diff --git a/hopp/simulation/technologies/wind/__init__.py b/hopp/simulation/technologies/wind/__init__.py index bacc75c94..b5cdf77f0 100644 --- a/hopp/simulation/technologies/wind/__init__.py +++ b/hopp/simulation/technologies/wind/__init__.py @@ -1,2 +1,2 @@ from hopp.simulation.technologies.wind.floris import Floris -from hopp.simulation.technologies.wind.pysam_wind import PySAMWind +#from hopp.simulation.technologies.wind.pysam_wind import PySAMWind diff --git a/tests/hopp/test_steel/test_eaf_model.py b/tests/hopp/test_steel/test_eaf_model.py new file mode 100644 index 000000000..b36c05ee2 --- /dev/null +++ b/tests/hopp/test_steel/test_eaf_model.py @@ -0,0 +1,193 @@ +import pytest +from hopp.simulation.technologies.steel.eaf_model import eaf_model +''' +Test files for eaf_model.py class and its functions. + +All values were hand calculated and compared with the values in: +[1]: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + +''' + +def test_mass_steel_output_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + steel_output_actual = outputs[1] + + assert pytest.approx(steel_output_actual) == 1044.68 + +def test_mass_carbon_total_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + carbon_total = outputs[2] + + assert pytest.approx(carbon_total) == 10 + + +def test_mass_lime_total_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + lime_total = outputs[3] + + + assert pytest.approx(lime_total) == 50 + + +def test_energy_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.energy_model(steel_output_desired) + + el_eaf = outputs[1] + + assert pytest.approx(el_eaf, .01) == 501.32 + + + +def test_emission_indirect_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.emission_model(steel_output_desired) + + indirect_emissions_total = outputs[1] + + assert pytest.approx(indirect_emissions_total, 0.1) == 325.56 + +def test_emission_direct_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.emission_model(steel_output_desired) + + direct_emissions = outputs[2] + + assert pytest.approx(direct_emissions) == .233 + +def test_emission_total_model(): + model_instance = eaf_model() + + steel_output_desired = 1000 + + outputs = model_instance.emission_model(steel_output_desired) + + indirect_emissions_total = outputs[1] + direct_emissions = outputs[2] + total_emissions = outputs[3] + + + assert pytest.approx(total_emissions) == (indirect_emissions_total + direct_emissions) + + +def test_cap_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + eaf_total_capital_cost = outputs[1] + + assert pytest.approx(eaf_total_capital_cost) == .84 + + +def test_op_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + eaf_operational_cost_yr = outputs[2] + + assert pytest.approx(eaf_operational_cost_yr) == .064 + + +def test_maint_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + eaf_maintenance_cost_yr = outputs[3] + + assert pytest.approx(eaf_maintenance_cost_yr) == .0126 + + +def test_dep_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + depreciation_cost = outputs[4] + + assert pytest.approx(depreciation_cost) == .021 + + +def test_coal_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000000 + + outputs = model_instance.financial_model(steel_output_desired) + + coal_total_cost_yr = outputs[5] + + assert pytest.approx(coal_total_cost_yr) == 4 + +def test_lab_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + total_labor_cost_yr = outputs[6] + + assert pytest.approx(total_labor_cost_yr) == .04 + +def test_lime_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000000 + + outputs = model_instance.financial_model(steel_output_desired) + + lime_cost_total = outputs[7] + + assert pytest.approx(lime_cost_total) == 11.2 + + +def test_emission_cost_model(): + model_instance = eaf_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + total_emission_cost = outputs[8] + + assert pytest.approx(total_emission_cost) == .01398 + + + + + diff --git a/tests/hopp/test_steel/test_enthalpy_functions.py b/tests/hopp/test_steel/test_enthalpy_functions.py new file mode 100644 index 000000000..81e1d5a4b --- /dev/null +++ b/tests/hopp/test_steel/test_enthalpy_functions.py @@ -0,0 +1,211 @@ +import pytest +import hopp.simulation.technologies.steel.enthalpy_functions as ep_f +''' +Values were grabbed from NIST https://webbook.nist.gov/chemistry/form-ser/ Gas thermochemistry tab for each element +and were hand calculated to verify results +''' +def test_h2_enthalpy_upper_function(): + + temp = 1500 + + assert pytest.approx(ep_f.h2_enthalpy(temp),.01) == 18.002 + +def test_h2_enthalpy_lower_function(): + + temp = 500 + + assert pytest.approx(ep_f.h2_enthalpy(temp),.01) == 2.91 + +def test_h2_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.h2_enthalpy(temp) + +def test_h2_enthalpy_error_function_upper(): + + temp = 3000 + + with pytest.raises(ValueError):ep_f.h2_enthalpy(temp) + + +def test_h2o_enthalpy_function_upper(): + + temp = 1000 + + assert pytest.approx(ep_f.h2o_enthalpy(temp),.01) == 1.443 + +def test_h2o_ehnthalpy_function_lower(): + + temp = 400 + + assert pytest.approx(ep_f.h2o_enthalpy(temp),.01) == .428 + +def test_h2o_ehnthalpy_function_error_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.h2o_enthalpy(temp) + +def test_h2o_ehnthalpy_function_error_upper(): + + temp = 1800 + + with pytest.raises(ValueError):ep_f.h2o_enthalpy(temp) + +def test_fe_enthalpy_upper_function(): + + temp = 2000 + + assert pytest.approx(ep_f.fe_enthalpy(temp),.01) == 1.23 + +def test_fe_enthalpy_lower_function(): + + temp = 1000 + + assert pytest.approx(ep_f.fe_enthalpy(temp),.01) == .369 + + +def test_fe_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.fe_enthalpy(temp) + +def test_fe_enthalpy_error_function_upper(): + + temp = 4000 + + with pytest.raises(ValueError):ep_f.fe_enthalpy(temp) + +def test_feo_enthalpy_function(): + + temp = 1000 + + assert pytest.approx(ep_f.feo_enthalpy(temp),.01) == .5394 + +def test_feo_enthalpy_error_function_upper(): + + temp = 2000 + + with pytest.raises(ValueError):ep_f.feo_enthalpy(temp) + +def test_feo_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.feo_enthalpy(temp) + +def test_al2o3_enthalpy_function(): + + temp = 1000 + + assert pytest.approx(ep_f.al2o3_enthalpy(temp),.01) == .781 + +def test_al2o3_enthalpy_error_function_upper(): + + temp = 3000 + + with pytest.raises(ValueError):ep_f.al2o3_enthalpy(temp) + +def test_al2o3_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.al2o3_enthalpy(temp) + +def test_sio2_enthalpy_function(): + + temp = 1000 + + assert pytest.approx(ep_f.sio2_enthalpy(temp),.01) == .754 + +def test_sio2_enthalpy_error_function_upper(): + + temp = 2000 + + with pytest.raises(ValueError):ep_f.sio2_enthalpy(temp) + +def test_sio2_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.sio2_enthalpy(temp) + +def test_mgo_enthalpy_function(): + + temp = 1000 + + assert pytest.approx(ep_f.mgo_enthalpy(temp),.01) == .818 + +def test_mgo_enthalpy_error_function_upper(): + + temp = 4000 + + with pytest.raises(ValueError):ep_f.mgo_enthalpy(temp) + +def test_mgo_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.mgo_enthalpy(temp) + +def test_cao_enthalpy_function(): + + temp = 1000 + + assert pytest.approx(ep_f.cao_enthalpy(temp),.01) == .628 + +def test_cao_enthalpy_error_function_upper(): + + temp = 4000 + + with pytest.raises(ValueError):ep_f.cao_enthalpy(temp) + +def test_cao_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.cao_enthalpy(temp) + +def test_ch4_enthalpy_upper_function(): + + temp = 1500 + + assert pytest.approx(ep_f.ch4_enthalpy(temp),.01) == 4.87 + +def test_ch4_enthalpy_lower_function(): + + temp = 1000 + + assert pytest.approx(ep_f.ch4_enthalpy(temp),.01) == 2.38 + +def test_ch4_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.ch4_enthalpy(temp) + +def test_ch4_enthalpy_error_function_upper(): + + temp = 7000 + + with pytest.raises(ValueError):ep_f.ch4_enthalpy(temp) + +def test_c_enthalpy_function(): + + temp = 900 + + assert pytest.approx(ep_f.c_enthalpy(temp),.01) == 1.04 + +def test_c_enthalpy_error_function_lower(): + + temp = 0 + + with pytest.raises(ValueError):ep_f.c_enthalpy(temp) + +def test_c_enthalpy_error_function_upper(): + + temp = 2000 + + with pytest.raises(ValueError):ep_f.c_enthalpy(temp) \ No newline at end of file diff --git a/tests/hopp/test_steel/test_hdri_model.py b/tests/hopp/test_steel/test_hdri_model.py new file mode 100644 index 000000000..8e947673f --- /dev/null +++ b/tests/hopp/test_steel/test_hdri_model.py @@ -0,0 +1,216 @@ +import pytest +from hopp.simulation.technologies.steel.hdri_model import hdri_model +''' +Test files for hdri_model.py class and its functions. + +All values were hand calculated and compared with the values in: +[1]: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. + +''' + +def test_steel_out_desired_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + steel_out_desired = outputs[3] + + + assert pytest.approx(steel_out_desired) == steel_output_desired + + +def test_iron_input_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_iron_ore_input = outputs[4] + + assert pytest.approx(mass_iron_ore_input,.01) == 1601.07 + + +def test_h2_input_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_h2_input = outputs[5] + + assert pytest.approx(mass_h2_input,.01) == 64.97 + + +def test_h2_output_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_h2_output = outputs[6] + + assert pytest.approx(mass_h2_output,.01) == 10.83 + + +def test_water_out_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_h2o_output = outputs[7] + + assert pytest.approx(mass_h2o_output,.01) == 483.89 + + +def test_iron_outputs_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_pure_fe = outputs[8] + + assert pytest.approx(mass_pure_fe,.01) == 1019.18 + + +def test_gas_out_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_h2_output = outputs[6] + mass_h2o_output = outputs[7] + + mass_h2_h2o_output = outputs[9] + + assert pytest.approx(mass_h2_h2o_output,.01) == (mass_h2_output+mass_h2o_output) + + +def test_iron_ore_output_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.mass_model(steel_output_desired) + + mass_iron_ore_output = outputs[10] + + assert pytest.approx(mass_iron_ore_output,.01) == 63.83 + +def test_energy_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.energy_model(steel_output_desired) + + energy_balance = outputs[1] + + assert pytest.approx(energy_balance,.01) == -332.2 + + + +def test_heater_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.heater_mass_energy_model(steel_output_desired) + + energy_needed = outputs[1] + + assert pytest.approx(energy_needed,.01) == 337.58 + +def test_recuperator_model(): + model_instance = hdri_model() + + steel_output_desired = 1000 + + outputs = model_instance.recuperator_mass_energy_model(steel_output_desired) + + energy_exchange = outputs[1] + + assert pytest.approx(energy_exchange,.01) == 37.01 + + + +def test_cap_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + capital_cost = outputs[1] + + assert pytest.approx(capital_cost) == .48 + +def test_op_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + operational_cost = outputs[2] + + assert pytest.approx(operational_cost) == .026 + +def test_maint_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + maintenance_cost = outputs[3] + + assert pytest.approx(maintenance_cost) == .0072 + + +def test_dep_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + depreciation_cost = outputs[4] + + assert pytest.approx(depreciation_cost) == .012 + + +def test_iron_ore_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000000 + + outputs = model_instance.financial_model(steel_output_desired) + + iron_ore_total = outputs[5] + + assert pytest.approx(iron_ore_total,.1) == 288.2 + + +def test_lab_cost_model(): + model_instance = hdri_model() + + steel_output_desired = 2000 + + outputs = model_instance.financial_model(steel_output_desired) + + labor_cost = outputs[6] + + assert pytest.approx(labor_cost) == .04 + + diff --git a/tests/hopp/test_steel/test_steel_example_run.py b/tests/hopp/test_steel/test_steel_example_run.py new file mode 100644 index 000000000..a223a344a --- /dev/null +++ b/tests/hopp/test_steel/test_steel_example_run.py @@ -0,0 +1,75 @@ +import pytest +from hopp.simulation.technologies.steel.example_steel_run_script import h2_main_steel +''' +Values for tests were determined from [1]: Bhaskar, Abhinav, Rockey Abhishek, Mohsen Assadi, and Homan Nikpey Somehesaraei. 2022. "Decarbonizing primary steel production : Techno-economic assessment of a hydrogen based green steel production plant in Norway." Journal of Cleaner Production 350: 131339. doi: https://doi.org/10.1016/j.jclepro.2022.131339. +And hand calcs to verify the results +''' +def test_lcos(): + + lcos = h2_main_steel()[0] + + assert pytest.approx(lcos,.1) == 613 + +def test_lcos_2(): + + lcoe = .60 #cents/kwh + steel_output_desired = 240320 #kg/hr + mw_h2 = .5 #mil usd/mw + elec_specification = 50 #kwh/kgh2 + lifetime = 20 + + lcos = h2_main_steel(lcoe,steel_output_desired,MW_h2=mw_h2,elec_spec=elec_specification,lifetime=lifetime)[0] + + assert pytest.approx(lcos,.01) == 616.85 + + +def test_total_operating_cost(): + + operating_cost_yr = h2_main_steel()[3] + + assert pytest.approx(operating_cost_yr) == 522431219 + +def test_total_operating_cost_2(): + + lcoe = .60 #cents/kwh + steel_output_desired = 240320 #kg/hr + mw_h2 = .5 #mil usd/mw + elec_specification = 50 #kwh/kgh2 + + operating_cost_yr = h2_main_steel(lcoe,steel_output_desired,MW_h2=mw_h2,elec_spec=elec_specification)[3] + + assert pytest.approx(operating_cost_yr,.1) == 1036847503 + +def test_total_electricity_cost(): + + electricity_cost_yr = h2_main_steel()[1] + + assert pytest.approx(electricity_cost_yr) == 251928316 + +def test_total_electricity_cost_2(): + + lcoe = .60 #cents/kwh + steel_output_desired = 240320 #kg/hr + mw_h2 = .5 #mil usd/mw + elec_specification = 50 #kwh/kgh2 + + electricity_cost_yr = h2_main_steel(lcoe,steel_output_desired,MW_h2=mw_h2,elec_spec=elec_specification)[1] + + assert pytest.approx(electricity_cost_yr,.1) == 495841707 + +def test_total_capital_cost(): + + total_capital_cost = h2_main_steel()[2] + + assert pytest.approx(total_capital_cost,.1) == 974104842 + +def test_total_capital_cost_2(): + + lcoe = .60 #cents/kwh + steel_output_desired = 240320 #tls/hr + mw_h2 = .5 #mil usd/mw + elec_specification = 50 #kwh/kgh2 + + total_capital_cost = h2_main_steel(lcoe,steel_output_desired,MW_h2=mw_h2,elec_spec=elec_specification)[2] + + assert pytest.approx(total_capital_cost) == 1843501768