Tutorial: Input Verification#

The Abaqus journal files from Tutorial 01: Geometry and Tutorial 02: Partition and Mesh already perform some input verification by specifying the expected variable types. This input verification can be extended by user specified type methods. This is useful when a journal file should limit the range of allowable float values, for instance. In the case of these tutorials, one might wish to limit the width, height, and global seed parameters to positive float values. The solution approach is sufficiently general to allow modsim owners to similarly implement ranges of floats or integers, specific value choices, or any other restriction which may be necessary to ensure that a simulation workflow is used within its designed assumptions.

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.

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

$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --overwrite tutorials/tutorial_02_partition_mesh && cp tutorial_02_partition_mesh tutorial_argparse_types
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
  1. Create a new directory modsim_package/argparse_types.

$ pwd
/path/to/waves-tutorials
$ mkdir -p modsim_package/argparse_types
  1. Copy the Abaqus journal files into the new directory modsim_package/argparse_types

$ pwd
/path/to/waves-tutorials
$ cp modsim_package/abaqus/rectangle_{geometry,partition,mesh}.py modsim_package/argparse_types

Journal Files#

  1. In the modsim_package directory, create a new file called argparse_types.py using the contents below

waves-tutorials/modsim_package/argparse_types.py

 1"""Python 2/3 compatible argparse types for input verification"""
 2
 3import argparse
 4
 5
 6def positive_float(argument):
 7    """Type function for argparse - positive floats
 8
 9    Abaqus Python 2 and Python 3 compatible argparse type method:
10    https://docs.python.org/3.12/library/argparse.html#type.
11
12    :param str argument: string argument from argparse
13
14    :returns: argument
15    :rtype: float
16
17    :raises ValueError:
18
19        * The argument can't be cast to float
20        * The argument is less than 0.0 in a float comparison
21    """
22    MINIMUM_VALUE = 0.0
23    try:
24        argument = float(argument)
25    except ValueError:
26        raise argparse.ArgumentTypeError("invalid float value: '{}'".format(argument))
27    if not argument > MINIMUM_VALUE:
28        raise argparse.ArgumentTypeError("invalid positive float: '{}'".format(argument))
29    return argument

The user-defined Argparse type function must take exactly one positional argument, which should correspond to the string that will be parsed by the argparse interface. The function may perform any arbitrary verification checks and return the type cast argument if all checks pass.

  1. Make the following changes to the journal file imports and argparse option definitions.

waves-tutorials/argparse_types/rectangle_geometry.py

--- /home/runner/work/waves/waves/build/docs/abaqus_rectangle_geometry.py
+++ /home/runner/work/waves/waves/build/docs/argparse_types_rectangle_geometry.py
@@ -5,6 +5,8 @@
 
 import abaqus
 import abaqusConstants
+
+from modsim_package.argparse_types import positive_float
 
 
 def main(output_file, model_name, part_name, width, height):
@@ -93,13 +95,13 @@
     )
     parser.add_argument(
         "--width",
-        type=float,
+        type=positive_float,
         default=default_width,
         help="The rectangle width. Positive float.",
     )
     parser.add_argument(
         "--height",
-        type=float,
+        type=positive_float,
         default=default_height,
         help="The rectangle height. Positive float.",
     )

waves-tutorials/argparse_types/rectangle_partition.py

--- /home/runner/work/waves/waves/build/docs/abaqus_rectangle_partition.py
+++ /home/runner/work/waves/waves/build/docs/argparse_types_rectangle_partition.py
@@ -5,6 +5,8 @@
 import argparse
 
 import abaqus
+
+from modsim_package.argparse_types import positive_float
 
 
 def main(input_file, output_file, model_name, part_name, width, height):
@@ -152,13 +154,13 @@
     )
     parser.add_argument(
         "--width",
-        type=float,
+        type=positive_float,
         default=default_width,
         help="The rectangle width. Positive float.",
     )
     parser.add_argument(
         "--height",
-        type=float,
+        type=positive_float,
         default=default_height,
         help="The rectangle height. Positive float.",
     )

waves-tutorials/argparse_types/rectangle_mesh.py

--- /home/runner/work/waves/waves/build/docs/abaqus_rectangle_mesh.py
+++ /home/runner/work/waves/waves/build/docs/argparse_types_rectangle_mesh.py
@@ -8,15 +8,8 @@
 import abaqusConstants
 import mesh
 
