Tutorial 06: Include Files#

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.

  1. 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
    
  2. 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.

  1. You can find the documentation version in the upper-left corner of the webpage.

  2. 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#

  1. 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 5 && mv tutorial_05_parameter_substitution_SConstruct SConstruct
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
  1. Download and copy the tutorial_05_parameter_substitution file to a new file named tutorial_06_include_files with the WAVES Command-Line Utility fetch subcommand.

$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --overwrite tutorials/tutorial_05_parameter_substitution && cp tutorial_05_parameter_substitution tutorial_06_include_files
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
  1. Create a new directory in modsim_package/python in the waves-tutorials directory.

$ pwd
/home/roppenheimer/waves-tutorials
$ mkdir -p modsim_package/python

Python Parameter File#

In this tutorial, we will update the code from Tutorial 05: Parameter Substitution to use an included parameter file instead of hardcoding the parameter definitions in the SConscript file. This technique will allow parameter reuse between simulations.

  1. Create a new file modsim_package/python/rectangle_compression_nominal.py from the content below.

waves-tutorials/modsim_package/python/rectangle_compression_nominal.py

"""Parameter sets and schemas for the rectangle compression simulation"""


def parameter_schema(
    width=1.0,
    height=1.0,
    global_seed=1.0,
    displacement=-0.01,
):
    """Return nominal simulation variables dictionary

    :param float width: The rectangle width
    :param float height: The rectangle height
    :param float global_seed: The global mesh seed size
    :param float displacement: The rectangle top surface displacement

    :returns: nominal simulation variables
    :rtype: dict
    """
    simulation_variables = {
        "width": width,
        "height": height,
        "global_seed": global_seed,
        "displacement": displacement,
    }
    return simulation_variables

The file you just created is similar to the code snippet in your tutorial_05_parameter_substitution file that defines the parameter key-value pairs. Here we have added a function to make documentation of the default values easier, as shown in the WAVES-TUTORIAL API for rectangle_compression_nominal.py.

  1. Create Python module initialization files to create a project specific local Python package.

waves-tutorials/modsim_package/python/__init__.py

$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch tutorials/modsim_package/python/__init__.py --destination modsim_package/python
$ find . -name "__init__.py"
./waves-tutorials/modsim_package/abaqus/__init__.py
./waves-tutorials/modsim_package/python/__init__.py
./waves-tutorials/modsim_package/__init__.py

The __init__.py files tell Python what directories to treat as a package or module. They need to exist, but do not need any content. You can read more about Python Modules in the Python documentation.

SConscript#

  1. Use the diff below to make the following modifications to your tutorial_06_include_files file:

    • Import rectangle_compression_nominal from the modsim_package.python module

    • Remove the simulation_variables dictionary that was created in Tutorial 05: Parameter Substitution’s code

    • Define simulation_variables using the newly imported rectangle_compression_nominal module

A diff against the SConscript file from Tutorial 05: Parameter Substitution is included below to help identify the changes made in this tutorial.

waves-tutorials/tutorial_06_include_files

--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_05_parameter_substitution
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_06_include_files
@@ -11,6 +11,8 @@
 
 import pathlib
 
+from modsim_package.python import rectangle_compression_nominal
+
 # Inherit the parent construction environment
 Import("env")
 
@@ -19,12 +21,7 @@
 # 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,
-}
+simulation_variables = rectangle_compression_nominal.parameter_schema()
 
 # Comment used in tutorial code snippets: marker-1
 

The first change to be made is importing the rectangle_compression_nominal module from the modsim_package.python module you created in the Python Parameter File section of this tutorial. This import statement will import all variables within the rectangle_compression_nominal.py file and make them available in the SConscript file’s name space. See the Python Modules documentation for more information about importing modules. You can access those variables with the following syntax:

rectangle_compression_nominal.simulation_variables

The second change removes the code that defines simulation_variables that remained from Tutorial 05: Parameter Substitution’s code.

The final change made in the tutorial_06_include_files file is to re-define the simulation_variables from the rectangle_compression_nominal module. The end result at this point in the code is the same between this tutorial and Tutorial 05: Parameter Substitution. However, now we import variables from a separate file, list that file as a source dependency of the parameterized targets, and allow ourselves the ability to change parameters without modification to the SConscript file.

SConstruct#

  1. Use the diff below to modify your waves-tutorials/SConstruct file in the following ways:

    • Add the waves-tutorials directory to your PYTHONPATH to make the modsim_package - and thus the modules within it - importable

    • Add tutorial_06_include_files to the workflow_configurations list

A diff against the SConstruct file from Tutorial 05: Parameter Substitution is included below to help identify the changes made in this tutorial.

waves-tutorials/SConstruct

--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_05_parameter_substitution_SConstruct
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_06_include_files_SConstruct
@@ -1,6 +1,7 @@
 #! /usr/bin/env python
 
 import os
+import sys
 import pathlib
 
 import waves
@@ -84,7 +85,8 @@
 for key, value in project_variables.items():
     env[key] = value
 
-# Make the project package importable for Python and Abaqus Python environments
+# Make the project package importable for: (1) SConscript files and (2) Python and Abaqus Python environments
+sys.path.insert(0, str(project_dir))
 env.PrependENVPath("PYTHONPATH", project_dir)
 
 # Comments used in tutorial code snippets: marker-5
@@ -101,6 +103,7 @@
     "tutorial_03_solverprep",
     "tutorial_04_simulation",
     "tutorial_05_parameter_substitution",
+    "tutorial_06_include_files",
 ]
 for workflow in workflow_configurations:
     build_dir = env["variant_dir_base"] / workflow

The first change you made allows for us to import modules from the modsim_package package. This step is neccessary to be able to import the modsim_package.python module in the tutorial_06_include_files file.

The last change to be made is adding tutorial_06_include_files to the workflow_configurations list. This process should be quite familiar by now.

Build Targets#

  1. Build the new targets

$ pwd
/home/roppenheimer/waves-tutorials
$ scons tutorial_06_include_files
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_06_include_files && /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_06_include_files && /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_06_include_files && /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_06_include_files/rectangle_compression.inp.in", "modsim_package/abaqus/rectangle_compression.inp.in")
Creating 'build/tutorial_06_include_files/rectangle_compression.inp'
Copy("build/tutorial_06_include_files/assembly.inp", "modsim_package/abaqus/assembly.inp")
Copy("build/tutorial_06_include_files/boundary.inp", "modsim_package/abaqus/boundary.inp")
Copy("build/tutorial_06_include_files/field_output.inp", "modsim_package/abaqus/field_output.inp")
Copy("build/tutorial_06_include_files/materials.inp", "modsim_package/abaqus/materials.inp")
Copy("build/tutorial_06_include_files/parts.inp", "modsim_package/abaqus/parts.inp")
Copy("build/tutorial_06_include_files/history_output.inp", "modsim_package/abaqus/history_output.inp")
cd /home/roppenheimer/waves-tutorials/build/tutorial_06_include_files && /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 to reduce clutter in the tree command output.

$ pwd
/home/roppenheimer/waves-tutorials
$ tree build/tutorial_06_include_files/
build/tutorial_06_include_files/
|-- 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 exactly the same as those from Tutorial 05: Parameter Substitution. As was mentioned when modifying the SConscript file, the use of an included Python file to define our parameters provides the same result as when we hard-code the parameters into the SConscript file. It is also worth noting that the modsim_package/python/rectangle_compression_nominal.py file did not get copied to the build directory. Instead, we added the modsim_package directory to PYTHONPATH. This way we can import the rectangle_compression_nominal module from its source location and remove any need to duplicate source code by copying files from place to place.

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_06_include_files --output-file tutorial_06_include_files.png --width=28 --height=6 --exclude-list /usr/bin .stdout .jnl .prt .com

The output should look similar to the figure below.

_images/tutorial_06_include_files.png

Note that the directed graph has not grown larger than the one shown in Tutorial 05: Parameter Substitution. While we have added a new parameter file, the dependence is implicitly captured in the simulation variable values passed to the subsitution dictionary. If the values in the parameter file change, the substituted rectangle_compression.inp file contents will also change. So while the parameter file is not explicitly included in the directed graph, the contents of the rectangle_compression.inp file will still correctly prompt re-builds when the parameter file changes.