.. _tutorial_partition_mesh:

###############################
Tutorial 02: Partition and Mesh
###############################

**********
References
**********

* Adding to `PYTHONPATH`_ with `SCons PrependENVPath`_ method :cite:`scons-user`
* `Abaqus Node Sets`_ :cite:`ABAQUS`
* `Abaqus Element Sets`_ and `Abaqus Elements Guide`_ :cite:`ABAQUS`
* `Abaqus Assembly Definition`_ :cite:`ABAQUS`

***********
Environment
***********

.. include:: tutorial_environment_activation.txt

.. include:: version_check_warning.txt

*******************
Directory Structure
*******************

.. include:: directory_structure_purpose.txt

.. include:: tutorial_directory_setup.txt

.. note::

   If you skipped any of the previous tutorials, run the following commands to create a copy of the necessary tutorial
   files.

   .. only:: not epub

      .. tab-set::
         :sync-group: OS

         .. tab-item:: Linux/MacOS
            :sync: bash

            .. code-block::

               $ pwd
               /home/roppenheimer/waves-tutorials
               $ waves fetch --overwrite --tutorial 1 && mv tutorial_01_geometry_SConstruct SConstruct
               WAVES fetch
               Destination directory: '/home/roppenheimer/waves-tutorials'

         .. tab-item:: Windows
            :sync: powershell

            .. code-block::

               PS > Get-Location

               Path
               ----
               C:\Users\roppenheimer\waves-tutorials

               PS > waves fetch --overwrite --tutorial 1 && Move-Item tutorial_01_geometry_SConstruct SConstruct -Force
               WAVES fetch
               Destination directory: 'C:\Users\roppenheimer\waves-tutorials'

4. Fetch the ``tutorial_01_geometry`` file and create a new file named ``tutorial_02_partition_mesh``
   using the :ref:`waves_cli` :ref:`waves_fetch_cli` subcommand.

.. only:: not epub

   .. tab-set::
      :sync-group: OS

      .. tab-item:: Linux/MacOS
         :sync: bash

         .. code-block:: bash

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

      .. tab-item:: Windows
         :sync: powershell

         .. code-block:: powershell

            PS > Get-Location

            Path
            ----
            C:\Users\roppenheimer\waves-tutorials

            PS > waves fetch --overwrite tutorials\tutorial_01_geometry && Copy-Item tutorial_01_geometry tutorial_02_partition_mesh
            WAVES fetch
            Destination directory: 'C:\Users\roppenheimer\waves-tutorials'

.. _tutorials_tutorial_partition_mesh:

**********
SConscript
**********

5. Modify your ``tutorial_02_partition_mesh`` file by adding the contents below immediately after the code
   pertaining to ``# Geometry`` from the previous tutorial, and above the ``# Collector alias`` code.

.. admonition:: waves-tutorials/tutorial_02_partition_mesh

   .. literalinclude:: tutorials_tutorial_02_partition_mesh
      :language: Python
      :lineno-match:
      :start-after: marker-2
      :end-before: marker-3

Just like building the geometry in :ref:`tutorial_geometry`, the code you just added instructs SCons on how to
build the targets for partitioning and meshing our rectangle part.

In the code pertaining to ``# Partition``, we will again pass an empty string for the ``subcommand_options``. We will
re-open the discussion of using the journal file's command-line interface via the ``subcommand_options`` variable in
:ref:`tutorial_parameter_substitution`. Next, the ``workflow`` list is extended once again to include the action
to use the :meth:`waves.scons_extensions.abaqus_journal_builder_factory` builder. The ``target`` list specifies the
files created by the :meth:`waves.scons_extensions.abaqus_journal_builder_factory` builder's action, and the ``source``
list specifies on which files to act in order to produce the targets.

