Skip to main content
`Ctrl`+`K`

# Tutorial: Part Image

This is an example implementation where an Abaqus Python script is used to export an assembly view image of an Abaqus model from an input or CAE file.

## References

Below is a list of references for more information about topics that are not explicitly covered in this tutorial.

- Abaqus Scripting [42]

- Abaqus Python Environment [42]

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

   Linux/MacOS

       $ 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

   Windows

       PS > conda create --name waves-tutorial-env --channel conda-forge waves scons matplotlib pandas pyyaml xarray seaborn numpy salib pytest

2. Activate the environment

   Linux/MacOS

       $ conda activate waves-tutorial-env

   Windows

       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

3. Create and change to a new project root directory to house the tutorial files if you have not already done so. For example

Linux/MacOS

    $ mkdir -p ~/waves-tutorials
    $ cd ~/waves-tutorials
    $ pwd
    /home/roppenheimer/waves-tutorials

Windows

    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 12 && mv tutorial_12_archival_SConstruct SConstruct
    WAVES fetch
    Destination directory: '/home/roppenheimer/waves-tutorials'

4. Download and copy the `tutorial_12_archival` file to a new file named `tutorial_part_image` with the WAVES Command-Line Utility fetch subcommand.

    $ pwd
    /home/roppenheimer/waves-tutorials
    $ waves fetch --overwrite tutorials/tutorial_12_archival && cp tutorial_12_archival tutorial_part_image
    WAVES fetch
    Destination directory: '/home/roppenheimer/waves-tutorials'

## Part-Image script

5. In the `waves-tutorials/modsim_package/abaqus` directory, create a file called `export_abaqus_image.py` using the contents below which contains the `main()` function.

waves-tutorials/modsim_package/abaqus/export_abaqus_image.py

     1import os
     2import sys
     3import shutil
     4import inspect
     5import argparse
     6import tempfile
     7
     8import abaqus
     9import abaqusConstants
    10
    11import modsim_package.abaqus.abaqus_utilities as abaqus_utilities
    12
    13
    14default_x_angle = 0.0
    15default_y_angle = 0.0
    16default_z_angle = 0.0
    17default_image_size = (1920, 1080)
    18default_model_name = "Model-1"
    19default_part_name = "Part-1"
    20cli_description = "Save an assembly view image of an Abaqus model from an input or CAE file"
    21
    22# One time dump from abaqus.session.viewports['Viewport: 1'].colorMappings.keys()) to stay Python 3 compatible for
    23# Sphinx documentation
    24# fmt: off
    25color_map_choices = [
    26    'Material', 'Section', 'Composite layup', 'Composite ply', 'Part', 'Part instance', 'Element set',
    27    'Averaging region', 'Element type', 'Default', 'Assembly', 'Part geometry', 'Load', 'Boundary condition',
    28    'Interaction', 'Constraint', 'Property', 'Meshability', 'Instance type', 'Set', 'Surface', 'Internal set',
    29    'Internal surface', 'Display group', 'Selection group', 'Skin', 'Stringer', 'Cell', 'Face'
    30]
    31# fmt: on
    32
    33
    34def main(
    35    input_file,
    36    output_file,
    37    x_angle=default_x_angle,
    38    y_angle=default_y_angle,
    39    z_angle=default_z_angle,
    40    image_size=default_image_size,
    41    model_name=default_model_name,
    42    part_name=default_part_name,
    43    color_map=color_map_choices[0],
    44):
    45    """Save an assembly view image of an Abaqus model from an input or CAE file.
    46
    47    Open an Abaqus CAE ``*.cae`` or input ``*.inp`` file and save an assembly view image.
    48    Abaqus CAE files are copied to a temporary file before opening to avoid file modification, which is necessary for
    49    compatibility with build systems such as SCons.
    50
    51    :param str input_file: Abaqus input file. Supports ``*.inp`` and ``*.cae``.
    52    :param str output_file: Output image file. Supports ``*.png`` and ``*.svg``.
    53    :param float x_angle: Rotation about X-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    54        method
    55    :param float y_angle: Rotation about Y-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    56        method
    57    :param float z_angle: Rotation about Z-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    58        method
    59    :param tuple image_size: Tuple containing height and width of the output image in pixels
    60    :param str model_name: model to query in the Abaqus model database
    61    :param str part_name: part to query in the specified Abaqus model
    62    :param str color_map: color map key
    63
    64    :returns: writes image to ``{output_file}``
    65    """
    66    input_file_extension = os.path.splitext(input_file)[1]
    67    if input_file_extension.lower() == ".cae":
    68        with AbaqusNamedTemporaryFile(input_file=input_file, suffix=".cae", dir="."):
    69            image(
    70                output_file,
    71                x_angle=x_angle,
    72                y_angle=y_angle,
    73                z_angle=z_angle,
    74                image_size=image_size,
    75                model_name=model_name,
    76                part_name=part_name,
    77                color_map=color_map,
    78            )
    79    elif input_file_extension.lower() == ".inp":
    80        abaqus.mdb.ModelFromInputFile(name=model_name, inputFileName=input_file)
    81        image(
    82            output_file,
    83            x_angle=x_angle,
    84            y_angle=y_angle,
    85            z_angle=z_angle,
    86            image_size=image_size,
    87            model_name=model_name,
    88            part_name=part_name,
    89            color_map=color_map,
    90        )
    91    else:
    92        sys.exit("Unknown file extension {}".format(input_file_extension))

