Skip to content

Conversation

@jmartin4nrel
Copy link
Collaborator

@jmartin4nrel jmartin4nrel commented Jan 2, 2026

Iron: Adding electrowinning capabilities

This PR adds three iron electrowinning technologies:

  • Aqueous hydroxide electrolysis (AHE)
  • Molten salt electrolysis (MSE)
  • Molten oxide electrolysis (MOE)

For the time being, the performance and cost are modeled fairly simply. Performance is modeled based on upper and lower bounds of energy required for each type as defined by Humbert. Cost is modeled based on correlations of capital cost developed for electrowinning of many different metals developed by Stinn and Allanore, and an opex model developed by Humbert in the spreadsheet available as SI to the linked paper, which also provides input values for the Stinn/Allanore capex model.

Section 1: Type of Contribution

  • Feature Enhancement
    • Framework
    • New Model
    • Updated Model
    • Tools/Utilities
    • Other (please describe):
  • Bug Fix
  • Documentation Update
  • CI Changes
  • Other (please describe):

Section 2: Draft PR Checklist

N/A

Type of Reviewer Feedback Requested (on Draft PR)

Structural feedback:

Implementation feedback:

Other feedback:

Section 3: General PR Checklist

  • PR description thoroughly describes the new feature, bug fix, etc.
  • Added tests for new functionality or bug fixes
  • Tests pass (If not, and this is expected, please elaborate in the Section 6: Test Results)
  • Documentation
    • Docstrings are up-to-date
    • Related docs/ files are up-to-date, or added when necessary
    • Documentation has been rebuilt successfully
    • Examples have been updated (if applicable)
  • CHANGELOG.md has been updated to describe the changes made in this PR

Section 3: Related Issues

Section 4: Impacted Areas of the Software

Section 4.1: New Files

  • h2integrate\converters\iron\:
    • humbert_ewin_perf.py: New iron electrowinning performance model humbert_electrowinning_performance based on Humbert
    • humbert_stinn_ewin_cost.py: New iron electrowinning cost model humbert_stinn_electrowinning_cost based on Humbert and Stinn and Allanore
    • stinn\table1.csv: Input data table mostly from Stinn and Allanore but iron costs from Humbert
  • h2integrate\converters\iron\stinn\cost_model.py: Modified the transcription of the Humbert SI equations to interface with the humbert_stinn_electrowinning_cost model
  • examples\27_iron_electrowinning\: New example that produces an LCOI for all 3 types of iron electrowinning

Section 4.2: Modified Files

  • h2integrate\converters\iron\stinn\:
    • cost_model.py: Modified the transcription of the Stinn and Allanore equations to interface with the humbert_stinn_electrowinning_cost model
    • cost_coeffs.csv: Added in some coefficients that were previously hard-coded into cost_model.py
  • h2integrate\core\supported_models.py: Added humbert_electrowinning_performance and humbert_stinn_electrowinning_cost as supported models
  • h2integrate\finances\profast_base.py: Added sponge_iron as a mass commodity

Section 5: Additional Supporting Information

Section 6: Test Results, if applicable

Section 7 (Optional): New Model Checklist

  • Model Structure:
    • Follows established naming conventions outlined in docs/developer_guide/coding_guidelines.md
    • Used attrs class to define the Config to load in attributes for the model
      • If applicable: inherit from BaseConfig or CostModelBaseConfig
    • Added: initialize() method, setup() method, compute() method
      • If applicable: inherit from CostModelBaseClass
  • Integration: Model has been properly integrated into H2Integrate
    • Added to supported_models.py
    • If a new commodity_type is added, update create_financial_model in h2integrate_model.py
  • Tests: Unit tests have been added for the new model
    • Pytest-style unit tests
    • Unit tests are in a "test" folder within the folder a new model was added to
    • If applicable add integration tests
  • Example: If applicable, a working example demonstrating the new model has been created
    • Input file comments
    • Run file comments
    • Example has been tested and runs successfully in test_all_examples.py
  • Documentation:
    • Write docstrings using the Google style
    • Model added to the main models list in docs/user_guide/model_overview.md
      • Model documentation page added to the appropriate docs/ section
      • <model_name>.md is added to the _toc.yml

Copy link
Collaborator

@kbrunik kbrunik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! Overall super cool and exciting to have some more functionality added to H2I. I know this isn't quite finished with regards to documentation and testing but thought I could share some initial thoughts.

@jmartin4nrel jmartin4nrel marked this pull request as ready for review January 14, 2026 20:22
Copy link
Collaborator

@johnjasa johnjasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this great PR, Jonathan! I'm glad we're back to moving the iron work forward so well.