Keen readers will note that this source-target definition is different from that in :ref:`tutorial_geometry`.
Here, we again specify two targets, ``rectangle_partition.cae`` and ``rectangle_partition.jnl``, each of which
are now generated by performing an action on *not one, but two* sources. The first source is similar to that in
:ref:`tutorial_geometry`, where we run the ``rectangle_partition.py`` file in the Abaqus kernel, but now the default
behavior of the journal is different.

6. In the :ref:`abaqus_rectangle_partition_cli` file, you'll notice that a new parameter is defined here that was absent
   in ``rectangle_geometry.py``. This parameter is defined in short with ``-i`` or verbosely by ``--input-file``.

The ``--input-file`` command-line argument defaults to the string ``'rectangle_geometry'`` and does not require a
file extension. So, we simply need to make sure that the ``rectangle_geometry.cae`` file (which is an output from
the code we wrote in :ref:`tutorial_geometry`) be included in the ``source`` list. If
``rectangle_geometry.cae`` were left out of the source list, the SCons build system would not be able to determine
that the partition target depends on the geometry target. This would result in an indeterminate race condition in target
execution order. Incomplete source and target lists also make it impossible for the build system to automatically
determine when a target needs to be re-built. If not specified as a source, the ``rectangle_geometry.cae`` file
could change and the build system would not know that the ``rectangle_partition.cae`` target needs to be re-built.

With the two sources defined, the :meth:`waves.scons_extensions.abaqus_journal_builder_factory` builder has all the
information it needs to build the ``rectangle_partition.cae`` target.

In the code pertaining to ``# Mesh``, the trend continues. We will re-assign the ``journal_file`` variable to the
meshing journal file name to reduce hard-coded duplication of strings. We define an empty string for
``subcommand_options``, as nothing other than the default is required for this task. We finally extend the workflow to
utilize the :meth:`waves.scons_extensions.abaqus_journal_builder_factory` builder on the ``source`` list. Just like the
code for ``# Partition``, we have two sources. In this tutorial, we rely on the ``rectangle_mesh.py`` CLI default
arguments which will use the ``rectangle_partition.cae`` file as the input model file. Readers are encouraged to return
to the :ref:`waves_tutorial_cli` to become familiar with the command-line arguments available for the journal files in
this tutorial.

The mesh task produces more than one output file, so the ``target`` list has changed size.
You should now be familiar with the behavior that generates the ``rectangle_mesh.cae`` and ``rectangle_mesh.jnl``
targets. The new target is the ``rectangle_mesh.inp`` file. This file is called an *orphan mesh* file. When the
:meth:`waves.scons_extensions.abaqus_journal_builder_factory` builder acts on the ``rectangle_mesh.py`` file, our three
target files are created. The orphan mesh file is created by calling the ``export_mesh()`` function within the
``rectangle_mesh.py`` file. See the :ref:`sphinx_abaqus_utilities_api` file for more information about the
``export_mesh()`` function.

In summary of the changes you just made to the ``tutorial_02_partition_mesh`` file, a ``diff`` against the
``SConscript`` file from :ref:`tutorial_geometry` is included below to help identify the changes made in this
tutorial.

.. admonition:: waves-tutorials/tutorial_02_partition_mesh

   .. literalinclude:: tutorials_tutorial_02_partition_mesh
      :language: Python
      :diff: tutorials_tutorial_01_geometry

*******************
Abaqus Journal File
*******************

Recall from :ref:`tutorial_geometry` that you created an Abaqus journal file called
``rectangle_geometry.py``. You will now create two more for the partitioning and meshing workflows. The reader is
referred to the following sections in :ref:`tutorial_geometry` for a reminder of different aspects of these
journal files:

* :ref:`tutorial_geometry_waves_main_functions`
* :ref:`tutorial_geometry_waves_python_docstrings`
* :ref:`tutorial_geometry_waves_abaqus_python_code`
* :ref:`tutorial_geometry_waves_command_line_interfaces`
* :ref:`tutorial_geometry_waves_top_level_code_environment`
* :ref:`tutorial_geometry_waves_retrieving_exit_codes`