-# Import the shared abaqus utilities, trying both tutorial directory structures.
-# Most end-users will implement only one of these structures and should replace
-# the try/except structure with a single import line, e.g.
-#
-# import modsim_package.abaqus.abaqus_utilities as abaqus_utilities
-try:
-    import modsim_package.abaqus.abaqus_utilities as abaqus_utilities
-except ImportError:
-    import abaqus_utilities
+import modsim_package.abaqus.abaqus_utilities
+from modsim_package.argparse_types import positive_float
 
 
 def main(input_file, output_file, model_name, part_name, global_seed):
@@ -66,7 +59,7 @@
     part.Set(faces=faces, name="NODES")
 
     model_object = abaqus.mdb.models[model_name]
-    abaqus_utilities.export_mesh(model_object, part_name, output_file)
+    modsim_package.abaqus.abaqus_utilities.export_mesh(model_object, part_name, output_file)
 
     abaqus.mdb.save()
 
@@ -133,7 +126,7 @@
     )
     parser.add_argument(
         "--global-seed",
-        type=float,
+        type=positive_float,
         default=default_global_seed,
         help="The global mesh seed size. Positive float.",
     )

Here we import the modsim package files as introduced in Tutorial 02: Partition and Mesh for the meshing journal file, but for all journal files to use the positive_float type check in the argparse interface.

SConscript#

No change is required to the SConscript configuration file. The new journal file location will be changed in the SConstruct file below.

SConstruct#

  1. Add tutorial_argparse_types to the workflow_configurations list in the waves-tutorials/SConstruct file.

A diff against the SConstruct file from Tutorial 02: Partition and Mesh is included below to help identify the changes made in this tutorial.

waves-tutorials/SConstruct

--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_02_partition_mesh_SConstruct
+++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_argparse_types_SConstruct
@@ -98,6 +98,7 @@
 workflow_configurations = [
     "tutorial_01_geometry",
     "tutorial_02_partition_mesh",
+    "tutorial_argparse_types",
 ]
 for workflow in workflow_configurations:
     build_dir = env["variant_dir_base"] / workflow

In addition to the new target workflow tutorial_argparse_types, the changes above point to the new argparse_types path containing the updated journal files.

Build Targets#

  1. Build the new targets

$ pwd
/path/to/waves-tutorials
$ scons tutorial_argparse_types
scons: Reading SConscript files ...
Checking whether abq2024 program exists.../apps/abaqus/Commands/abq2024
Checking whether abq2021 program exists.../apps/abaqus/Commands/abq2021
Checking whether abq2020 program exists.../apps/abaqus/Commands/abq2020
scons: done reading SConscript files.
scons: Building targets ...
cd /home/roppenheimer/waves-tutorials/build/tutorial_argparse_types && /apps/abaqus/Commands/abaqus cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_geometry.py -- > rectangle_geometry.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/build/tutorial_argparse_types && /apps/abaqus/Commands/abaqus cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_partition.py -- > rectangle_partition.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/build/tutorial_argparse_types && /apps/abaqus/Commands/abaqus cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_mesh.py -- > rectangle_mesh.stdout 2>&1
scons: done building targets.

The build process, targets, and output files should be identical to that of Tutorial 02: Partition and Mesh. You can explore changes in behavior by modifying the subcommand_options of both tutorial_02_partition_mesh and tutorial_argparse_types to include negative floats and re-running both workflows. For instance, by adding the following to the Geometry task definition.

subcommand_options="--width '-1.0'"

See Tutorial 05: Parameter Substitution for more details about using the command-line interface and subcommand_options task argument.

Output Files#

The contents of the new workflow should be identical to that of Tutorial 02: Partition and Mesh.

$ pwd
/home/roppenheimer/waves-tutorials
$ tree build/tutorial_02_partition_mesh/ build/tutorial_argparse_types/
build/tutorial_02_partition_mesh/
|-- abaqus.rpy
|-- abaqus.rpy.1
|-- abaqus.rpy.2
|-- 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
build/tutorial_argparse_types/
|-- abaqus.rpy
|-- abaqus.rpy.1
|-- abaqus.rpy.2
|-- 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, 26 files