Automatically Extending a Parameter Study#
Warning
The waves build feature is considered experimental. The feature should be treated like an alpha feature whose
design, behavior, and interface may change without notice. This feature is documented to solicit user feedback on
preferred behavior and usefulness.
Warning
This tutorial is in a draft outline state. It is provided as reference and will be fleshed out in future releases. Be sure to check back in on this tutorial or watch the Changelog for updates!
References#
WAVES Command-Line Utility build subcommand
WAVES Parameter Generators API:
waves.parameter_generators.SobolSequence()Xarray and the xarray dataset [46, 47]
Environment#
SCons and WAVES can be installed in a Conda environment with the Conda package manager. See the Conda installation and Conda environment management documentation for more details about using Conda.
Note
The SALib and numpy versions may not need to be this strict for most tutorials. However, Tutorial: Sensitivity Study uncovered some undocumented SALib version sensitivity to numpy surrounding the numpy v2 rollout.
Create the tutorials environment if it doesn’t exist
$ conda create --name waves-tutorial-env --channel conda-forge waves 'scons>=4.6' matplotlib pandas pyyaml xarray seaborn 'numpy>=2' 'salib>=1.5.1' pytest
PS > conda create --name waves-tutorial-env --channel conda-forge waves scons matplotlib pandas pyyaml xarray seaborn numpy salib pytest
Activate the environment
$ conda activate waves-tutorial-env
PS > conda activate waves-tutorial-env
Some tutorials require additional third-party software that is not available for the Conda package manager. This
software must be installed separately and either made available to SConstruct by modifying your system’s PATH or by
modifying the SConstruct search paths provided to the waves.scons_extensions.add_program() method.
Directory Structure#
Create and change to a new project root directory to house the tutorial files if you have not already done so. For example
$ mkdir -p ~/waves-tutorials
$ cd ~/waves-tutorials
$ pwd
/home/roppenheimer/waves-tutorials
PS > New-Item $HOME\waves-tutorials -ItemType "Directory"
PS > Set-Location $HOME\waves-tutorials
PS > Get-Location
Path
----
C:\Users\roppenheimer\waves-tutorials
Note
If you skipped any of the previous tutorials, run the following commands to create a copy of the necessary tutorial files.
$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --overwrite --tutorial 8 && mv tutorial_08_data_extraction_SConstruct SConstruct
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
PS > Get-Location
Path
----
C:\Users\roppenheimer\waves-tutorials
PS > waves fetch --overwrite --tutorial 8 && Move-Item tutorial_08_data_extraction_SConstruct SConstruct -Force
WAVES fetch
Destination directory: 'C:\Users\roppenheimer\waves-tutorials'
Download and copy the
tutorial_08_data_extraction.sconsfile to a new file namedtutorial_extend_study.sconswith the WAVES Command-Line Utility fetch subcommand.
$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --overwrite tutorials/tutorial_08_data_extraction.scons && cp tutorial_08_data_extraction.scons tutorial_extend_study.scons
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
PS > Get-Location
Path
----
C:\Users\roppenheimer\waves-tutorials
PS > waves fetch --overwrite tutorials\tutorial_08_data_extraction.scons && Copy-Item tutorial_08_data_extraction.scons tutorial_extend_study.scons
WAVES fetch
Destination directory: 'C:\Users\roppenheimer\waves-tutorials'
SConscript#
A diff against the tutorial_08_data_extraction.scons file from Tutorial 08: Data Extraction is included below
to help identify the differences between the two parameter generators and workflows.
waves-tutorials/tutorial_extend_study.scons
--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_08_data_extraction.scons
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_extend_study.scons
@@ -13,7 +13,7 @@
import waves
-from modsim_package.python.rectangle_compression_cartesian_product import parameter_schema
+from modsim_package.python.rectangle_compression_sobol_sequence import parameter_schema
# Inherit the parent construction environment
Import("env")
@@ -24,6 +24,11 @@
build_directory = pathlib.Path(Dir(".").abspath)
workflow_name = build_directory.name
parameter_study_file = build_directory / "parameter_study.h5"
+extended_parameter_study_file = build_directory / "extended_parameter_study.h5"
+simulation_constants = {
+ "global_seed": 1,
+ "displacement": -0.01,
+}
# Collect the target nodes to build a concise alias for all targets
workflow = []
@@ -31,10 +36,11 @@
# Comment used in tutorial code snippets: marker-2
-# Parameter Study with Cartesian Product
-parameter_generator = waves.parameter_generators.CartesianProduct(
+# Parameter Study with Sobol Sequence
+parameter_generator = waves.parameter_generators.SobolSequence(
parameter_schema(),
- previous_parameter_study=parameter_study_file,
+ previous_parameter_study=extended_parameter_study_file,
+ scramble=False,
)
parameter_generator.write(output_file=parameter_study_file)
@@ -43,7 +49,7 @@
# Parameterized targets must live inside current simulation_variables for loop
for set_name, parameters in parameter_generator.parameter_study_to_dict().items():
set_path = pathlib.Path(set_name)
- simulation_variables = parameters
+ simulation_variables = {**parameters, **simulation_constants}
# Comment used in tutorial code snippets: marker-4
@@ -159,6 +165,22 @@
# Comment used in tutorial code snippets: marker-6
+# Post-processing
+post_processing_source = [
+ pathlib.Path(set_name) / "rectangle_compression_datasets.h5"
+ for set_name in parameter_generator.parameter_study_to_dict()
+]
+workflow.extend(
+ env.PythonScript(
+ target=[extended_parameter_study_file.name],
+ source=["#/modsim_package/python/tutorial_extend_study.py", parameter_study_file.name, *post_processing_source],
+ subcommand_options=(
+ "--input-file ${SOURCES[2:].abspath} --parameter-study-file ${SOURCES[1].abspath}"
+ " --output-file ${TARGETS[0].abspath}"
+ ),
+ )
+)
+
# Collector alias based on parent directory name
env.Alias(workflow_name, workflow)
env.Alias(f"{workflow_name}_datacheck", datacheck)
This post-processing workflow should look nearly identical to the post-processing tasks introduced in
Tutorial 09: Post-Processing. The difference in this tutorial is that there are two parameter study files to track.
The configuration time parameter study is written to parameter_study.h5 as before, but the
previous_parameter_study now reads from a new file, extended_parameter_study.h5, which does not exist until the
workflow is run at least once.
A post-processing task is written to generate the extended_parameter_study.h5 as a final step of the workflow. As
shown in the next section where the post-processing file is introduced, this task reads the parameter_study.h5 file
and the associated simulation results, performs some analysis, and either writes new parameter sets into the
extended_parameter_study.h5 file or simply creates a copy of the parameter_study.h5 file. Because the
configuration time parameter study reads from extended_parameter_study.h5, the next time the workflow is executed,
it will pick up any new parameter sets and configure the new sets as part of the workflow. This process of performing
new work continues until the the post-processing task no longer recommends new parameter sets.
Both the configuration time parameter study definition found in the SConscript file and the post-processing
parameter study extension take advantage of the WAVES feature that preserves set name assignments of the original
parameter sets. At each re-execution of the workflow, parameter sets that have already been seen preserve their original
set names and set contents. Those set-named output files already exist, so re-work is minimized to the newest parameter
sets.
The WAVES build subcommand was written to help automate the process of re-execution. The command is
written to continue re-submitting the normal scons command until SCons reports that there is no new work to
complete, as when the post-processing script no longer recommends new parameter sets, or until the maximum number of
iterations has been reached.
Post-processing script#
In the
waves-tutorials/modsim_package/pythondirectory, create a file calledtutorial_extend_study.pyusing the contents below.
waves-tutorials/modsim_package/python/tutorial_extend_study.py
"""Read simulation output, process data, recommend new parameter sets, write updated parameter study."""
import argparse
import copy
import pathlib
import shutil
import typing
import waves
from modsim_package.python.rectangle_compression_sobol_sequence import parameter_schema
def main(
input_files: typing.Sequence[pathlib.Path],
parameter_study_file: pathlib.Path,
output_file: pathlib.Path | None = None,
) -> None:
"""Read simulation output, process data, recommend new parameter sets, write updated parameter study."""
set_count = len(input_files)
if set_count < 8:
new_schema = copy.deepcopy(parameter_schema())
new_schema["num_simulations"] = set_count + 2
new_generator = waves.parameter_generators.SobolSequence(
new_schema,
previous_parameter_study=parameter_study_file,
scramble=False,
)
new_generator.write(output_file=output_file)
else:
shutil.copyfile(parameter_study_file, output_file)
def get_parser() -> argparse.ArgumentParser:
"""Return parser for CLI options."""
script_name = pathlib.Path(__file__)
prog = f"python {script_name.name} "
cli_description = "Read Xarray Datasets, process data, recommend new parameter sets, write updated parameter study."
parser = argparse.ArgumentParser(description=cli_description, prog=prog)
required_named = parser.add_argument_group("required named arguments")
required_named.add_argument(
"-i",
"--input-file",
nargs="+",
type=pathlib.Path,
required=True,
help="The Xarray Dataset file(s)",
)
required_named.add_argument(
"-p",
"--parameter-study-file",
type=pathlib.Path,
help="An optional h5 file with a WAVES parameter study Xarray Dataset (default: %(default)s)",
)
parser.add_argument(
"-o",
"--output-file",
type=pathlib.Path,
help=("The parameter study with new parameter sets."),
)
return parser
if __name__ == "__main__":
parser = get_parser()
args = parser.parse_args()
main(
input_files=args.input_file,
output_file=args.output_file,
parameter_study_file=args.parameter_study_file,
)
This post-processing script is a stripped down version of the post_processing.py script introduced in
Tutorial 09: Post-Processing. The tutorial_extend_study.py script simply checks the number of simulations and
increases the size of the parameter study to a hardcoded value. This simple implementation is intended only to
demonstrate the workflow and task structure of an automatically extending workflow.
In real projects, the purpose of extending a parameter is to perform an optimization or uncertainty quantification
workflow. A post-processing script more similar to the post_processing.py script of Tutorial 09: Post-Processing
or Tutorial: Sensitivity Study would perform some kind of sensitivity analysis or uncertainty quantification and
recommend new parameter sets to meet an objective function. Such a workflow may also require several post-processing
steps, such as training a reduced-order or surrogate model which is used to investigate a larger parameter space before
recommending parameter sets to investigate with the original, higher cost simulations.
In all these examples, the outcome of the post-processing step should be new parameter sets that are added to the original parameter study. On re-execution of the workflow, the new parameter sets are read into the workflow definition and the workflow picks up with the new parameter sets without re-computing the old ones.
SConstruct#
A diff against the SConstruct file from Tutorial 08: Data Extraction is included below to help identify the
changes made in this tutorial.
waves-tutorials/SConstruct
--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_08_data_extraction_SConstruct
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_extend_study_SConstruct
@@ -99,7 +99,8 @@
"tutorial_05_parameter_substitution.scons",
"tutorial_06_include_files.scons",
"tutorial_07_cartesian_product.scons",
- "tutorial_08_data_extraction.scons",
+ "tutorial_07_sobol_sequence.scons",
+ "tutorial_extend_study.scons",
]
for workflow in workflow_configurations:
workflow_build_directory = build_directory / pathlib.Path(workflow).stem
Build Targets#
Build the new targets
$ pwd
/home/roppenheimer/waves-tutorials
$ waves build --max-iterations=4 tutorial_extend_study --jobs=4
Output Files#
$ pwd
/home/roppenheimer/waves-tutorials
$ tree build/tutorial_extend_study -d
build/tutorial_extend_study
|-- parameter_set0
|-- parameter_set1
|-- parameter_set2
|-- parameter_set3
|-- parameter_set4
|-- parameter_set5
|-- parameter_set6
`-- parameter_set7
8 directories