7. In the ``modsim_package/abaqus`` directory, create a file called ``rectangle_partition.py`` using all the contents
   below.

.. admonition:: waves-tutorials/modsim_package/abaqus/rectangle_partition.py

    .. literalinclude:: abaqus_rectangle_partition.py
        :language: Python
        :lineno-match:

The ``rectangle_partition.py`` file is laid out in a very similar fashion to ``rectangle_geometry.py``. It
contains a ``main()`` function with `PEP-287`_ formatted docstrings. Within that ``main()`` function is Abaqus python
code that does a few specific tasks:

* Format the ``--input-file`` and ``--output-file`` command-line argument values with ``.cae`` file extensions
* Copy the ``input_file`` to an identical ``output_file`` with a new name. This is necessary because Abaqus changes the
  contents of ``*.cae`` files on open. The content change will cause the build system to always re-run the task that
  generated the ``input_file``.
* Within the new ``output_file``, do the following:

  * Create node sets at four corners of the rectangle part. See the `Abaqus Node Sets`_ documentation :cite:`ABAQUS` for
    more information about node sets.
  * Create node sets for the four sides of the rectangle part.

* Save the ``output_file`` with the changes made

The :ref:`abaqus_rectangle_partition_cli` script also contains an argument parser function which implements the
documented command line interface. The argument parser functions in a very similar way to that in the
``rectangle_geometry.py`` file, but a new command-line argument ``--input-file`` is added. This command-line argument
is how the script knows which file to copy and then modify in the Abaqus python code.

Lastly, the execution of the ``main()`` function is protected within the context of a ``if __name__ == "__main__":``
statement, and the ``main()`` function is called within ``sys.exit()`` for exit code retrieval.

8. In the ``modsim_package/abaqus`` directory, create a file called ``abaqus_utilities.py`` using the contents
   below.

.. admonition:: waves-tutorial/modsim_package/abaqus/abaqus_utilities.py

   .. literalinclude:: abaqus_abaqus_utilities.py
      :language: Python
      :lineno-match:
      :end-before: marker-1

The ``abaqus_utilities.py`` script's purpose is to contain commonly used functions that we do not want to
duplicate. At the moment, we have only created two functions - ``export_mesh()`` and ``return_abaqus_constant()``.
The ``export_mesh`` function utilizes an `Abaqus Model Object`_ :cite:`ABAQUS` along with a ``part_name`` and
``orphan_mesh_file`` name to create an orphan mesh file. Orphan mesh files define the entire part's mesh in a
text-based file. The node and element locations and labels are listed in a tabular format that the Abaqus file parser
understands. The ``return_abaqus_constant`` function utilizes a search string and will return the matching
``abaqusConstants`` attribute if it exists. The ``return_abaqus_constant`` is not relevant to this tutorial but will be
utilized in :ref:`tutorial_part_image`.

9. In the ``modsim_package/abaqus`` directory, create a file called ``rectangle_mesh.py`` using all the contents
   below.

.. admonition:: waves-tutorials/modsim_package/abaqus/rectangle_mesh.py

    .. literalinclude:: abaqus_rectangle_mesh.py
        :language: Python
        :lineno-match:

The ``rectangle_mesh.py`` file will have many similarities in code structure to the ``rectangle_geometry.py``
and ``rectangle_partition.py`` files. The first significant change is within the ``import`` statements at the top
of the file. The ``rectangle_mesh.py`` file uses the ``export_mesh()`` function that is imported from the
``abaqus_utilities.py`` file you just created. ``abaqus_utilities.py`` exists in the
``modsim_package/abaqus`` directory, and is never copied to the build directory.

It is possible to use a normal looking import statement because we will modify `PYTHONPATH`_ in the project
``SConstruct`` configuration file. Abaqus Python and Python 3 environments will both inherit the `PYTHONPATH`_ and
search for packages on the paths in this environment variable. While this path modification would be bad practice for a
Python package, since we aren't packaging and deploying our modsim Python modules this path modification is required.
Care should still be taken to avoid naming conflicts between the modsim package directory and any Python packages that
may exist in the active Conda environment.

