Skip to main content
`Ctrl`+`K`

# SCons Multi-Action Tasks

Note

Unlike the Quickstart: Abaqus, this tutorial will use native SCons code without the WAVES extensions and builders. This tutorial is included as an example for using native SCons techniques when WAVES does not support required third-party software, such as numeric solvers, or for when a modsim project requires unique builder behavior. You can learn more about writing your own SCons Builders in the SCons user manual [32] and Tutorial: Writing Builders.

This quickstart will create a pure SCons, minimal, two file project configuration matching the tutorials listed below.

- Tutorial 00: SConstruct

- Tutorial 01: Geometry

- Tutorial 02: Partition and Mesh

- Tutorial 03: SolverPrep

- Tutorial 04: Simulation

The tutorials above and this quickstart describe the computational engineering workflow through simulation execution. This quickstart uses a separate, standalone subdirectory to avoid file name clashes with the full tutorial files. The quickstart also uses a flat directory structure to simplify the project configuration. Larger projects, like the ModSim Templates, may require a hierarchical directory structure to separate files with identical basenames.

Most build systems use intermediate target files to identify which tasks need to be performed again on subsequent execution. The SCons Quickstart uses this behavior to allow conditional re-building of partial workflows. For example, if the `rectangle_mesh.py` journal file changes, the geometry and partitioning tasks do not need to be re-executed because the `rectangle_geometry.cae` and `rectangle_paritition.cae` targets do not depend on the source `rectangle_mesh.py`.

This conditional re-build granularity comes at the cost of roughly tripling the disk space required to store the Abaqus CAE files. Sometimes disk space is limited, such as for large models where even a single copy of the file may consume large amounts of disk space or when a smaller model is built in a large parameteric study. In these cases it is necessary to operate on a common file from multiple actions. SCons provides a solution to this by allowing a task definition to include a list of actions. The state machine stored by Scons will not store the target state until all actions have been performed, which avoids re-build state ambiguity when performing more than one action on a single file. While this does save storage resources, it will increase computational cost of the re-build because every source file in the task definition requires the entire task to be re-executed.

## References

- SCons Command [32]

## Environment

SCons 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

While the files in this tutorial don’t use WAVES, the package will still be used to fetch necessary tutorial directories and files. If you don’t have access to WAVES, the relevant WAVES tutorials abaqus source files may be found in the GitHub repository

1. Create the environment if it doesn’t exist

       $ conda create --name waves-tutorial-env --channel conda-forge 'scons>=4.6' waves

2. Activate the environment

       $ conda activate waves-tutorial-env

## Directory Structure

3. Create the project directory structure and copy the Multi-Action Task source files into the `~/waves-tutorials/multi_action_task` sub-directory with the WAVES Command-Line Utility fetch subcommand.

    $ waves fetch tutorials/multi_action_task --destination ~/waves-tutorials/multi_action_task
    WAVES fetch
    Destination directory: '/home/roppenheimer/waves-tutorials/multi_action_task'
    $ cd ~/waves-tutorials/multi_action_task
    $ pwd
    /home/roppenheimer/waves-tutorials/multi_action_task

## SConscript File

The SConscript file below contains the workflow task definitions, where a task is a list of sources, an action to operate on those sources, and the targets that the action produces. The Build System discussion includes a more detailed review of build systems.

multi_action_task/SConscript

     1Import("env")
     2
     3# Write project builders for re-use in task definitions
     4abaqus_journal = Builder(
     5    action=[
     6        (
     7            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCE.abspath} ${abaqus_options} "
     8            "-- ${journal_options}"
     9        )
    10    ]
    11)
    12
    13abaqus_solver = Builder(
    14    action=[
    15        (
    16            "cd ${TARGET.dir.abspath} && ${abaqus_program} -job ${job} -input ${SOURCE.filebase} "
    17            "${abaqus_options} -interactive -ask_delete no"
    18        )
    19    ]
    20)
    21
    22# Add builders and pseudo-builders
    23env.Append(
    24    BUILDERS={
    25        "AbaqusJournal": abaqus_journal,
    26        "AbaqusSolver": abaqus_solver,
    27    }
    28)
    29
    30# Geometry, Partition, Mesh
    31env.Command(
    32    target=["rectangle_mesh.cae", "rectangle_mesh.inp"],
    33    source=["rectangle_geometry.py", "rectangle_partition.py", "rectangle_mesh.py", "abaqus_utilities.py"],
    34    action=[
    35        (
    36            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[0].abspath} "
    37            "${abaqus_options} -- --output-file ${TARGET.abspath}"
    38        ),
    39        (
    40            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[1].abspath} "
    41            "${abaqus_options} -- --input-file ${TARGET.abspath} --output-file ${TARGET.abspath}"
    42        ),
    43        (
    44            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[2].abspath} "
    45            "${abaqus_options} -- --input-file ${TARGET.abspath} --output-file ${TARGET.abspath}"
    46        ),
    47    ],
    48    abaqus_program=env["ABAQUS_PROGRAM"],
    49)
    50
    51# Abaqus Solve
    52solve_sources = [
    53    "rectangle_compression.inp",
    54    "rectangle_mesh.inp",
    55]
    56
    57solve_targets = [
    58    "rectangle_compression.odb",
    59    "rectangle_compression.dat",
    60    "rectangle_compression.msg",
    61    "rectangle_compression.com",
    62    "rectangle_compression.prt",
    63    "rectangle_compression.sta",
    64]
    65
    66target = env.AbaqusSolver(
    67    target=solve_targets,
    68    source=solve_sources,
    69    abaqus_program=env["ABAQUS_PROGRAM"],
    70    job="rectangle_compression",
    71    program_options="-double both",
    72)
    73
    74# Collector alias named after the model simulation
    75env.Alias("rectangle", target)
    76
    77if not env["unconditional_build"] and not env["ABAQUS_PROGRAM"]:
    78    print(f"Program 'abaqus' was not found in construction environment. Ignoring 'rectangle' target(s)")
    79    Ignore([".", "rectangle"], target)