I've pushed up some refactoring changes directly. This move some of the calculations that occurred in separate files into a singular file. Could you please take a look and see if you support those changes or if you think the setup was better before them? Given how the calcs are done now, I think it's more clear, but if you were planning to expand out the modeling or use a combination of Stinn or Humbert models in other constituent components later, then I could see the use case for having separate functions. Of course, feel free to undo any changes I did.

Otherwise, I have a large-ish overall question about how you see the usefulness of the cost_coeffs.csv and cost_model.py files would be going forward. Given that we have more of the H2I framework built out and understood now than when we were working on this a year ago, I think we could simplify the setup to move away from having multiple files to define each method, and instead have the calcs defined in-line within the corresponding compute() methods for each converter. Do you think this is reasonable, or should we retain the cost_model.py and cost_coeffs.csv setup from before for a technical reason?

Copy link
Collaborator

@kbrunik kbrunik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get a chance to fully review @johnjasa comments so some might be duplicative since I started before John submitted his review. I think it's looking pretty good! Just a few changes hopefully, but exciting this is moving along :)


H2I contains models to simulate to separation of mostly pure iron from iron oxides.
The main input feedstock is iron ore, while the output commodity is "sponge iron", i.e. iron that is typically brittle ("spongey") and contains less carbon than most steel alloys.
This sponge iron can then be connected to an electric arc furnace (EAF) to produce steel.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This sponge iron can then be connected to an electric arc furnace (EAF) to produce steel.
This sponge iron can then be used in other processes such as acting as a feedstock for an electric arc furnace (EAF) which produces steel.


To use this model, specify `"humbert_electrowinning_performance"` as the performance model and `"humbert_stinn_electrowinning_cost"` as the cost model.

## Shared Parameters
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding based on some feedback I received on a different PR is that we want to start relying on the API docs to autopopulate definitions like this. @johnjasa is this something we could beta here by linking the API documentation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way @elenya-grant and I approached the other iron models was to remove some of the file abstraction and have the py files live in the iron folder instead of subfolders. I think it could make sense to move this function directly into the humbert_stinn_ewin_cost.py within the cost class

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could make sense to move this into iron and out of the subfolder.

cost_model (dict): Dictionary with the file path to cost coefficients.
electrolysis_temp (float): Electrolysis temperature in degrees Celsius (°C).
pressure (float): System pressure.
intsalled capacity (float): Installed capacity in tonnes per year (t/y).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
intsalled capacity (float): Installed capacity in tonnes per year (t/y).
installed_capacity (float): Installed capacity in tonnes per year (t/y).

Copy link
Collaborator

@elenya-grant elenya-grant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Jonathan! I think this is super cool and the example is very well done! I didn't take a super deep look into the new models but provided some initial feedback (some of it may be irrelevant depending on other changes you plan on making). Would be happy to do a deeper review once it's ready! Thanks for the work on this! Very exciting!


def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
# Physical constants
F = 96485.3321 # Faraday constant: Electric charge per mole of electrons (C/mol)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar comments about F and M being moved to h2integrate/tools/constants.py

self.add_output("labor_opex", val=0.0, units="USD/year")
self.add_output("NaOH_opex", val=0.0, units="USD/year")
self.add_output("CaCl2_opex", val=0.0, units="USD/year")
self.add_output("limestone_opex", val=0.0, units="USD/year")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't feedstock costs (lime, electricity, ore, etc) be taken care of with feedstock component(s)? In my mind, this should only output costs associated with this tech, not its feedstocks.

elec_price = inputs["price_electricity"]

# Add ore transport cost TODO: turn iron_transport into proper transporter
ore_price += ore_transport_cost
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ore transport is now a separate model, should not be included here.


# Humbert Opex model - from SI spreadsheet (doi.org/10.1007/s40831-024-00878-3)
# Default costs - adjusted to 2018 to match Stinn via CPI
labor_rate = 55.90 # USD/person-hour
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should labor_rate be an attribute of the configuration class?

labor_rate = 55.90 # USD/person-hour
NaOH_cost = 415.179 # USD/tonne
CaCl2_cost = 207.59 # USD/tonne
limestone_cost = 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these feedstock costs should be taken care of with the feedstock component.

@johnjasa johnjasa added the needs modifications This PR has been reviewed, at least partially, and is ready for PR author response label Jan 20, 2026
@jmartin4nrel jmartin4nrel added ready for review This PR is ready for input from folks and removed needs modifications This PR has been reviewed, at least partially, and is ready for PR author response labels Jan 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review This PR is ready for input from folks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants