Skip to content

Finance models to account for lifetime performance of electrolyzer (follow-on to 463)#491

Draft
elenya-grant wants to merge 60 commits intoNatLabRockies:developfrom
elenya-grant:elec_lifetime_perf
Draft

Finance models to account for lifetime performance of electrolyzer (follow-on to 463)#491
elenya-grant wants to merge 60 commits intoNatLabRockies:developfrom
elenya-grant:elec_lifetime_perf

Conversation

@elenya-grant
Copy link
Collaborator

@elenya-grant elenya-grant commented Jan 30, 2026

Finance models to account for lifetime performance of electrolyzer

This PR is a follow-on to #463 to highlight what test values change when the finance models account for lifetime performance of the electrolyzer model. There is some new hard-coded logic introduced to show just this case. A subsequent PR will remove the added logic that's specific to the electrolyzer and will always use lifetime performance calculations for all technologies. This PR will help ensure that differing test values in the follow-on PR are not related to a change in the electrolyzer performance.

This PR should not be merged in until after PR #463 is.

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

  • Open draft PR
  • Describe the feature that will be added
  • Fill out TODO list steps
  • Describe requested feedback from reviewers on draft PR
  • Complete Section 7: New Model Checklist (if applicable)

TODO:

  • Step 1
  • Step 2

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

This partially resolves Issue #485 but not completely.

Section 4: Impacted Areas of the Software

Section 4.1: New Files

  • path/to/file.extension
    • method1: What and why something was changed in one sentence or less.

Section 4.2: Modified Files

  • examples/08_wind_electrolyzer/user_finance_model/simple_lco.py
  • examples/test/test_all_examples.py: see Section 6
  • h2integrate/core/h2integrate_model.py
  • h2integrate/finances/numpy_financial_npv.py
  • h2integrate/finances/profast_base.py
    • method1: What and why something was changed in one sentence or less.

Section 5: Additional Supporting Information

Section 6: Test Results, if applicable

Changed test values in test_all_examples.py

Tests where LCOH (or equivalent) decreased:

  • test_steel_example: LCOS also decreased
  • test_simple_ammonia_example
  • test_ammonia_synloop_example
  • test_co2h_methanol_example: LCOM decreased
  • test_splitter_wind_doc_h2_example
  • test_wind_solar_electrolyzer_example
  • test_wombat_electrolyzer_example: note that this test does not actually test the example using wombat
  • test_csvgen_design_of_experiments

Tests where LCOH increased:

  • test_hydrogen_dispatch_example
  • test_electrolyzer_om_example: this test is for the example that uses wombat. The reason the LCOH increased is because the capacity factor is lower when output from the wombat model (capacity factor of about 0.13) than the ECOElectrolyzerPerformanceModel (capacity factor of about 0.16).

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

elenya-grant and others added 30 commits January 20, 2026 15:27
Copy link
Collaborator

@jaredthomas68 jaredthomas68 left a comment

Choose a reason for hiding this comment

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

I know this is still a work in progress. I glanced through and am leaving a few comments.

Based on discussion in dev meetings, I also want to make sure we avoid using average lifetime production for each year because that could alter the financial results. If we have yearly, let's try to use that.

self.dt / 3600
)
outputs["capacity_factor"] = outputs["total_electricity_produced"].sum() / max_production
outputs["annual_electricity_produced"] = outputs["total_electricity_produced"] * (
Copy link
Collaborator

Choose a reason for hiding this comment

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

any reason to not just divide here?

outputs["annual_hydrogen_produced"] = np.sum(hydrogen_out_with_availability)

# Compute percent hydrogen lost due to O&M maintenance
# TODO: make below total rather than annual
Copy link
Collaborator

Choose a reason for hiding this comment

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

while touching this, we may want to reconsider the name since hydrogen_lost seems like leaks, but this is specifically for down-time. Maybe hydrogen_opportunity_cost_OM or something like that? #223

# output is minimum between available feedstocks and output demand
pig_iron_production = np.minimum.reduce(pig_iron_from_feedstocks)
outputs["pig_iron_out"] = pig_iron_production
outputs["total_pig_iron_produced"] = np.sum(pig_iron_production)
Copy link
Collaborator

Choose a reason for hiding this comment

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

As I understand it, DRI does not produce pig iron, it produces sponge iron (aka DRI-grade pellets).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Pig iron is specifically what comes out of a blast furnace I believe


outputs["rated_methanol_production"] = inputs["plant_capacity_kgpy"] / 8760
outputs["total_methanol_produced"] = outputs["methanol_out"].sum()
max_production = len(meoh_prod) * inputs["plant_capacity_kgpy"] / 8760
Copy link
Collaborator

Choose a reason for hiding this comment

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

double check this equation, seem like it may not be safe for varying dt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants