Skip to content

Commit

Permalink
Merge pull request #38 from NREL/develop
Browse files Browse the repository at this point in the history
Release: v0.1.3
  • Loading branch information
RHammond2 authored Nov 2, 2024
2 parents aa329cf + 6b40c6f commit ad7d7c8
Show file tree
Hide file tree
Showing 12 changed files with 37 additions and 132 deletions.
22 changes: 18 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,44 @@ jobs:
build:

runs-on: ubuntu-latest
defaults:
run:
shell: bash -el {0}
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
- uses: actions/checkout@v4
- name: Set up Miniconda Python ${{ matrix.python-version }}
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
python-version: ${{ matrix.python-version }}
channels: conda-forge
activate-environment: greenheart-test-${{ matrix.python-version }}
- name: Install dependencies
env:
SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL: True
run: |
sudo apt-get update && sudo apt-get install -y libglpk-dev glpk-utils coinor-cbc
python -m pip install --upgrade pip
pip install electrolyzer@git+https://github.com/jaredthomas68/electrolyzer.git@smoothing
pip install ProFAST@git+https://github.com/NREL/ProFAST.git
pip install ".[develop]"
- name: Create env file
run: |
touch .env
# echo NREL_API_KEY=${{ secrets.NREL_API_KEY }} >> .env
# cat .env
- name: Save environment build details
run: |
mkdir ~/artifacts
conda env export --file ~/artifacts/environment.yml
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.python-version }}-environment
path: ~/artifacts/environment.yml
- name: Run tests
run: |
PYTHONPATH=. pytest tests
Expand Down
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
# CHANGELOG

## v0.1.1 [28 October 2024]
## v0.1.3 [1 November 2024]

- Minor updates to examples for NAWEA workshop
- Replaces the git ProFAST installation with a PyPI installation.
- Removed dependence on external electrolyzer repo
- Updated CI to use conda environments with reproducible environment artifacts
- Rename logger from "wisdem/weis" to "greenheart"
- Remove unsupported optimization algorithms

## v0.1.2 [28 October 2024]

- Minor updates to examples for NAWEA workshop.
- Adds `environment.yml` for easy environment creation and GreenHEART installation.

## v0.1.1 [22 October 2024]

- ?

## v0.1 [16 October 2024]

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ pip install -e ".[all]"
```bash
conda install -y -c conda-forge glpk
pip install electrolyzer@git+https://github.com/jaredthomas68/electrolyzer.git@smoothing
pip install ProFAST@git+https://github.com/NREL/ProFAST.git
```

Note: Unix users should install Cbc via:
Expand Down
1 change: 0 additions & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ pip install -e ".[all]"
```bash
conda install -y -c conda-forge glpk
pip install electrolyzer@git+https://github.com/jaredthomas68/electrolyzer.git@smoothing
pip install ProFAST@git+https://github.com/NREL/ProFAST.git
```

````{note}
Expand Down
1 change: 0 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ dependencies:
- pip
- pip:
- electrolyzer@git+https://github.com/jaredthomas68/electrolyzer.git@smoothing
- ProFAST@git+https://github.com/NREL/ProFAST.git
- "."
2 changes: 1 addition & 1 deletion greenheart/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

__version__ = "0.1.2"
__version__ = "0.1.3"
2 changes: 0 additions & 2 deletions greenheart/tools/eco/electrolysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@

from greenheart.simulation.technologies.hydrogen.electrolysis.PEM_BOP.PEM_BOP import pem_bop

# from electrolyzer import run_electrolyzer