The `export_abaqus_image.py` file is an Abaqus journal file. The top of the file imports standard library modules, Abaqus modules, and the `abaqus_utilities.py` module create in Tutorial 02: Partition and Mesh. The `main()` function takes two required arguments: `input_file` which is an Abaqus CAE `*.cae` or Abaqus input `*.inp` file and `output_file` which is the file path of the assembly view image that this function will create.

6. In the `waves-tutorials/modsim_package/abaqus` directory, continue editing the file `export_abaqus_image.py` using the contents below which contains the rest of the script.

waves-tutorials/modsim_package/abaqus/export_abaqus_image.py

     96def image(
     97    output_file,
     98    x_angle=default_x_angle,
     99    y_angle=default_y_angle,
    100    z_angle=default_z_angle,
    101    image_size=default_image_size,
    102    model_name=default_model_name,
    103    part_name=default_part_name,
    104    color_map=color_map_choices[0],
    105):
    106    """Save an assembly view image of an Abaqus model from an input or CAE file.
    107
    108    The viewer window is adjusted by the provided x, y, and z angles and the viewport is set to fit the assembly prior
    109    to saving an image of the viewport screen.
    110
    111    If the model assembly has no instances, use ``part_name`` to generate one. The ``input_file`` is not modified to
    112    include this generated instance.
    113
    114    :param str output_file: Output image file. Supports ``*.png`` and ``*.svg``.
    115    :param float x_angle: Rotation about X-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    116        method
    117    :param float y_angle: Rotation about Y-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    118        method
    119    :param float z_angle: Rotation about Z-axis in degrees for ``abaqus.session.viewports[].view.rotate`` Abaqus Python
    120        method
    121    :param tuple image_size: Tuple containing height and width of the output image in pixels
    122    :param str model_name: model to query in the Abaqus model database
    123    :param str part_name: part to query in the specified Abaqus model
    124    :param str color_map: color map key
    125
    126    :returns: writes image to ``{output_file}``
    127    """
    128    output_file_stem, output_file_extension = os.path.splitext(output_file)
    129    output_file_extension = output_file_extension.lstrip(".")
    130    assembly = abaqus.mdb.models[model_name].rootAssembly
    131    if len(assembly.instances.keys()) == 0:
    132        part = abaqus.mdb.models[model_name].parts[part_name]
    133        assembly.Instance(name=part_name, part=part, dependent=abaqusConstants.ON)
    134    viewport = abaqus.session.viewports["Viewport: 1"]
    135    viewport.assemblyDisplay.setValues(
    136        optimizationTasks=abaqusConstants.OFF,
    137        geometricRestrictions=abaqusConstants.OFF,
    138        stopConditions=abaqusConstants.OFF,
    139    )
    140    viewport.setValues(displayedObject=assembly)
    141    viewport.view.rotate(xAngle=x_angle, yAngle=y_angle, zAngle=z_angle, mode=abaqusConstants.MODEL)
    142    viewport.view.fitView()
    143    viewport.enableMultipleColors()
    144    viewport.setColor(initialColor="#BDBDBD")
    145    cmap = viewport.colorMappings[color_map]
    146    viewport.setColor(colorMapping=cmap)
    147    viewport.disableMultipleColors()
    148    abaqus.session.printOptions.setValues(vpDecorations=abaqusConstants.OFF)
    149    abaqus.session.pngOptions.setValues(imageSize=image_size)
    150
    151    output_format = abaqus_utilities.return_abaqus_constant(output_file_extension)
    152    abaqus.session.printToFile(fileName=output_file_stem, format=output_format, canvasObjects=(viewport,))
    153
    154
    155class AbaqusNamedTemporaryFile:
    156    """Open an Abaqus CAE ``input_file`` as a temporary file. Close and delete on exit of context manager.
    157
    158    Provides Windows compatible temporary file handling. Required until Python 3.12 ``delete_on_close=False`` option is
    159    available in Abaqus Python.
    160
    161    :param str input_file: The input file to copy before open
    162    """
    163
    164    def __init__(self, input_file, *args, **kwargs):
    165        self.temporary_file = tempfile.NamedTemporaryFile(*args, delete=False, **kwargs)
    166        shutil.copyfile(input_file, self.temporary_file.name)
    167        abaqus.openMdb(pathName=self.temporary_file.name)
    168
    169    def __enter__(self):
    170        return self.temporary_file
    171
    172    def __exit__(self, exc_type, exc_val, exc_tb):
    173        abaqus.mdb.close()
    174        self.temporary_file.close()
    175        os.remove(self.temporary_file.name)
    176
    177
    178def get_parser():
    179    """Return parser for CLI options
    180
    181    All options should use the double-hyphen ``--option VALUE`` syntax to avoid clashes with the Abaqus option syntax,
    182    including flag style arguments ``--flag``. Single hyphen ``-f`` flag syntax often clashes with the Abaqus command
    183    line options and should be avoided.
    184
    185    :returns: parser
    186    :rtype: argparse.ArgumentParser
    187    """
    188    file_name = inspect.getfile(lambda: None)
    189    base_name = os.path.basename(file_name)
    190    prog = "abaqus cae -noGui {} --".format(base_name)
    191    parser = argparse.ArgumentParser(description=cli_description, prog=prog)
    192    parser.add_argument(
    193        "--input-file",
    194        type=str,
    195        required=True,
    196        help="Abaqus input file. Supports ``*.inp`` and ``*.cae``.",
    197    )
    198    parser.add_argument(
    199        "--output-file",
    200        type=str,
    201        required=True,
    202        help="Output image from the Abaqus viewport. Supports ``*.png``, ``*.svg`` and ``*.eps``.",
    203    )
    204    parser.add_argument(
    205        "--x-angle",
    206        type=float,
    207        default=default_x_angle,
    208        help="Viewer rotation about X-axis in degrees (default: %(default)s)",
    209    )
    210    parser.add_argument(
    211        "--y-angle",
    212        type=float,
    213        default=default_y_angle,
    214        help="Viewer rotation about Y-axis in degrees (default: %(default)s)",
    215    )
    216    parser.add_argument(
    217        "--z-angle",
    218        type=float,
    219        default=default_z_angle,
    220        help="Viewer rotation about Z-axis in degrees (default: %(default)s)",
    221    )
    222    parser.add_argument(
    223        "--image-size",
    224        nargs=2,
    225        type=int,
    226        default=default_image_size,
    227        help="Image size in pixels (X, Y) (default: %(default)s)",
    228    )
    229    parser.add_argument(
    230        "--model-name",
    231        type=str,
    232        default=default_model_name,
    233        help="Abaqus model name (default: %(default)s)",
    234    )
    235    parser.add_argument(
    236        "--part-name",
    237        type=str,
    238        default=default_part_name,
    239        help="Abaqus part name (default: %(default)s)",
    240    )
    241    parser.add_argument(
    242        "--color-map",
    243        type=str,
    244        choices=color_map_choices,
    245        default=color_map_choices[0],
    246        help="Color map (default: %(default)s)",
    247    )
    248    return parser
    249
    250
    251if __name__ == "__main__":
    252    parser = get_parser()
    253    try:
    254        args, unknown = parser.parse_known_args()
    255    except SystemExit as err:
    256        sys.exit(err.code)
    257    possible_typos = [argument for argument in unknown if argument.startswith("--")]
    258    if len(possible_typos) > 0:
    259        raise RuntimeError("Found possible typos in CLI option(s) {}".format(possible_typos))
    260
    261    sys.exit(
    262        main(
    263            args.input_file,
    264            args.output_file,
    265            x_angle=args.x_angle,
    266            y_angle=args.y_angle,
    267            z_angle=args.z_angle,
    268            image_size=args.image_size,
    269            model_name=args.model_name,
    270            part_name=args.part_name,
    271            color_map=args.color_map,
    272        )
    273    )