.. note::

   The ``rectangle_mesh.py`` script is also never copied to the build directory, so we can utilize the path of the
   ``rectangle_mesh.py`` file to point to the location of the ``abaqus_utilities`` file as well. The journal
   files are executed via absolute path from within the build directory, so the output from these scripts is placed in
   the build directory.

From this point, the ``main()`` function proceeds to copy the input file just like in ``rectangle_partition.py``.
The code that follows performs the following tasks within the new ``output_file``:

* Create a part instance that can be meshed. See the `Abaqus Assembly Definition`_ documentation :cite:`ABAQUS` for
  more information about defining parts, part instances, and assemblies.
* Seed the part using the ``--global-seed`` command-line argument value to define the global meshing size
* Mesh the part
* Assign an element type to the part. See the `Abaqus Elements Guide`_ :cite:`ABAQUS` for more information about
  defining element types.
* Define element and node sets for elements and nodes that may require output requests in the model. See the `Abaqus
  Element Sets`_ documentation :cite:`ABAQUS` for more information about element sets.
* Create an orphan mesh file by calling the ``export_mesh()`` function that was imported from
  ``abaqus_utilities.py``
* Save the ``output_file`` with the changes made

The ``rectangle_mesh.py`` script also contains an argument parser function. This command-line interface has yet
another new argument ``--global-seed``. This argument defines global mesh sizing for the model and has a default value
that is assigned to the ``global_seed`` variable if not specified when calling the script.

All other aspects of the ``rectangle_mesh.py`` file are the same as ``rectangle_partition.py``.

**********
SConstruct
**********

10. Add ``tutorial_02_partition_mesh`` to the ``workflow_configurations`` list in the
    ``waves-tutorials/SConscruct`` file.

A ``diff`` against the SConstruct file from :ref:`tutorial_geometry` is included below to help identify the
changes made in this tutorial.

   ..  admonition:: waves-tutorials/SConstruct

     .. literalinclude:: tutorials_tutorial_02_partition_mesh_SConstruct
        :language: python
        :diff: tutorials_tutorial_01_geometry_SConstruct

Note the `PYTHONPATH`_ modification by `SCons PrependENVPath`_. This modification to the project's construction
environment will allow Abaqus Python to import the project module files used by ``rectangle_mesh.py``.

*************
Build Targets
*************

11. Build the new targets