def run_electrolyzer_physics(
hopp_results,
Expand Down
28 changes: 0 additions & 28 deletions greenheart/tools/optimization/gc_PoseOptimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,6 @@ def __init__(self, config: GreenHeartSimulationConfig):

self.config = config

self.nlopt_methods = [
"GN_DIRECT",
"GN_DIRECT_L",
"GN_DIRECT_L_NOSCAL",
"GN_ORIG_DIRECT",
"GN_ORIG_DIRECT_L",
"GN_AGS",
"GN_ISRES",
"LN_COBYLA",
"LD_MMA",
"LD_CCSAQ",
"LD_SLSQP",
]

self.scipy_methods = [
"SLSQP",
"Nelder-Mead",
Expand Down Expand Up @@ -265,20 +251,6 @@ def set_driver(self, opt_prob):
]
opt_prob = self._set_optimizer_properties(opt_prob, options_keys)

elif opt_options["solver"] in self.nlopt_methods:
try:
from wisdem.optimization_drivers.nlopt_driver import NLoptDriver
except:
raise ImportError(
"You requested an optimization method from NLopt, but need to first install NLopt to use this method."
)

opt_prob.driver = NLoptDriver()
opt_prob.driver.options["optimizer"] = opt_options["solver"]
options_keys = ["tol", "xtol", "max_iter", "max_time", "numgen"]
mapped_keys = {"max_iter": "maxiter", "max_time": "maxtime"}
opt_prob = self._set_optimizer_properties(opt_prob, options_keys, mapped_keys=mapped_keys)

else:
raise ValueError(f"The {self.config.greenheart_config['opt_options']['driver']['optimization']['solver']} optimizer is not yet supported!")

Expand Down
2 changes: 1 addition & 1 deletion greenheart/tools/optimization/gc_run_greenheart.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def run_greenheart(config:GreenHeartSimulationConfig, overridden_values=None, ru
os.makedirs(folder_output, exist_ok=True)

# create logger
logger = logging.getLogger("wisdem/weis")
logger = logging.getLogger("greenheart")
logger.setLevel(logging.INFO)

# create handlers
Expand Down
90 changes: 0 additions & 90 deletions greenheart/tools/optimization/openmdao.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import numpy as np
import openmdao.api as om

import electrolyzer.inputs.validation as val
from electrolyzer import run_lcoh

from shapely.geometry import Polygon, Point
from hopp.simulation import HoppInterface
from greenheart.simulation.greenheart_simulation import GreenHeartSimulationConfig, run_simulation
Expand Down Expand Up @@ -305,90 +302,3 @@ def compute(self, inputs, outputs):

def setup_partials(self):
self.declare_partials('*', '*', method='fd', form='forward')

class ElectrolyzerComponent(om.ExplicitComponent):
"""
This is an OpenMDAO wrapper to the generic electrolyzer model.
It makes some assumptions about the number of electrolyzers, stack size, and
how to distribute electricity across the different electrolyzers. These
could be later made into modeling options to allow for more user configuration.
"""
def initialize(self):
self.options.declare("h2_modeling_options")
self.options.declare("h2_opt_options")
self.options.declare("modeling_options")
self.options.declare("design_variables",
# ["electrolyzer_rating_kw"],
types=list,
desc="List of design variables that should be included",
default=[],
recordable=False)

def setup(self):
self.add_input("power_signal", val=np.zeros(8760), units="W")
self.add_input("lcoe_real", units="USD/kW/h")

if "electrolyzer_rating_kw" in self.options["design_variables"]:
self.add_input("electrolyzer_rating_kw", val=15000, units="kW")

if self.options["h2_opt_options"]["control"]["system_rating_MW"]["flag"] \
or self.options["modeling_options"]["rating_equals_turbine_rating"]:
self.add_input("system_rating_MW", units="MW", val=self.options["h2_modeling_options"]["electrolyzer"]["control"]["system_rating_MW"])
self.add_output("h2_produced", units="kg")
self.add_output("max_curr_density", units="A/cm**2")
self.add_output("electrolyzer_capex", units="USD")
self.add_output("electrolyzer_opex", units="USD")
self.add_output("lcoh", units="USD/kg")
self.add_output("h2_produced_hourly", units="kg", val=np.zeros(8760))
self.add_output("power_kW_curtailed", units="kW", val=np.zeros(8760))
self.add_output("power_kW_avail", units="kW", val=np.zeros(8760))
# self.add_output("deg_state", units="V", val=np.zeros(6)) # TODO we need a way to size this dynamically

def compute(self, inputs, outputs):
# Set electrolyzer parameters from model inputs
power_signal = inputs["power_signal"]
lcoe_real = inputs["lcoe_real"][0]

if "electrolyzer_rating_kw" in inputs:
self.options["h2_modeling_options"]["electrolyzer"]["control"]["system_rating_MW"] = inputs["electrolyzer_rating_kw"][0]*1E-3

elif self.options["h2_opt_options"]["control"]["system_rating_MW"]["flag"] \
or self.options["modeling_options"]["rating_equals_turbine_rating"]:
self.options["h2_modeling_options"]["electrolyzer"]["control"]["system_rating_MW"] = inputs["system_rating_MW"][0]

elif "electrolyzer_rating_MW" in self.options["modeling_options"]["overridden_values"]:
electrolyzer_rating_MW = self.options["modeling_options"]["overridden_values"]["electrolyzer_rating_MW"]
self.options["h2_modeling_options"]["electrolyzer"]["control"]["system_rating_MW"] = electrolyzer_rating_MW

h2_prod, max_curr_density, lcoh, lcoh_dict, lcoh_options_dict, = run_lcoh(
self.options["h2_modeling_options"],
power_signal,
lcoe_real,
optimize=True
)

lt = lcoh_dict["LCOH Breakdown"]["Life Totals [$]"]
capex = lt["CapEx"]
opex = lt["OM"]

# msg = (
# f"\n====== Electrolyzer ======\n"
# f" - h2 produced (kg): {h2_prod}\n"
# f" - max current density (A/cm^2): {max_curr_density}\n"
# f" - LCOH ($/kg): {lcoh}\n"
# )

# logger.info(msg)
outputs["h2_produced"] = h2_prod
outputs["max_curr_density"] = max_curr_density
outputs["electrolyzer_capex"] = capex
outputs["electrolyzer_opex"] = opex
outputs["lcoh"] = lcoh
outputs["h2_produced_hourly"] = lcoh_options_dict["kg_produced"]
outputs["power_kW_curtailed"] = lcoh_options_dict["power_kW_curtailed"]
outputs["power_kW_avail"] = lcoh_options_dict["power_kW_avail"]
# outputs["deg_state"] = lcoh_options_dict["deg_state"] # TODO we need a way to size this dynamically

def setup_partials(self):
self.declare_partials('lcoh', '*', method='fd', form='forward')
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ dependencies = [
"HOPP>=3.0",
"orbit-nrel>=1.1",
"openmdao[all]",
"ProFAST",
]
keywords = [
"python3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_system_power_report(self):
comp = Compressor(p_outlet, flow_rate_kg_per_day, p_inlet=p_inlet, n_compressors=n_compressors, sizing_safety_factor=sizing_safety_factor)
comp.compressor_power()
_motor_rating, total_system_power = comp.compressor_system_power()
assert total_system_power == 3627.3907562149357
assert total_system_power == approx(3627.3907562149357)

def test_max_flow_rate_per_compressor(self):
p_inlet = 20 # bar
Expand Down

0 comments on commit ad7d7c8

Please sign in to comment.