Tutorial 05: Parameter Substitution#
References#
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
Activate the environment
$ 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.
Warning
STOP! Before continuing, check that the documentation version matches your installed package version.
You can find the documentation version in the upper-left corner of the webpage.
You can find the installed WAVES version with
waves --version
.
If they don’t match, you can launch identically matched documentation with the WAVES Command-Line Utility
docs subcommand as waves docs
.
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
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 4 && mv tutorial_04_simulation_SConstruct SConstruct
Destination directory: '/home/roppenheimer/waves-tutorials'
Download and copy the
tutorial_04_simulation
file to a new file namedtutorial_05_parameter_substitution
with the WAVES Command-Line Utility fetch subcommand.
$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --overwrite tutorials/tutorial_04_simulation && cp tutorial_04_simulation tutorial_05_parameter_substitution
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
Solver Input Files#
Copy the
modsim_package/abaqus/rectangle_compression.inp
file and all of its contents to a new file in the same directory namedrectangle_compression.inp.in
. Note: the only change in the file name is the addition of the.in
suffix.
$ pwd
/home/roppenheimer/waves-tutorials
$ cp modsim_package/abaqus/rectangle_compression.inp modsim_package/abaqus/rectangle_compression.inp.in
In this tutorial, we will be modifying several files from Tutorial 04: Simulation, the first of which is
rectangle_compression.inp
. We copy this file and all of its contents to a new file with the same basename and
the .in
extension for the purposes of parameter substitution. This change is made so it is easy for the
waves.scons_extensions.copy_substfile()
method to identify which files should be searched for parameters. Any files with
the .in
extension that are passed to the waves.scons_extensions.copy_substfile()
method will be parsed for
characters matching the parameter definitions using substitution with SCons Substfile. This is discussed in
more detail later in this tutorial.
Use the
diff
below to modify yourrectangle_compression.inp.in
file.
waves-tutorials/modsim_package/abaqus/rectangle_compression.inp.in
--- /home/runner/work/waves/waves/build/docs/abaqus_rectangle_compression.inp
+++ /home/runner/work/waves/waves/build/docs/abaqus_rectangle_compression.inp.in
@@ -22,7 +22,7 @@
.005, 1.00, 0.000001, 0.5
**
*BOUNDARY, OP=MOD
-A.rectangle.top,2,2,-0.01
+A.rectangle.top,2,2,@displacement@
**
*MONITOR, DOF=2, NODE=A.rectangle.top_right
**
The modification made to the rectangle_compression.inp.in
file is to replace the hardcoded displacement value
of -1.0
with the parameter substitution key @displacement@
. Note that the SCons Substfile builder performs a
literal string substitution in the target file, so it is necessary to prepare the correct syntax for the file type where
the substitution occurs.
SConscript#
Modify your
tutorial_05_parameter_substitution
file by adding the contents shown below to the code pertaining to# Simulation variables
. The entire code snippet shows how your code should look after editing, and the highlghted portion is what needs to be added to your existing code.
waves-tutorials/tutorial_05_parameter_substitution
18# Simulation variables
19build_directory = pathlib.Path(Dir(".").abspath)
20workflow_name = build_directory.name
21simulation_variables = {
22 "width": 1.0,
23 "height": 1.0,
24 "global_seed": 1.0,
25 "displacement": -0.01,
26}
In the code you just added, a simulation_variables
dictionary is defined. Each key-value pair in the
simulation_variables
dictionary defines a parameter that already exists in several of the scripts we have utilized
in the previous tutorials. The width
and height
parameters are used in the rectangle_geometry.py
and
rectangle_partition.py
scripts, and global_seed
is used in the rectangle_mesh.py
script. Recall
that each of these scripts is called using a command-line interface that has default parameters. See the
WAVES-TUTORIAL CLI to see what the default values are. As mentioned in Tutorial 01: Geometry, the argument
parser for each of these scripts will supply a default value for each command-line argument that is not specified
(assuming a defualt value was specified in the argument parser definition). This allowed us to simplify the command
passed to the waves.scons_extensions.abaqus_journal_builder_factory()
builder. The advantage to coding this behavior ahead of time is that
we get parameter substitution into our journal files when we need it. The width
, height
, and global_seed
keys of the simulation_variables
dictionary will be used later in this tutorial to specify the values passed to the
journal files via the CLI.
The final key-value pair defined in the simulation_variables
dictionary is displacement
. This parameter will be
used in a slightly different way than the others, as the script that utilizes this parameter does not function with a
command-line interface. Recall from earlier in this tutorial, we created a new file called
rectangle_compression.inp.in
and added the @displacement@
key. This text file parameter substitution is
the primary reason the @
characters are required in the simulation_variables
keys. Disussion of exactly how
this is implemented with the waves.scons_extensions.copy_substfile()
method will come later in this tutorial.
Modify your
tutorial_05_parameter_substitution
file by using the highlighed lines below to modify thesubcommand_options
for the code pertaining to# Geometry
,# Partition
, and# Mesh
.
waves-tutorials/tutorial_05_parameter_substitution
30# Collect the target nodes to build a concise alias for all targets
31workflow = []
32datacheck = []
33
34# Geometry
35workflow.extend(
36 env.AbaqusJournal(
37 target=["rectangle_geometry.cae", "rectangle_geometry.jnl"],
38 source=["#/modsim_package/abaqus/rectangle_geometry.py"],
39 subcommand_options="--width ${width} --height ${height}",
40 **simulation_variables,
41 )
42)
43
44# Comment used in tutorial code snippets: marker-2
45
46# Partition
47workflow.extend(
48 env.AbaqusJournal(
49 target=["rectangle_partition.cae", "rectangle_partition.jnl"],
50 source=["#/modsim_package/abaqus/rectangle_partition.py", "rectangle_geometry.cae"],
51 subcommand_options="--width ${width} --height ${height}",
52 **simulation_variables,
53 )
54)
55
56# Mesh
57workflow.extend(
58 env.AbaqusJournal(
59 target=["rectangle_mesh.inp", "rectangle_mesh.cae", "rectangle_mesh.jnl"],
60 source=["#/modsim_package/abaqus/rectangle_mesh.py", "rectangle_partition.cae"],
61 subcommand_options="--global-seed ${global_seed}",
62 **simulation_variables,
63 )
64)
As was previously discussed, we use the key-value pairs of the simulation_variables
dictionary in the arguments we
pass to the command-line interfaces for rectangle_{geometry,partition,mesh}.py
. Using SCons variable
substitution as shown in the first highlighted section, we will end up passing a string that looks like the following to
the rectangle_geometry.py
CLI:
--width 1.0 --height 1.0
Note that the keyword arguments subcommand_options
, width
, height
, and global_options
are not part of the
normal builder interface. SCons will accept these keyword arguments and use them as substitution variables as part of
the task definition. We can use this feature to pass arbitrary variables to the builder task construction on a per-task
basis without affecting other tasks which use the same builder. For instance, the # Mesh
task will not have access
to the width
and height
substitutions because we have not specified those keyword arguments.
This behavior is repeated for the code pertaining to # Partition
and # Mesh
. SCons will save a signature of
the completed action string as part of the task definition. If the substituted parameter values change, SCons will
recognize that the tasks need to be re-executed in the same way that tasks need to be re-executed when the contents of a
source file change.
Modify your
tutorial_05_parameter_substitution
file by using the highlighed lines below to modify the code pertaining to# SolverPrep
.
waves-tutorials/tutorial_05_parameter_substitution
68# SolverPrep
69copy_source_list = [
70 "#/modsim_package/abaqus/rectangle_compression.inp.in",
71 "#/modsim_package/abaqus/assembly.inp",
72 "#/modsim_package/abaqus/boundary.inp",
73 "#/modsim_package/abaqus/field_output.inp",
74 "#/modsim_package/abaqus/materials.inp",
75 "#/modsim_package/abaqus/parts.inp",
76 "#/modsim_package/abaqus/history_output.inp",
77]
78workflow.extend(
79 env.CopySubstfile(
80 copy_source_list,
81 substitution_dictionary=env.SubstitutionSyntax(simulation_variables),
82 )
83)
Per the changes you made earlier in this tutorial, the abaqus_source_list
must be updated to reflect the replacement
of rectangle_compression.inp
with the parameterized rectangle_compression.inp.in
file.
The final change to be made in the tutorial_05_parameter_substitution
file is to utilize the
substitution_dictionary
parameter in the usage of the waves.scons_extensions.copy_substfile()
method.
In this tutorial, we leverage two different builder behaviors when defining sources and targets for the
waves.scons_extensions.copy_substfile()
method. We are already familiar with one behavior, where the builder
simply copies the source file to the build directory.
The second behavior is to apply template substitution on files with the *.in
extension in the abaqus_source_list
using a substitution_dictionary
provided in the builder’s options. The builder will search any file with the .in
extension for strings matching substitution_dictionary
parameter keys. Any key found in the file’s text will be
replaced with the corresponding substitution_dictionary
value. To avoid spurious text replacements on text unrelated
to our parameters, we must make our parameter names uniquely identifiable with a templating character (e.g.
@variable@
). To avoid carrying around two copies of the simulation variables dictionary, one with the special
characters and one without, the waves.scons_extensions.substitution_syntax()
method can be used to modify the
simulation variable dictionary keys as needed.
In this template substitution process, the files with .in
are first copied to a file of the same name in the build
directory. The contents of the newly copied file are modified to reflect the parameter substitution and the .in
extension is removed as a default behavior of the SCons Substfile method. The two step copy/substitute behavior is
required to allow SCons to unambiguously resolve the source-target file locations. We will see this behavior more
clearly when we investigate the Output Files for this tutorial. The
substitution
dictionary becomes part of the task signature for all *.in
files. When the dictionary changes, the
copy and substitute operations will be re-executed.
In summary of the changes you just made to the tutorial_05_parameter_substitution
file, a diff
against the
SConscript
file from Tutorial 04: Simulation is included below to help identify the
changes made in this tutorial.
waves-tutorials/tutorial_05_parameter_substitution
--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_04_simulation
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_05_parameter_substitution
@@ -14,9 +14,17 @@
# Inherit the parent construction environment
Import("env")
+# Comment used in tutorial code snippets: marker-0
+
# Simulation variables
build_directory = pathlib.Path(Dir(".").abspath)
workflow_name = build_directory.name
+simulation_variables = {
+ "width": 1.0,
+ "height": 1.0,
+ "global_seed": 1.0,
+ "displacement": -0.01,
+}
# Comment used in tutorial code snippets: marker-1
@@ -29,7 +37,8 @@
env.AbaqusJournal(
target=["rectangle_geometry.cae", "rectangle_geometry.jnl"],
source=["#/modsim_package/abaqus/rectangle_geometry.py"],
- subcommand_options="",
+ subcommand_options="--width ${width} --height ${height}",
+ **simulation_variables,
)
)
@@ -40,7 +49,8 @@
env.AbaqusJournal(
target=["rectangle_partition.cae", "rectangle_partition.jnl"],
source=["#/modsim_package/abaqus/rectangle_partition.py", "rectangle_geometry.cae"],
- subcommand_options="",
+ subcommand_options="--width ${width} --height ${height}",
+ **simulation_variables,
)
)
@@ -49,7 +59,8 @@
env.AbaqusJournal(
target=["rectangle_mesh.inp", "rectangle_mesh.cae", "rectangle_mesh.jnl"],
source=["#/modsim_package/abaqus/rectangle_mesh.py", "rectangle_partition.cae"],
- subcommand_options="",
+ subcommand_options="--global-seed ${global_seed}",
+ **simulation_variables,
)
)
@@ -57,7 +68,7 @@
# SolverPrep
copy_source_list = [
- "#/modsim_package/abaqus/rectangle_compression.inp",
+ "#/modsim_package/abaqus/rectangle_compression.inp.in",
"#/modsim_package/abaqus/assembly.inp",
"#/modsim_package/abaqus/boundary.inp",
"#/modsim_package/abaqus/field_output.inp",
@@ -68,6 +79,7 @@
workflow.extend(
env.CopySubstfile(
copy_source_list,
+ substitution_dictionary=env.SubstitutionSyntax(simulation_variables),
)
)
SConstruct#
Add
tutorial_05_parameter_substitution
to theworkflow_configurations
list in thewaves-tutorials/SConstruct
file.
A diff
against the SConstruct
file from Tutorial 04: Simulation is included below to help identify the
changes made in this tutorial.
waves-tutorials/SConstruct
--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_04_simulation_SConstruct
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_05_parameter_substitution_SConstruct
@@ -100,6 +100,7 @@
"tutorial_02_partition_mesh",
"tutorial_03_solverprep",
"tutorial_04_simulation",
+ "tutorial_05_parameter_substitution",
]
for workflow in workflow_configurations:
build_dir = env["variant_dir_base"] / workflow
A previous tutorial constructed the simulation_variables
and the substitution_dictionary
variables. The
simulation_variables
dictionary is used to define simulation parameters for SCons project configuration and script
command-line interfaces. The substitution_dictionary
is constructed from the simulation_variables
dictionary to
apply the parameter substitution syntax (leading and trailing @
character) to each variable name for use with the
copy_substfile
method as introduced in the current tutorial.
Build Targets#
Build the new targets
$ pwd
/home/roppenheimer/waves-tutorials
$ scons tutorial_05_parameter_substitution
scons: Reading SConscript files ...
Checking whether /apps/abaqus/Commands/abq2024 program exists.../apps/abaqus/Commands/abq2024
Checking whether abq2024 program exists.../apps/abaqus/Commands/abq2024
scons: done reading SConscript files.
scons: Building targets ...
cd /home/roppenheimer/waves-tutorials/build/tutorial_05_parameter_substitution && /apps/abaqus/Commands/abq2024 cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_geometry.py -- --width 1.0 --height 1.0 > rectangle_geometry.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/build/tutorial_05_parameter_substitution && /apps/abaqus/Commands/abq2024 cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_partition.py -- --width 1.0 --height 1.0 > rectangle_partition.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/build/tutorial_05_parameter_substitution && /apps/abaqus/Commands/abq2024 cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_mesh.py -- --global-seed 1.0 > rectangle_mesh.stdout 2>&1
Copy("build/tutorial_05_parameter_substitution/rectangle_compression.inp.in", "modsim_package/abaqus/rectangle_compression.inp.in")
Creating 'build/tutorial_05_parameter_substitution/rectangle_compression.inp'
Copy("build/tutorial_05_parameter_substitution/assembly.inp", "modsim_package/abaqus/assembly.inp")
Copy("build/tutorial_05_parameter_substitution/boundary.inp", "modsim_package/abaqus/boundary.inp")
Copy("build/tutorial_05_parameter_substitution/field_output.inp", "modsim_package/abaqus/field_output.inp")
Copy("build/tutorial_05_parameter_substitution/materials.inp", "modsim_package/abaqus/materials.inp")
Copy("build/tutorial_05_parameter_substitution/parts.inp", "modsim_package/abaqus/parts.inp")
Copy("build/tutorial_05_parameter_substitution/history_output.inp", "modsim_package/abaqus/history_output.inp")
cd /home/roppenheimer/waves-tutorials/build/tutorial_05_parameter_substitution && /apps/abaqus/Commands/abq2024 -job rectangle_compression -input rectangle_compression -double both -interactive -ask_delete no > rectangle_compression.stdout 2>&1
scons: done building targets.
Output Files#
Explore the contents of the build
directory using the tree
command against the build
directory, as shown
below. Note the usage of the -I
option to reduce clutter in the tree
command output.
$ pwd
/home/roppenheimer/waves-tutorials
$ tree build/tutorial_05_parameter_substitution
build/tutorial_05_parameter_substitution
|-- abaqus.rpy
|-- abaqus.rpy.1
|-- abaqus.rpy.2
|-- assembly.inp
|-- boundary.inp
|-- field_output.inp
|-- history_output.inp
|-- materials.inp
|-- parts.inp
|-- rectangle_compression.com
|-- rectangle_compression.dat
|-- rectangle_compression.inp
|-- rectangle_compression.inp.in
|-- rectangle_compression.msg
|-- rectangle_compression.odb
|-- rectangle_compression.prt
|-- rectangle_compression.sta
|-- rectangle_compression.stdout
|-- rectangle_geometry.cae
|-- rectangle_geometry.jnl
|-- rectangle_geometry.stdout
|-- rectangle_mesh.cae
|-- rectangle_mesh.inp
|-- rectangle_mesh.jnl
|-- rectangle_mesh.stdout
|-- rectangle_partition.cae
|-- rectangle_partition.jnl
`-- rectangle_partition.stdout
0 directories, 28 files
The output files for this tutorial are very similar to those from Tutorial 04: Simulation with a few key differences.
Most importantly, note that the build directory contains a file named rectangle_compression.inp.in
, which is
the file we created earlier in this tutorial. There is also a file named rectangle_compression.inp
.
Investigate the contents of
rectangle_compression.inp
using your preferred text editor. Specifically, look in the step definition where we defined thedisplacement
parameter. You should see the following:
1*STEP, NLGEOM=NO, INC=100, AMPLITUDE=RAMP
2*STATIC
3.005, 1.00, 0.000001, 0.5
4**
5*BOUNDARY,OP=MOD
6A.rectangle.top,2,2,-0.01
7**
With the use of the waves.scons_extensions.copy_substfile()
method, we used the rectangle_compression.inp.in
file as the source and the rectangle_compression.inp
file was the target. The builder acted by substituting the
parameter key @displacement@
with the parameter value -1.0
, and then generated the target with this information
in the text, as shown above.
It is also worth noting that that there are 29 files in the build/tutorial_05_parameter_substitution
directory
compared to the 28 files from Tutorial 04: Simulation with the addition of the
rectangle_compression.inp.in
file.
Workflow Visualization#
View the workflow directed graph by running the following command and opening the image in your preferred image viewer.
$ pwd
/home/roppenheimer/waves-tutorials
$ waves visualize tutorial_05_parameter_substitution --output-file tutorial_05_parameter_substitution.png --width=36 --height=6 --exclude-list /usr/bin .stdout .jnl .prt .com
The output should look similar to the figure below.