.. only:: not epub

   .. tab-set::
      :sync-group: OS

      .. tab-item:: Linux/MacOS
         :sync: bash

         .. code-block::

            $ pwd
            /home/roppenheimer/waves-tutorials
            $ scons tutorial_02_partition_mesh
            scons: Reading SConscript files ...
            Checking whether '/apps/abaqus/Commands/abq2024' program exists.../apps/abaqus/Commands/abq2024
            Checking whether '/usr/projects/ea/abaqus/Commands/abq2024' program exists...no
            Checking whether 'abq2024' program exists.../apps/abaqus/Commands/abq2024
            Checking whether 'abaqus' program exists...no
            scons: done reading SConscript files.
            scons: Building targets ...
            cd /home/roppenheimer/waves-tutorials/build/tutorial_02_partition_mesh && /apps/abaqus/Commands/abq2024 cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_geometry.py -- > rectangle_geometry.cae.stdout 2>&1
            cd /home/roppenheimer/waves-tutorials/build/tutorial_02_partition_mesh && /apps/abaqus/Commands/abq2024 -information /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_partition.py -- > rectangle_partition.cae.stdout 2>&1
            cd /home/roppenheimer/waves-tutorials/build/tutorial_02_partition_mesh && /apps/abaqus/Commands/abq2024 cae -noGui /home/roppenheimer/waves-tutorials/modsim_package/abaqus/rectangle_mesh.py -- > rectangle_mesh.cae.stdout 2>&1
            scons: done building targets.

      .. tab-item:: Windows
         :sync: powershell

         .. code-block::

            PS > Get-Location

            Path
            ----
            C:\Users\roppenheimer\waves-tutorials

            PS > scons tutorial_02_partition_mesh
            scons: Reading SConscript files ...
            Checking whether '/apps/abaqus/Commands/abq2024' program exists...no
            Checking whether '/usr/projects/ea/abaqus/Commands/abq2024' program exists...no
            Checking whether 'abq2024' program exists...C:\SIMULIA\Commands\abq2024.BAT
            Checking whether 'abaqus' program exists...C:\SIMULIA\Commands\abaqus.BAT
            scons: done reading SConscript files.
            scons: Building targets ...
            cd C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh && C:\SIMULIA\Commands\abq2024.BAT cae -noGUI  C:\Users\roppenheimer\waves-tutorials\modsim_package\abaqus\rectangle_geometry.py -- > C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh\rectangle_geometry.cae.stdout 2>&1
            cd C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh && C:\SIMULIA\Commands\abq2024.BAT cae -noGUI  C:\Users\roppenheimer\waves-tutorials\modsim_package\abaqus\rectangle_partition.py -- > C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh\rectangle_partition.cae.stdout 2>&1
            cd C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh && C:\SIMULIA\Commands\abq2024.BAT cae -noGUI  C:\Users\roppenheimer\waves-tutorials\modsim_package\abaqus\rectangle_mesh.py -- > C:\Users\roppenheimer\waves-tutorials\build\tutorial_02_partition_mesh\rectangle_mesh.inp.stdout 2>&1
            scons: done building targets.

************
Output Files
************

Explore the contents of the ``build`` directory using the ``tree`` command against the ``build`` directory, as shown
below.

.. only:: not epub

   .. tab-set::
      :sync-group: OS

      .. tab-item:: Linux/MacOS
         :sync: bash

         .. code-block::

            $ pwd
            /home/roppenheimer/waves-tutorials
            $ tree build/tutorial_01_geometry/ build/tutorial_02_partition_mesh/
            build/tutorial_01_geometry/
            |-- abaqus.rpy
            |-- rectangle_geometry.cae
            |-- rectangle_geometry.jnl
            `-- rectangle_geometry.cae.stdout
            build/tutorial_02_partition_mesh/
            |-- abaqus.rpy
            |-- abaqus.rpy.1
            |-- abaqus.rpy.2
            |-- rectangle_geometry.cae
            |-- rectangle_geometry.jnl
            |-- rectangle_geometry.cae.stdout
            |-- rectangle_mesh.cae
            |-- rectangle_mesh.inp
            |-- rectangle_mesh.jnl
            |-- rectangle_mesh.cae.stdout
            |-- rectangle_partition.cae
            |-- rectangle_partition.jnl
            `-- rectangle_partition.cae.stdout

            0 directories, 16 files

      .. tab-item:: Windows
         :sync: powershell

         .. code-block::

            PS > Get-Location

               Path
               ----
               C:\Users\roppenheimer\waves-tutorials

            PS > tree build /F
            C:\USERS\ROPPENHEIMER\WAVES-TUTORIALS\BUILD
            ├───tutorial_01_geometry
            │       abaqus.rpy
            │       rectangle_geometry.cae
            │       rectangle_geometry.cae.stdout
            │       rectangle_geometry.jnl
            │
            └───tutorial_02_partition_mesh
                    abaqus.rpy
                    abaqus.rpy.1
                    abaqus.rpy.2
                    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

