Tutorial: Cubit+Sierra#
Warning
Most WAVES tutorials are used as system tests in the regression test suite to ensure that the tutorial files are up-to-date and functional. The sierra local submission without sbatch is part of the regression suite, but the sbatch submission behavior is not. If you run into problems running this tutorial, please contact the WAVES development team.
Note
Depending on your Cubit installation and operating system, it may not be
possible to import Cubit into arbitrary Python 3 environments. Instead, it
may be necessary to execute Cubit Python scripts using the Python
interpreter bundled with Cubit. An alternate Cubit tutorial using
waves.scons_extensions.add_cubit_python()
is provided as
tutorial_cubit_alternate
$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --destination tutorial_cubit_alternate tutorials/tutorial_cubit_alternate
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.
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
Create a new
tutorial_cubit
directory with thewaves fetch
command below
$ pwd
/home/roppenheimer/waves-tutorials
$ waves fetch --destination tutorial_cubit tutorials/tutorial_cubit
$ ls tutorial_cubit
modsim_package/ abaqus cubit SConstruct sierra fierro
Make the new
tutorial_cubit
directory the current working directory
$ pwd
/home/roppenheimer/waves-tutorials
$ cd tutorial_cubit
$ pwd
/home/roppenheimer/waves-tutorials/tutorial_cubit
$ ls
modsim_package/ abaqus cubit SConstruct sierra fierro
SConscript#
Note that the tutorial_cubit
directory has four SConscript files: cubit
, abaqus
, sierra
, and fierro
.
The cubit
and sierra
files are relevant to the current tutorial. The abaqus
and fierro
workflows are
described in the complementary Tutorial: Cubit+Abaqus and Tutorial: Cubit+Fierro.
Review the
cubit
andsierra
tutorials and compare them against the Tutorial 04: Simulation files.
The structure has changed enough that a diff view is not as useful. Instead the contents of the new SConscript files are duplicated below.
waves-tutorials/tutorial_cubit/cubit
1#! /usr/bin/env python
2"""Rectangle compression workflow: geometry, partition, mesh
3
4Requires the following ``SConscript(..., exports={})``
5
6* ``env`` - The SCons construction environment with the following required keys
7
8 * ``unconditional_build`` - Boolean flag to force building of conditionally ignored targets
9 * ``cubit`` - String path for the Cubit executable
10
11* ``element_type`` - The Cubit 4 node quadrilateral element type
12* ``solver`` - The target solver to use when writing a mesh file
13"""
14
15import pathlib
16
17import waves
18
19# Inherit the parent construction environment
20Import("env", "element_type", "solver")
21
22# Simulation variables
23build_directory = pathlib.Path(Dir(".").abspath)
24workflow_name = build_directory.name
25
26# Collect the target nodes to build a concise alias for all targets
27workflow = []
28
29# Rectangle 2D
30# Geometry
31workflow.extend(
32 env.PythonScript(
33 target=["rectangle_geometry.cub"],
34 source=["#/modsim_package/cubit/rectangle_geometry.py"],
35 subcommand_options="",
36 )
37)
38
39# Partition
40workflow.extend(
41 env.PythonScript(
42 target=["rectangle_partition.cub"],
43 source=["#/modsim_package/cubit/rectangle_partition.py", "rectangle_geometry.cub"],
44 subcommand_options="",
45 )
46)
47
48# Mesh
49if solver.lower() == "abaqus":
50 mesh_extension = "inp"
51elif solver.lower() in ["sierra", "adagio"]:
52 mesh_extension = "g"
53else:
54 raise RuntimeError(f"Unknown solver '{solver}'")
55workflow.extend(
56 env.PythonScript(
57 target=[f"rectangle_mesh.{mesh_extension}", "rectangle_mesh.cub"],
58 source=["#/modsim_package/cubit/rectangle_mesh.py", "rectangle_partition.cub"],
59 subcommand_options="--element-type ${element_type} --solver ${solver}",
60 element_type=element_type,
61 solver=solver,
62 )
63)
64
65
66# Cube 3D
67# Geometry
68workflow.extend(
69 env.PythonScript(
70 target=["cube_geometry.cub"],
71 source=["#/modsim_package/cubit/cube_geometry.py"],
72 subcommand_options="",
73 )
74)
75
76# Partition
77workflow.extend(
78 env.PythonScript(
79 target=["cube_partition.cub"],
80 source=["#/modsim_package/cubit/cube_partition.py", "cube_geometry.cub"],
81 subcommand_options="",
82 )
83)
84
85# Mesh
86if solver.lower() == "abaqus":
87 mesh_extension = "inp"
88elif solver.lower() in ["sierra", "adagio"]:
89 mesh_extension = "g"
90else:
91 raise RuntimeError(f"Unknown solver '{solver}'")
92workflow.extend(
93 env.PythonScript(
94 target=[f"cube_mesh.{mesh_extension}", "cube_mesh.cub"],
95 source=["#/modsim_package/cubit/cube_mesh.py", "cube_partition.cub"],
96 subcommand_options="--element-type ${element_type} --solver ${solver}",
97 element_type=element_type,
98 solver=solver,
99 )
100)
101
102# Collector alias based on parent directory name
103env.Alias(f"{workflow_name}_cubit", workflow)
104
105if not env["unconditional_build"] and not env["CUBIT_PROGRAM"]:
106 print(f"Program 'cubit' was not found in construction environment. Ignoring '{workflow_name}' target(s)")
107 Ignore([".", workflow_name], workflow)
waves-tutorials/tutorial_cubit/sierra
1#! /usr/bin/env python
2"""Rectangle compression workflow: Sierra solve
3
4Requires the following ``SConscript(..., exports={})``
5
6* ``env`` - The SCons construction environment with the following required keys
7
8 * ``unconditional_build`` - Boolean flag to force building of conditionally ignored targets
9 * ``cubit`` - String path for the Cubit executable
10
11* ``envSierra`` - The Sierra SCons construction environment with the following required keys
12
13 * ``sierra`` - String path for the Sierra executable
14"""
15
16import pathlib
17
18# Inherit the parent construction environment
19Import("env", "envSierra")
20
21# Simulation variables
22build_directory = pathlib.Path(Dir(".").abspath)
23workflow_name = build_directory.name
24
25# Collect the target nodes to build a concise alias for all targets
26workflow = []
27
28element_type = "SHELL"
29solver = "sierra"
30SConscript(
31 "cubit",
32 exports={"env": env, "element_type": element_type, "solver": solver},
33 duplicate=False,
34)
35
36# SolverPrep
37sierra_source_list = ["#/modsim_package/sierra/rectangle_compression.i"]
38sierra_source_list = [pathlib.Path(source_file) for source_file in sierra_source_list]
39workflow.extend(env.CopySubstfile(sierra_source_list))
40
41# Sierra Solve
42solve_source_list = [source_file.name for source_file in sierra_source_list]
43solve_source_list.append("rectangle_mesh.g")
44workflow.extend(
45 envSierra.Sierra(
46 target=["rectangle_compression.e"],
47 source=solve_source_list,
48 )
49)
50
51# Collector alias based on parent directory name
52env.Alias(workflow_name, workflow)
53
54# Developer note: CI system configuration for Sierra is inconsistent. Do not force with ``unconditional build`` option.
55if not envSierra["sierra"]:
56 print(f"Program 'sierra' was not found in construction environment. Ignoring '{workflow_name}' target(s)")
57 Ignore([".", workflow_name], workflow)
Cubit Journal Files#
Review the following journal files in the
waves-tutorials/modsim_package/cubit
directory.
The Cubit journal files include the same CLI introduced in Tutorial 02: Partition and Mesh for the Abaqus journal files. Besides the differences in Abaqus and Cubit commands, the major difference between the Abaqus and Cubit journal files is the opportunity to use Python 3 with Cubit, where Abaqus journal files must use the Abaqus controlled installation of Python 2. The API and CLI built from the Cubit journal files’ docstrings may be found in the WAVES-TUTORIAL API for cubit and the WAVES-TUTORIAL CLI for cubit, respectively.
waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_geometry.py
1import sys
2import pathlib
3import argparse
4
5import cubit
6
7
8def main(output_file, width, height):
9 """Create a simple rectangle geometry.
10
11 This script creates a simple Cubit model with a single rectangle part.
12
13 :param str output_file: The output file for the Cubit model. Will be stripped of the extension and ``.cub`` will be
14 used.
15 :param float width: The rectangle width
16 :param float height: The rectangle height
17
18 :returns: writes ``output_file``.cub
19 """
20 output_file = pathlib.Path(output_file).with_suffix(".cub")
21
22 cubit.init(["cubit", "-noecho", "-nojournal", "-nographics", "-batch"])
23 cubit.cmd("new")
24 cubit.cmd("reset")
25
26 cubit.cmd(f"create vertex 0 0 0")
27 cubit.cmd(f"create vertex {width} 0 0")
28 cubit.cmd(f"create vertex {width} {height} 0")
29 cubit.cmd(f"create vertex 0 {height} 0")
30 cubit.cmd(f"create surface vertex 1,2,3,4")
31
32 cubit.cmd(f"save as '{output_file}' overwrite")
33
34
35def get_parser():
36 script_name = pathlib.Path(__file__)
37 # Set default parameter values
38 default_output_file = script_name.with_suffix(".cub").name
39 default_width = 1.0
40 default_height = 1.0
41
42 prog = f"python {script_name.name} "
43 cli_description = "Create a simple rectangle geometry and write an ``output_file``.cub Cubit model file."
44 parser = argparse.ArgumentParser(description=cli_description, prog=prog)
45 parser.add_argument(
46 "--output-file",
47 type=str,
48 default=default_output_file,
49 # fmt: off
50 help="The output file for the Cubit model. "
51 "Will be stripped of the extension and ``.cub`` will be used, e.g. ``output_file``.cub "
52 "(default: %(default)s",
53 # fmt: on
54 )
55 parser.add_argument(
56 "--width",
57 type=float,
58 default=default_width,
59 help="The rectangle width",
60 )
61 parser.add_argument(
62 "--height",
63 type=float,
64 default=default_height,
65 help="The rectangle height",
66 )
67 return parser
68
69
70if __name__ == "__main__":
71 parser = get_parser()
72 args = parser.parse_args()
73 sys.exit(
74 main(
75 output_file=args.output_file,
76 width=args.width,
77 height=args.height,
78 )
79 )
waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_partition.py
1import sys
2import shutil
3import pathlib
4import argparse
5
6import cubit
7
8
9def main(input_file, output_file, width, height):
10 """Partition the simple rectangle geometry created by ``rectangle_geometry.py``
11
12 This script partitions a simple Cubit model with a single rectangle part.
13
14 **Feature labels:**
15
16 * ``bottom_left`` - bottom left vertex
17 * ``bottom_right`` - bottom right vertex
18 * ``top_right`` - top right vertex
19 * ``top_left`` - top left vertex
20 * ``left`` - left edge nodes
21 * ``top`` - top edge nodes
22 * ``right`` - right edge nodes
23 * ``bottom`` - bottom edge nodes
24 * ``elset_left`` - left edge elements
25 * ``elset_top`` - top edge elements
26 * ``elset_right`` - right edge elements
27 * ``elset_bottom`` - bottom edge elements
28
29 :param str input_file: The Cubit model file created by ``rectangle_geometry.py``. Will be stripped of the extension
30 and ``.cub`` will be used.
31 :param str output_file: The output file for the Cubit model. Will be stripped of the extension and ``.cub`` will be
32 used.
33 :param float width: The rectangle width
34 :param float height: The rectangle height
35
36 :returns: writes ``output_file``.cub
37 """
38 input_file = pathlib.Path(input_file).with_suffix(".cub")
39 output_file = pathlib.Path(output_file).with_suffix(".cub")
40
41 # Avoid modifying the contents or timestamp on the input file.
42 # Required to get conditional re-builds with a build system such as GNU Make, CMake, or SCons
43 if input_file != output_file:
44 shutil.copyfile(input_file, output_file)
45
46 cubit.init(["cubit", "-noecho", "-nojournal", "-nographics", "-batch"])
47 cubit.cmd("new")
48 cubit.cmd("reset")
49
50 cubit.cmd(f"open '{output_file}'")
51
52 cubit.cmd("nodeset 1 add vertex 1")
53 cubit.cmd("nodeset 1 name 'bottom_left'")
54 cubit.cmd("nodeset 2 add vertex 2")
55 cubit.cmd("nodeset 2 name 'bottom_right'")
56 cubit.cmd("nodeset 3 add vertex 3")
57 cubit.cmd("nodeset 3 name 'top_right'")
58 cubit.cmd("nodeset 4 add vertex 4")
59 cubit.cmd("nodeset 4 name 'top_left'")
60
61 cubit.cmd("nodeset 5 add curve 4")
62 cubit.cmd("nodeset 5 name 'left'")
63 cubit.cmd("nodeset 6 add curve 3")
64 cubit.cmd("nodeset 6 name 'top'")
65 cubit.cmd("nodeset 7 add curve 2")
66 cubit.cmd("nodeset 7 name 'right'")
67 cubit.cmd("nodeset 8 add curve 1")
68 cubit.cmd("nodeset 8 name 'bottom'")
69
70 cubit.cmd("sideset 1 add curve 4")
71 cubit.cmd("sideset 1 name 'elset_left'")
72 cubit.cmd("sideset 2 add curve 3")
73 cubit.cmd("sideset 2 name 'elset_top'")
74 cubit.cmd("sideset 3 add curve 2")
75 cubit.cmd("sideset 3 name 'elset_right'")
76 cubit.cmd("sideset 4 add curve 1")
77 cubit.cmd("sideset 4 name 'elset_bottom'")
78
79 cubit.cmd(f"save as '{output_file}' overwrite")
80
81
82def get_parser():
83 script_name = pathlib.Path(__file__)
84 # Set default parameter values
85 default_input_file = script_name.with_suffix(".cub").name.replace("_partition", "_geometry")
86 default_output_file = script_name.with_suffix(".cub").name
87 default_width = 1.0
88 default_height = 1.0
89
90 prog = f"python {script_name.name} "
91 cli_description = (
92 "Partition the simple rectangle geometry created by ``rectangle_geometry.py`` "
93 "and write an ``output_file``.cub Cubit model file."
94 )
95 parser = argparse.ArgumentParser(description=cli_description, prog=prog)
96 parser.add_argument(
97 "--input-file",
98 type=str,
99 default=default_input_file,
100 # fmt: off
101 help="The Cubit model file created by ``rectangle_geometry.py``. "
102 "Will be stripped of the extension and ``.cub`` will be used, e.g. ``input_file``.cub "
103 "(default: %(default)s",
104 # fmt: on
105 )
106 parser.add_argument(
107 "--output-file",
108 type=str,
109 default=default_output_file,
110 # fmt: off
111 help="The output file for the Cubit model. "
112 "Will be stripped of the extension and ``.cub`` will be used, e.g. ``output_file``.cub "
113 "(default: %(default)s",
114 # fmt: on
115 )
116 parser.add_argument(
117 "--width",
118 type=float,
119 default=default_width,
120 help="The rectangle width",
121 )
122 parser.add_argument(
123 "--height",
124 type=float,
125 default=default_height,
126 help="The rectangle height",
127 )
128 return parser
129
130
131if __name__ == "__main__":
132 parser = get_parser()
133 args = parser.parse_args()
134 sys.exit(
135 main(
136 input_file=args.input_file,
137 output_file=args.output_file,
138 width=args.width,
139 height=args.height,
140 )
141 )
waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_mesh.py
1import sys
2import shutil
3import pathlib
4import argparse
5
6import cubit
7
8
9def main(input_file, output_file, global_seed, element_type="QUAD", solver="abaqus"):
10 """Mesh the simple rectangle geometry partitioned by ``rectangle_partition.py``
11
12 This script meshes a simple Cubit model with a single rectangle part.
13
14 **Feature labels:**
15
16 * ``NODES`` - all part nodes
17 * ``ELEMENTS`` - all part elements
18
19 :param str input_file: The Cubit model file created by ``rectangle_partition.py``. Will be stripped of the extension
20 and ``.cub`` will be used.
21 :param str output_file: The output file for the Cubit model. Will be stripped of the extension and ``.cub`` and
22 ``.inp`` will be used for the model and orphan mesh output files, respectively.
23 :param float global_seed: The global mesh seed size
24 :param str element_type: The model element type. Must be a supported Cubit 4 node element type.
25 :param str solver: The solver type to use when exporting the mesh
26
27 :returns: writes ``output_file``.cub and ``output_file``.inp
28
29 :raises RuntimeError: If the solver is not supported
30 """
31 input_file = pathlib.Path(input_file).with_suffix(".cub")
32 output_file = pathlib.Path(output_file).with_suffix(".cub")
33 abaqus_mesh_file = output_file.with_suffix(".inp")
34 sierra_mesh_file = output_file.with_suffix(".g")
35
36 # Avoid modifying the contents or timestamp on the input file.
37 # Required to get conditional re-builds with a build system such as GNU Make, CMake, or SCons
38 if input_file != output_file:
39 shutil.copyfile(input_file, output_file)
40
41 cubit.init(["cubit", "-noecho", "-nojournal", "-nographics", "-batch"])
42 cubit.cmd("new")
43 cubit.cmd("reset")
44
45 cubit.cmd(f"open '{output_file}'")
46
47 cubit.cmd(f"surface 1 size {global_seed}")
48 cubit.cmd("mesh surface 1")
49 cubit.cmd("set duplicate block elements off")
50
51 cubit.cmd("nodeset 9 add surface 1")
52 cubit.cmd("nodeset 9 name 'NODES'")
53
54 cubit.cmd("block 1 add surface 1")
55 cubit.cmd(f"block 1 name 'ELEMENTS' Element type {element_type}")
56
57 cubit.cmd(f"save as '{output_file}' overwrite")
58
59 if solver.lower() == "abaqus":
60 # Export Abaqus orphan mesh for Abaqus workflow
61 cubit.cmd(f"export abaqus '{abaqus_mesh_file}' partial dimension 2 block 1 overwrite everything")
62 elif solver.lower() in ["sierra", "adagio"]:
63 # Export Genesis file for Sierra workflow
64 cubit.cmd(f"export mesh '{sierra_mesh_file}' overwrite")
65 else:
66 raise RuntimeError(f"Uknown solver '{solver}'")
67
68
69def get_parser():
70 script_name = pathlib.Path(__file__)
71 # Set default parameter values
72 default_input_file = script_name.with_suffix(".cub").name.replace("_mesh", "_partition")
73 default_output_file = script_name.with_suffix(".cub").name
74 default_global_seed = 1.0
75 default_element_type = "QUAD"
76 default_solver = "abaqus"
77
78 prog = f"python {script_name.name} "
79 cli_description = (
80 "Mesh the simple rectangle geometry partitioned by ``rectangle_partition.py`` "
81 "and write an ``output_file``.cub Cubit model file and ``output_file``.inp orphan mesh file."
82 )
83 parser = argparse.ArgumentParser(description=cli_description, prog=prog)
84 parser.add_argument(
85 "--input-file",
86 type=str,
87 default=default_input_file,
88 # fmt: off
89 help="The Cubit model file created by ``rectangle_partition.py``. "
90 "Will be stripped of the extension and ``.cub`` will be used, e.g. ``input_file``.cub "
91 "(default: %(default)s",
92 # fmt: on
93 )
94 parser.add_argument(
95 "--output-file",
96 type=str,
97 default=default_output_file,
98 # fmt: off
99 help="The output file for the Cubit model. "
100 "Will be stripped of the extension and ``.cub`` will be used, e.g. ``output_file``.cub",
101 # fmt: on
102 )
103 parser.add_argument(
104 "--global-seed",
105 type=float,
106 default=default_global_seed,
107 help="The global mesh seed size (default: %(default)s)",
108 )
109 parser.add_argument(
110 "--element-type",
111 type=str,
112 default=default_element_type,
113 help="The model element type. Must be a supported Cubit 4 node element type. " "(default: %(default)s)",
114 )
115 parser.add_argument(
116 "--solver",
117 type=str,
118 default=default_solver,
119 choices=["abaqus", "sierra", "adagio"],
120 help="The target solver for the mesh file. (default: %(default)s)",
121 )
122
123 return parser
124
125
126if __name__ == "__main__":
127 parser = get_parser()
128 args = parser.parse_args()
129 sys.exit(
130 main(
131 input_file=args.input_file,
132 output_file=args.output_file,
133 global_seed=args.global_seed,
134 element_type=args.element_type,
135 solver=args.solver,
136 )
137 )
Sierra Input File(s)#
Create or review the Sierra input file from the contents below
waves-tutorials/tutorial_cubit/modsim_package/sierra/rectangle_compression.i
1begin sierra
2
3 begin function line
4 type is analytic
5 evaluate expression = "x"
6 end function line
7
8 begin property specification for material mock
9 density = 0.27000e-08
10 begin parameters for model elastic
11 youngs modulus = 100
12 poissons ratio = 0.3
13 end
14 end
15
16 begin shell section planestress
17 thickness = 0.1
18 end shell section planestress
19
20 begin finite element model rectangle_compression
21 database name = rectangle_mesh.g
22 database type = exodusII
23
24 begin parameters for block ELEMENTS
25 material mock
26 solid mechanics use model elastic
27 section = planestress
28 end
29
30 end finite element model rectangle_compression
31
32 begin adagio procedure adagio
33
34 begin time control
35 begin time stepping block p0
36 start time = 0
37 begin parameters for adagio region adagio
38 time increment = 0.5
39 end
40 end
41 termination time = 1
42 end
43
44 begin adagio region adagio
45 use finite element model rectangle_compression
46
47 begin results output output_rectangle_compression
48 database name = rectangle_compression.e
49 database type = exodusII
50 at time 0 interval = 0.1
51 global variables = kinetic_energy
52 global variables = internal_energy
53 global variables = external_energy
54 global variables = von_mises_max
55 global variables = effective_strain_max
56 nodal variables = displacement
57 nodal variables = force_external
58 nodal variables = force_internal
59 element variables = strain
60 element variables = unrotated_stress
61 element variables = effective_strain
62 element variables = von_mises
63 end
64
65 begin user output
66 include all blocks
67 compute global von_mises_max as max absolute value of element von_mises
68 compute global effective_strain_max as max absolute value of element effective_strain
69 end user output
70
71 begin fixed displacement
72 node set = bottom_left
73 component = x
74 end
75
76 begin fixed displacement
77 node set = bottom_left
78 component = y
79 end
80
81 begin fixed rotation
82 node set = bottom_left
83 component = x
84 end
85
86 begin fixed rotation
87 node set = bottom_left
88 component = y
89 end
90
91 begin fixed rotation
92 node set = bottom_left
93 component = z
94 end
95
96 begin fixed displacement
97 node set = bottom
98 component = y
99 end
100
101 begin prescribed displacement
102 node set = top
103 component = y
104 function = line
105 scale factor = -0.01
106 end
107
108 ## TODO: Do we need to add traction BC for plane stress? Is there a plane stress element?
109
110 begin solver
111 begin cg
112 reference = external
113 target relative residual = 1e-10
114 begin full tangent preconditioner
115 iteration update = 10
116 end full tangent preconditioner
117 end cg
118 end solver
119
120 end adagio region adagio
121
122 end adagio procedure adagio
123
124end sierra
SConstruct#
Note that Sierra requires a separate construction environment from the launching Conda environment. This is because Sierra ships with a version of Python that conflicts with the launching Conda environment. You may need to update the Sierra activation shell command according to the instructions on your local system.
A diff
against the SConstruct
file from Tutorial 04: Simulation is included below to help identify the
changes made in this tutorial.
waves-tutorials/tutorial_cubit/SConstruct
--- /home/runner/work/waves/waves/build/docs/tutorials_tutorial_04_simulation_SConstruct
+++ /home/runner/work/waves/waves/build/docs/tutorial_cubit_SConstruct
@@ -1,7 +1,10 @@
#! /usr/bin/env python
import os
+import sys
+import typing
import pathlib
+import subprocess
import waves
@@ -48,6 +51,20 @@
metavar="COMMAND",
help=f"Override for the Abaqus command. Repeat to specify more than one (default: {default_abaqus_commands})",
)
+default_cubit_commands = [
+ "/apps/Cubit-16.12/cubit",
+ "/usr/projects/ea/Cubit/Cubit-16.12/cubit",
+ "cubit",
+]
+AddOption(
+ "--cubit-command",
+ dest="cubit_command",
+ nargs=1,
+ type="string",
+ action="append",
+ metavar="COMMAND",
+ help=f"Override for the Cubit command. Repeat to specify more than one (default: {default_cubit_commands})",
+)
# Comments used in tutorial code snippets: marker-2
@@ -58,6 +75,7 @@
unconditional_build=GetOption("unconditional_build"),
print_build_failures=GetOption("print_build_failures"),
abaqus_commands=GetOption("abaqus_command"),
+ cubit_commands=GetOption("cubit_command"),
)
# Conditionally print failed task *.stdout files
@@ -69,6 +87,28 @@
env["ABAQUS_PROGRAM"] = env.AddProgram(
env["abaqus_commands"] if env["abaqus_commands"] is not None else default_abaqus_commands
)
+env["CUBIT_PROGRAM"] = env.AddCubit(
+ env["cubit_commands"] if env["cubit_commands"] is not None else default_cubit_commands
+)
+env["FIERRO_IMPLICIT_PROGRAM"] = env.AddProgram(["fierro-parallel-implicit"])
+
+
+# Sierra requires a separate construction environment
+def return_modulepath(modules: typing.Iterable[str]) -> pathlib.Path:
+ """Return parent path of first found module or the current working directory"""
+ return next((pathlib.Path(path).parent for path in modules if pathlib.Path(path).exists()), pathlib.Path("."))
+
+
+sierra_modules = [
+ "/projects/aea_compute/modulefiles/sierra/5.21.6",
+]
+sierra_modulefile_parent = return_modulepath(sierra_modules)
+try:
+ envSierra = waves.scons_extensions.shell_environment(f"module use {sierra_modulefile_parent} && module load sierra")
+except subprocess.CalledProcessError:
+ print("Failed to initialize the Sierra environment", file=sys.stderr)
+ envSierra = Environment()
+envSierra["sierra"] = waves.scons_extensions.add_program(envSierra, ["sierra"])
# Comments used in tutorial code snippets: marker-4
@@ -84,26 +124,33 @@
for key, value in project_variables.items():
env[key] = value
-# Make the project package importable for Python and Abaqus Python environments
-env.PrependENVPath("PYTHONPATH", project_dir)
-
# Comments used in tutorial code snippets: marker-5
# Add builders and pseudo-builders
env.Append(BUILDERS={})
+envSierra.Append(
+ BUILDERS={
+ "Sierra": waves.scons_extensions.sierra_builder_factory(program=envSierra["sierra"]),
+ }
+)
+
# Comments used in tutorial code snippets: marker-6
# Add simulation targets
workflow_configurations = [
- "tutorial_01_geometry",
- "tutorial_02_partition_mesh",
- "tutorial_03_solverprep",
- "tutorial_04_simulation",
+ "abaqus",
+ "sierra",
+ "fierro",
]
for workflow in workflow_configurations:
build_dir = env["variant_dir_base"] / workflow
- SConscript(workflow, variant_dir=build_dir, exports={"env": env}, duplicate=False)
+ SConscript(
+ workflow,
+ variant_dir=build_dir,
+ exports={"env": env, "envSierra": envSierra},
+ duplicate=False,
+ )
# Comments used in tutorial code snippets: marker-7
Note that the Cubit Python files don’t perform any imports from the current modsim project package, so the
PYTHONPATH
modification is no longer required. This tutorial is created in a new, stand-alone subdirectory, so the
previous tutorial workflow configurations are no longer available. Only the sierra
and abaqus
workflow
configurations will be found by SCons at execution time. Finally, note that the cubit
SConscript file is not called
by the SConstruct
file. Instead, the cubit
configuration is reused by the sierra
and abaqus
workflows,
so the Cubit tasks only need to be defined once. To handle this task reuse some additional variable import and export
statements are required by the cubit
configuration file.
Build Targets#
Build the new targets
$ pwd
/path/to/waves-tutorials/tutorial_cubit
$ scons sierra
scons: Reading SConscript files ...
Checking whether /apps/abaqus/Commands/abq2024 program exists.../apps/abaqus/Commands/abq2024
Checking whether abq2024 program exists...no
Checking whether /apps/Cubit-16.12/cubit program exists.../apps/Cubit-16.12/cubit
Checking whether cubit program exists...no
Checking whether sierra program exists.../projects/sierra/sierra5121/install/tools/sntools/engine/sierra
scons: done reading SConscript files.
scons: Building targets ...
Copy("build/sierra/rectangle_compression.i", "modsim_package/sierra/rectangle_compression.i")
cd /home/roppenheimer/waves-tutorials/tutorial_cubit/build/sierra && python /home/roppenheimer/waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_geometry.py > rectangle_geometry.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/tutorial_cubit/build/sierra && python /home/roppenheimer/waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_partition.py > rectangle_partition.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/tutorial_cubit/build/sierra && python /home/roppenheimer/waves-tutorials/tutorial_cubit/modsim_package/cubit/rectangle_mesh.py --element-type SHELL --solver sierra > rectangle_mesh.stdout 2>&1
cd /home/roppenheimer/waves-tutorials/tutorial_cubit/build/sierra && /projects/sierra/sierra5121/install/tools/sntools/engine/sierra adagio -i rectangle_compression.i > 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/abaqus
directory, as shown
below.
$ pwd
/home/roppenheimer/waves-tutorials/tutorial_cubit
$ tree build/sierra/
build/sierra/
|-- rectangle_compression.e
|-- rectangle_compression.i
|-- rectangle_compression.log
|-- rectangle_compression.stdout
|-- rectangle_geometry.cub
|-- rectangle_geometry.stdout
|-- rectangle_mesh.cub
|-- rectangle_mesh.g
|-- rectangle_mesh.stdout
|-- rectangle_partition.cub
`-- rectangle_partition.stdout
0 directories, 11 files