A `diff` against the SConstruct file from SCons Quickstart is included below to help identify the changes made in this tutorial. Note that the `AbaqusJournal` builder is no longer used. While it would be possible to adapt the builder to the multi-action journal file execution, in general the files executed by each action may not have a sufficiently similar command-line interface (CLI) or naming convention to generalize a multi-task builder. Instead, the more flexible, general purpose SCons Command builder is used.

waves-tutorials/SConstruct

    --- /home/runner/work/waves/waves/build/docs/scons_quickstart_SConscript
    +++ /home/runner/work/waves/waves/build/docs/multi_action_task_SConscript
    @@ -4,7 +4,7 @@
     abaqus_journal = Builder(
         action=[
             (
    -            "cd ${TARGET.dir.abspath} && ${ABAQUS_PROGRAM} cae -noGui ${SOURCE.abspath} ${abaqus_options} "
    +            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCE.abspath} ${abaqus_options} "
                 "-- ${journal_options}"
             )
         ]
    @@ -13,7 +13,7 @@
     abaqus_solver = Builder(
         action=[
             (
    -            "cd ${TARGET.dir.abspath} && ${ABAQUS_PROGRAM} -job ${job} -input ${SOURCE.filebase} "
    +            "cd ${TARGET.dir.abspath} && ${abaqus_program} -job ${job} -input ${SOURCE.filebase} "
                 "${abaqus_options} -interactive -ask_delete no"
             )
         ]
    @@ -27,22 +27,25 @@
         }
     )

    -# Geometry
    -env.AbaqusJournal(
    -    target=["rectangle_geometry.cae"],
    -    source=["rectangle_geometry.py"],
    -)
    -
    -# Partition
    -env.AbaqusJournal(
    -    target=["rectangle_partition.cae"],
    -    source=["rectangle_partition.py", "rectangle_geometry.cae"],
    -)
    -
    -# Mesh
    -env.AbaqusJournal(
    -    target=["rectangle_mesh.inp", "rectangle_mesh.cae"],
    -    source=["rectangle_mesh.py", "rectangle_partition.cae", "abaqus_utilities.py"],
    +# Geometry, Partition, Mesh
    +env.Command(
    +    target=["rectangle_mesh.cae", "rectangle_mesh.inp"],
    +    source=["rectangle_geometry.py", "rectangle_partition.py", "rectangle_mesh.py", "abaqus_utilities.py"],
    +    action=[
    +        (
    +            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[0].abspath} "
    +            "${abaqus_options} -- --output-file ${TARGET.abspath}"
    +        ),
    +        (
    +            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[1].abspath} "
    +            "${abaqus_options} -- --input-file ${TARGET.abspath} --output-file ${TARGET.abspath}"
    +        ),
    +        (
    +            "cd ${TARGET.dir.abspath} && ${abaqus_program} cae -noGui ${SOURCES[2].abspath} "
    +            "${abaqus_options} -- --input-file ${TARGET.abspath} --output-file ${TARGET.abspath}"
    +        ),
    +    ],
    +    abaqus_program=env["ABAQUS_PROGRAM"],
     )

     # Abaqus Solve
    @@ -63,6 +66,7 @@
     target = env.AbaqusSolver(
         target=solve_targets,
         source=solve_sources,
    +    abaqus_program=env["ABAQUS_PROGRAM"],
         job="rectangle_compression",
         program_options="-double both",
     )

## Building targets

    $ pwd
    /home/roppenheimer/waves-tutorials/multi_action_task
    $ scons rectangle

## Output Files

There are fewer files than in SCons Quickstart because the intermediate targets, `rectangle_geometry.{cae,jnl}` and `rectangle_partition.{cae,jnl}` are no longer created. In the case of the `*.jnl` files, this is because Abaqus write the journal file name to match the model name, which is now `rectangle_mesh` in all journal files.

    $ pwd
    /home/roppenheimer/waves-tutorials/multi_action_task
    $ tree build/
    build/
    ├── abaqus_utilities.py
    ├── 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.msg
    ├── rectangle_compression.odb
    ├── rectangle_compression.prt
    ├── rectangle_compression.sta
    ├── rectangle_geometry.py
    ├── rectangle_mesh.cae
    ├── rectangle_mesh.inp
    ├── rectangle_mesh.jnl
    ├── rectangle_mesh.py
    ├── rectangle_partition.py
    └── SConscript

    0 directories, 24 files

## Workflow Visualization

    $ pwd
    /home/roppenheimer/waves-tutorials/multi_action_task
    $ waves visualize rectangle --output-file multi_action_task.png --width=28 --height=6