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.
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.
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 12 && mv tutorial_12_archival_SConstruct SConstruct
WAVES fetch
Destination directory: '/home/roppenheimer/waves-tutorials'
Download and copy the
tutorial_12_archival
file to a new file namedtutorial_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#
In the
waves-tutorials/modsim_package/abaqus
directory, create a file calledexport_abaqus_image.py
using the contents below which contains themain()
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.
In the
waves-tutorials/modsim_package/abaqus
directory, continue editing the fileexport_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#
Add the
images
task list and alias to thetutorial_part_image
SConscript file. A``diff`` against thetutorial_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#
Add the
tutorial_part_image
SConscript file to the workflow. Adiff
against theSConstruct
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#
Build the new targets
$ pwd
/home/roppenheimer/waves-tutorials
$ scons tutorial_part_image_images --jobs=4
Output Files#
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