Examine the contents of the ``build/tutorial_01_geometry`` and a ``build/tutorial_02_partition_mesh`` directories.
Recall from the earlier note that we require the geometry target introduced in :ref:`tutorial_geometry` to build the
partition and mesh targets. There is an important distinction to be made here. This tutorial is **NOT** using the
outputs from :ref:`tutorial_geometry`'s
:ref:`tutorial_geometry_waves_build_targets` section when we executed the ``$ scons tutorial_01_geometry`` command. This
tutorial is using the outputs generated from executing the same code, but from our new
``tutorial_02_partition_mesh`` file. For this reason, we see the same outputs from the
``build/tutorial_01_geometry`` directory in the ``build/tutorial_02_partition_mesh`` directory (along with other
:ref:`tutorial_partition_mesh` output files).

The new output files pertain to the partitioning and meshing steps we added to the workflow. The file extensions are the
same as when we ran the geometry workflow, but now we have an added ``rectangle_mesh.inp`` orphan mesh file.

**********************
Workflow Visualization
**********************

View the workflow directed graph by running the following command and opening the image in your preferred image viewer.

.. only:: not epub

   .. tab-set::
      :sync-group: OS

      .. tab-item:: Linux/MacOS
         :sync: bash

         .. code-block::

            $ pwd
            /home/roppenheimer/waves-tutorials
            $ waves visualize tutorial_02_partition_mesh --output-file tutorial_02_partition_mesh.png --width=28 --height=3 --exclude-list /usr/bin .stdout .jnl

      .. tab-item:: Windows
         :sync: powershell

         .. code-block::

            PS > Get-Location

            Path
            ----
            C:\Users\roppenheimer\waves-tutorials

            PS > waves visualize tutorial_02_partition_mesh --output-file tutorial_02_partition_mesh.png --width=28 --height=3 --exclude-list .stdout .jnl

The output should look similar to the figure below.

.. raw:: latex

    \begin{landscape}
        \vspace*{\fill}

.. figure:: tutorial_02_partition_mesh.png
   :align: center
   :width: 100%

.. raw:: latex

        \vspace*{\fill}
    \end{landscape}

As in :ref:`tutorial_geometry`, the visualization of the workflow directed graph looks relatively simple to
manage. In part, this is because we've removed some of the automanaged output files with the ``--exclude-list`` option
of the |project| :ref:`waves_visualize_cli` subcommand. Probably you would not try to manage all of these files in a
manual workflow; however, files like the ``*.stdout`` are important for debugging errors and lose significant value if
they can't be tied uniquely to the most recent execution.

There are two important features of the new workflow graph. First, notice that the ``rectangle_partition.cae`` and
``rectangle_mesh.cae`` files have two dependencies. As defined in the task definitions, they depend on their
respective Abaqus journal file and the previous script's output ``*.cae`` file. While we defined these tasks in the
order they need to be executed, this was not strictly necessary and the tasks could be defined in any order within the
``SConscript`` file. The actual directed graph is assembled automatically by `SCons`_ from the target and source lists
that define each task. For a simple workflow, this is relatively trivial. As the workflow grows, and especially after
adding parameter studies, assembling the task execution order will become increasingly difficult and the benefits of the
build system will become more clear.

Second, notice that all output ``*.cae`` and ``*.inp`` files are tied directly to the ``tutorial_02_partition_mesh``
alias. This is a result of appending all targets of the workflow to the workflow alias. This is useful if, for instance,
there are some images produced by an intermediate step which aren't strictly required by the final simulation results
file. Such files may be useful for plotting geometric images used in documentation, but not necessary for the simulation
or analysis results. The target alias can capture all relevant intermediate output which isn't captured by the
simulation results file target and simplify the scons command to execute this workflow.

As the tutorial workflow grows in size and complexity, or for workflows of mature modsim projects, it will become harder
to view the shape of the directed graph with legible file names. Users are encouraged to build local copies and zoom in
and out to explore the directed graph. The :ref:`waves_visualize_cli` options for ``--width``, ``--height``, and
``--font-size`` as well as vector graphic file formats (e.g. ``*.pdf`` output in place of ``*.png``) can help make
workflow graphs more useful beyond the general impressions of workflow shape and complexity.
