Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
- Reduced import time for `h2integrate_model.py` by deferring imports of heavy dependencies until they are needed [PR 762](https://github.com/NatLabRockies/H2Integrate/pull/762)
- Added multivariable purge gas stream output to `AmmoniaSynLoopPerformanceModel` [PR 760](https://github.com/NatLabRockies/H2Integrate/pull/760)
- Add `constant` pricing mode for Grid cost models, allowing an explicit scalar price configuration alongside `per_timestep` and `per_year` modes. [PR 764](https://github.com/NatLabRockies/H2Integrate/pull/764)
- Renamed `design_of_experiments` to `parameter_sweep` throughout the codebase to avoid confusion with "Department of Energy" (DOE) in the energy domain. The core code supports both the new `parameter_sweep` and legacy `design_of_experiments` YAML keys for backward compatibility. Updated all driver configs, examples, tests, and documentation. Added generator type descriptions to the parameter sweep docs page and updated the run-cases docs to recommend parameter sweeps over manual for-loops. [PR 768](https://github.com/NatLabRockies/H2Integrate/pull/768)

## 0.8 [April 15, 2026]

Expand Down
2 changes: 1 addition & 1 deletion docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ parts:
- file: user_guide/connecting_technologies
- file: user_guide/defining_sites_and_resources
- file: user_guide/design_optimization_in_h2i
- file: user_guide/design_of_experiments_in_h2i
- file: user_guide/parameter_sweep_in_h2i
- file: user_guide/postprocessing_results
- file: user_guide/recording_and_loading_data
- file: user_guide/how_to_interface_with_user_defined_model
Expand Down
2 changes: 1 addition & 1 deletion docs/user_guide/design_optimization_in_h2i.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ We will lean on the `05_wind_h2_opt` example in the `examples` folder to illustr

```{note}
When we say "driver" in this context, we are referring to the optimizer that is used to solve the optimization problem as detailed in this [OpenMDAO doc page](https://openmdao.org/newdocs/versions/latest/basic_user_guide/single_disciplinary_optimization/first_optimization.html).
Drivers could also refer to a design of experiments (DOE) or other types of analysis that are not strictly optimizers.
Drivers could also refer to a parameter sweep (called "Design of Experiments" or DOE in OpenMDAO) or other types of analysis that are not strictly optimizers.
```


Expand Down
14 changes: 12 additions & 2 deletions docs/user_guide/how_to_run_several_cases_in_sequence.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

## Overview

If you have several different cases you want to run with different input parameters, these cases can be set up in an input spreadsheet rather than directly modifying the `tech_config`.
This is done using the functions in `h2integrate/tools/run_cases.py`
```{tip}
For most use cases where you want to sweep over different values of **design variables** (e.g., system capacities, number of clusters), we recommend using the built-in [parameter sweep capability](parameter_sweep_in_h2i.md).
It handles case generation, parallel execution, and result recording automatically.
```

The approach described on this page is intended for **advanced users** who need to modify **technology configuration** parameters between runs — values that are not exposed as design variables in the `driver_config.yaml`.
This is done using the functions in `h2integrate/tools/run_cases.py`.

```{warning}
The for-loop approach shown below does not automatically record results to a SQL file, does not support parallel execution, and requires manual post-processing.
Use the [parameter sweep](parameter_sweep_in_h2i.md) whenever possible.
```

## Setting up a variation of parameters in a .csv

Expand Down
2 changes: 1 addition & 1 deletion docs/user_guide/how_to_set_up_an_analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Once the configs are loaded into H2I and the model is instantiated, you can dire
This is an advanced approach that isn't necessarily recommended for basic users, but showcases the level of flexibility possible with H2I.

```{note}
The same behavior shown here with a manual for-loop can be achieved by using the [design of experiments capability](design_of_experiments_in_h2i.md).
The same behavior shown here with a manual for-loop can be achieved more easily by using the [parameter sweep capability](parameter_sweep_in_h2i.md), which is the recommended approach for most users.
```

```{code-cell} ipython3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,31 @@ kernelspec:
name: python3
---

# Design of experiments in H2I
# Parameter sweeps in H2I

One of the key features of H2Integrate is the ability to perform a design of experiments (DOE) for hybrid energy systems.
One of the key features of H2Integrate is the ability to perform **parameter sweeps** across hybrid energy systems.
A parameter sweep systematically varies one or more design variables across a range of values and evaluates the system at each combination, making it easy to explore the design space.

The design of experiments process uses the `driver_config.yaml` file to define the design sweep, including the design variables, constraints, and objective functions.
```{note}
Under the hood, H2Integrate uses OpenMDAO's [Design of Experiments (DOE) Driver](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/drivers/doe_generators.html) to perform parameter sweeps.
We use the term **parameter sweep** in H2Integrate to avoid confusion with the U.S. Department of Energy (DOE), which is frequently referenced in our domain.
If you see "DOE" or "Design of Experiments" in OpenMDAO documentation, it refers to the same capability called "parameter sweep" here.
```

The parameter sweep is configured through the `driver_config.yaml` file, which defines the sweep settings, design variables, constraints, and objective functions.
Detailed information on setting up the `driver_config.yaml` file can be found in the
[user guide](https://h2integrate.readthedocs.io/en/latest/user_guide/design_optimization_in_h2i.html)
[user guide](https://h2integrate.readthedocs.io/en/latest/user_guide/design_optimization_in_h2i.html).

```{tip}
Parameter sweeps are the **recommended way** to run multiple cases with different design variable values.
If you need to change technology configuration values (not just design variables), see the
[advanced for-loop approach](how_to_run_several_cases_in_sequence.md) instead.
```

## Driver config file

The driver config file defines the analysis type and the optimization or design of experiments settings.
For completeness, here is an example of a driver config file for a design of experiments problem:
The driver config file defines the analysis type and the parameter sweep settings.
For completeness, here is an example of a driver config file for a parameter sweep:

```{literalinclude} ../../examples/22_site_doe/driver_config.yaml
:language: yaml
Expand All @@ -31,7 +44,8 @@ For completeness, here is an example of a driver config file for a design of exp

## Types of Generators

H2Integrate currently supports the following types of generators:
H2Integrate supports the following generator types to create the set of cases for a parameter sweep.
Each generator produces combinations of design variable values using a different sampling strategy.

- ["uniform"](#uniform): uses the `UniformGenerator` generator
- ["fullfact"](#fullfactorial): uses the `FullFactorialGenerator` generator
Expand All @@ -45,9 +59,11 @@ Documentation for each generator type can be found on [OpenMDAO's documentation
(uniform)=
### Uniform

Generates random samples drawn uniformly between the lower and upper bounds of each design variable. Good for initial exploration when you have no prior knowledge of the design space.

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "uniform" #type of generator to use
num_samples: 10 #input is specific to this generator
Expand All @@ -57,50 +73,50 @@ driver:
(fullfactorial)=
### FullFactorial

Evaluates **every combination** of evenly spaced levels for each design variable. Provides complete coverage of the design space but grows exponentially with the number of variables (e.g., 3 variables with 4 levels = 64 cases).

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "fullfact" #type of generator to use
levels: 2 #input is specific to this generator
```

The **levels** input is the number of evenly spaced levels between each design variable lower and upper bound.

You can check the values that will be used for a specific design variable by running:

```python
import numpy as np

design_variable_values = np.linspace(lower_bound,upper_bound,levels)
```
The **levels** input is the number of evenly spaced levels between each design variable lower and upper bound, inclusive.

(plackettburman)=
### PlackettBurman

A screening method that uses a fractional factorial approach to identify which design variables have the **largest effect** on the outputs. Requires far fewer runs than a full factorial sweep, making it useful for narrowing down which variables matter most before performing a more detailed study.

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "plackettburman" #type of generator to use
```

(boxbehnken)=
### BoxBehnken

A response surface method that samples at the **midpoints of edges** and the center of the design space (never at the corners). Useful for fitting quadratic response surface models with fewer runs than a full factorial at three levels. Best suited for 3 or more design variables.

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "boxbehnken" #type of generator to use
```

(latinhypercube)=
### LatinHypercube

A space-filling method that divides each variable's range into equal-probability intervals and samples exactly once from each interval. Provides good coverage of the design space with fewer samples than a full factorial.

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "latinhypercube" #type of generator to use
num_samples: 10 #input is specific to this generator
Expand All @@ -111,11 +127,11 @@ driver:
(csv)=
### CSV

This method is useful if there are specific combinations of designs variables that you want to sweep. An example is shown here:
Allows you to specify **exact combinations** of design variable values in a CSV file. This is useful when you have specific scenarios you want to evaluate rather than a systematic sampling of the design space.

```yaml
driver:
design_of_experiments:
parameter_sweep:
flag: True
generator: "csvgen" #type of generator to use
filename: "cases_to_run.csv" #input is specific to this generator
Expand All @@ -132,7 +148,7 @@ You should check the csv file for potential formatting issues before running a s
This `csvgen` generator example reflects the work to produce the `examples/20_solar_electrolyzer_doe`
example.

We use the `examples/20_solar_electrolyzer_doe/driver_config.yaml` to run a design of experiments for
We use the `examples/20_solar_electrolyzer_doe/driver_config.yaml` to run a parameter sweep for
varying combinations of solar power and hydrogen electrolyzer capacities.

```{literalinclude} ../../examples/20_solar_electrolyzer_doe/driver_config.yaml
Expand All @@ -148,7 +164,7 @@ The different combinations of solar and electrolyzer capacities are listed in th
:language: text
```

Next, we'll import the required models and functions to complete run a successful design of experiments.
Next, we'll import the required models and functions to run a parameter sweep.

```{code-cell} ipython3
# Import necessary methods and packages
Expand All @@ -169,9 +185,9 @@ EXAMPLE_DIR = Path("../../examples/20_solar_electrolyzer_doe").resolve()
config = load_yaml(EXAMPLE_DIR / "20_solar_electrolyzer_doe.yaml")

driver_config = load_yaml(EXAMPLE_DIR / config["driver_config"])
csv_config_fn = EXAMPLE_DIR / driver_config["driver"]["design_of_experiments"]["filename"]
csv_config_fn = EXAMPLE_DIR / driver_config["driver"]["parameter_sweep"]["filename"]
config["driver_config"] = driver_config
config["driver_config"]["driver"]["design_of_experiments"]["filename"] = csv_config_fn
config["driver_config"]["driver"]["parameter_sweep"]["filename"] = csv_config_fn

config["technology_config"] = load_yaml(EXAMPLE_DIR / config["technology_config"])
config["plant_config"] = load_yaml(EXAMPLE_DIR / config["plant_config"])
Expand Down
6 changes: 3 additions & 3 deletions docs/user_guide/postprocessing_results.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ The `electricity_base_unit` argument (default: `"MW"`) controls the units used f
### Summarizing scalar results to CSV

While `save_case_timeseries_as_csv` exports time-series data, the `convert_sql_to_csv_summary` function extracts **scalar** results from one or more SQL recorder files and writes them to a single CSV summary.
This is especially useful when running parameter sweeps or DOE studies, where each row in the output corresponds to a different case.
This is especially useful when running parameter sweeps, where each row in the output corresponds to a different case.

The function:

Expand Down Expand Up @@ -212,9 +212,9 @@ model.post_process()
summary_df = convert_sql_to_csv_summary(model.recorder_path)
```

#### Summarizing parallel DOE results
#### Summarizing parallel parameter sweep results

When a DOE or parallel study is executed, H2Integrate writes one SQL file per process (e.g. `cases.sql_0`, `cases.sql_1`).
When a parameter sweep or parallel study is executed, H2Integrate writes one SQL file per process (e.g. `cases.sql_0`, `cases.sql_1`).
Pass the base name and the function handles the rest:

```python
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: H2Integrate_config
system_summary: Run DOE over solar and electrolyzer capacities
system_summary: Run parameter sweep over solar and electrolyzer capacities
driver_config: driver_config.yaml
technology_config: tech_config.yaml
plant_config: plant_config.yaml
4 changes: 2 additions & 2 deletions examples/20_solar_electrolyzer_doe/driver_config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
description: Driver config for CSVGen design of experiments
description: Driver config for CSVGen parameter sweep
name: driver_config
general:
folder_output: ex_20_out
create_om_reports: true
driver:
design_of_experiments:
parameter_sweep:
flag: true
debug_print: true
generator: csvgen
Expand Down
6 changes: 3 additions & 3 deletions examples/20_solar_electrolyzer_doe/run_csv_doe.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Minimal working example from the DOE user guide docs."""
"""Minimal working example from the parameter sweep user guide docs."""

from h2integrate import H2IntegrateModel
from h2integrate.core.dict_utils import update_defaults
Expand All @@ -9,7 +9,7 @@
config = load_yaml("20_solar_electrolyzer_doe.yaml")

driver_config = load_yaml(config["driver_config"])
csv_config_fn = driver_config["driver"]["design_of_experiments"]["filename"]
csv_config_fn = driver_config["driver"]["parameter_sweep"]["filename"]

try:
model = H2IntegrateModel(config)
Expand Down Expand Up @@ -43,7 +43,7 @@
new_csv_filename.name,
)
driver_config["driver"].update(updated_driver)
print(f"New DOE driver CSV file: {new_csv_filename}")
print(f"New parameter sweep driver CSV file: {new_csv_filename}")

# Step 3
config["driver_config"] = driver_config
Expand Down
2 changes: 1 addition & 1 deletion examples/21_iron_examples/iron_mapping/driver_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: This analysis runs a hybrid plant to match the first example in H2I
general:
folder_output: ex_out
driver:
design_of_experiments:
parameter_sweep:
flag: true
debug_print: false
generator: csvgen
Expand Down
2 changes: 1 addition & 1 deletion examples/22_site_doe/22_solar_site_doe.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: H2Integrate_config
system_summary: Run DOE over solar capacities and site locations
system_summary: Run parameter sweep over solar capacities and site locations
driver_config: driver_config.yaml
technology_config: tech_config.yaml
plant_config: plant_config.yaml
4 changes: 2 additions & 2 deletions examples/22_site_doe/driver_config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
description: Driver config for CSVGen design of experiments
description: Driver config for CSVGen parameter sweep
name: driver_config
general:
folder_output: ex_22_out
create_om_reports: false
driver:
design_of_experiments:
parameter_sweep:
flag: true
debug_print: true
generator: csvgen
Expand Down
2 changes: 1 addition & 1 deletion examples/27_site_doe_diff/27_wind_solar_site_doe.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: H2Integrate_config
system_summary: Run DOE over solar capacities and site locations
system_summary: Run parameter sweep over solar capacities and site locations
driver_config: driver_config.yaml
technology_config: tech_config.yaml
plant_config: plant_config.yaml
4 changes: 2 additions & 2 deletions examples/27_site_doe_diff/driver_config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
description: Driver config for CSVGen design of experiments
description: Driver config for CSVGen parameter sweep
name: driver_config
general:
folder_output: ex_27_out
create_om_reports: false
driver:
design_of_experiments:
parameter_sweep:
flag: true
debug_print: false
generator: csvgen
Expand Down
4 changes: 2 additions & 2 deletions examples/test/test_all_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -1746,7 +1746,7 @@ def test_windard_pv_battery_dispatch_example(subtests, temp_copy_of_example):
@pytest.mark.parametrize(
"example_folder,resource_example_folder", [("20_solar_electrolyzer_doe", None)]
)
def test_csvgen_design_of_experiments(subtests, temp_copy_of_example):
def test_csvgen_parameter_sweep(subtests, temp_copy_of_example):
example_folder = temp_copy_of_example

with pytest.raises(UserWarning) as excinfo:
Expand All @@ -1760,7 +1760,7 @@ def test_csvgen_design_of_experiments(subtests, temp_copy_of_example):
# load the driver config file
driver_config = load_driver_yaml("driver_config.yaml")
# specify the filepath to the csv file
csv_fpath = Path(driver_config["driver"]["design_of_experiments"]["filename"]).absolute()
csv_fpath = Path(driver_config["driver"]["parameter_sweep"]["filename"]).absolute()
# run the csv checker method, we want it to write the csv file to a new filepath so
# set overwrite_file=False
new_csv_filename = check_file_format_for_csv_generator(
Expand Down
2 changes: 1 addition & 1 deletion h2integrate/converters/solar/test/test_pysam_solar.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def test_pvwatts_singleowner_notilt_different_site(basic_pysam_options, plant_co
"""

driver_config = {
"driver": {"design_of_experiments": {"flag": True}},
"driver": {"parameter_sweep": {"flag": True}},
"design_variables": {
"site": {
"latitude": {},
Expand Down
Loading
Loading