The `image()` function utilizes the rest of the optional arguments that were passed from the `main()` function. The arguments `color_map`, `x_angle`, `y_angle`, and `z_angle` are used to adjust the viewer window. The `model_name` and `part_name` are used to set the Abaqus part assembly. The `image_size` parameter can change the size of your output image. All of these arguments are optional and have default values to rely on if no value was specified.

## SConscript

7. Add the `images` task list and alias to the `tutorial_part_image` SConscript file. A``diff`` against the `tutorial_12_archival` file from Tutorial 12: Data Archival is included below to help identify the changes made in this tutorial.

waves-tutorials/tutorial_part_image

    --- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_12_archival
    +++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_part_image
    @@ -33,6 +33,7 @@
     # Collect the target nodes to build a concise alias for all targets
     workflow = []
     datacheck = []
    +images = []

     # Comment used in tutorial code snippets: marker-2

    @@ -163,6 +164,19 @@
             )
         )

    +    # Part images
    +    script_options = (
    +        "--input-file ${SOURCES[1].abspath} --output-file ${TARGET.file} --model-name ${model} --part-name ${model}"
    +    )
    +    images.extend(
    +        env.AbaqusJournal(
    +            target=[set_name / "rectangle_compression.png"],
    +            source=[str("#/modsim_package/abaqus/export_abaqus_image.py")] + solve_source_list,
    +            subcommand_options=script_options,
    +            model="rectangle",
    +        )
    +    )
    +
     # Comment used in tutorial code snippets: marker-6

     # Post-processing
    @@ -207,6 +221,7 @@
     env.Alias(env["datacheck_alias"], datacheck)
     env.Alias(env["regression_alias"], datacheck)
     env.Alias(f"{workflow_name}_archive", archive_target)
    +env.Alias(f"{workflow_name}_images", images)

     if not env["unconditional_build"] and not env["ABAQUS_PROGRAM"]:
         print(f"Program 'abaqus' was not found in construction environment. Ignoring '{workflow_name}' target(s)")

Generating images will be part of a separate workflow. To do this we have created an `images` list that will capture the SCons tasks and have mapped a new alias to that list.

## SConstruct

8. Add the `tutorial_part_image` SConscript file to the workflow. A `diff` against the `SConstruct` file from Tutorial 12: Data Archival is included below to help identify the changes made in this tutorial.

waves-tutorials/SConstruct

    --- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_12_archival_SConstruct
    +++ /home/runner/work/waves/waves/build/docs/tutorials_tutorial_part_image_SConstruct
    @@ -121,6 +121,7 @@
         "tutorial_09_post_processing",
         "tutorial_11_regression_testing",
         "tutorial_12_archival",
    +    "tutorial_part_image",
     ]
     for workflow in workflow_configurations:
         build_dir = env["variant_dir_base"] / workflow

## Build Targets

9. Build the new targets

    $ pwd
    /home/roppenheimer/waves-tutorials
    $ scons tutorial_part_image_images --jobs=4

## Output Files

10. View the output files. Notice that the output files from Tutorial 11: Regression Testing have been created with the addition of the `.png` output files.

    $ pwd
    /home/roppenheimer/waves-tutorials
    $ tree build/tutorial_part_image/parameter_set0/
    build/tutorial_part_image/parameter_set0/
    ├── abaqus1.rec
    ├── abaqus.rpy
    ├── abaqus.rpy.1
    ├── abaqus.rpy.2
    ├── abaqus.rpy.3
    ├── abaqus.rpy.4
    ├── assembly.inp
    ├── boundary.inp
    ├── field_output.inp
    ├── history_output.inp
    ├── materials.inp
    ├── parts.inp
    ├── rectangle_compression.inp
    ├── rectangle_compression.inp.in
    ├── rectangle_compression.png
    ├── rectangle_compression.png.stdout
    ├── rectangle_geometry.cae
    ├── rectangle_geometry.cae.stdout
    ├── rectangle_geometry.jnl
    ├── rectangle_mesh.cae
    ├── rectangle_mesh.inp
    ├── rectangle_mesh.inp.stdout
    ├── rectangle_mesh.jnl
    ├── rectangle_partition.cae
    ├── rectangle_partition.cae.stdout
    └── rectangle_partition.jnl

    0 directories, 26 files