.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "examples/gallery_examples/gallery/10_wheel_ground_contact_patch.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_examples_gallery_examples_gallery_10_wheel_ground_contact_patch.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_examples_gallery_examples_gallery_10_wheel_ground_contact_patch.py:


.. _ref_contact_patch:

========================================================================
Create a contact patch for wrapping between a wheel and ground interface
========================================================================

**Summary**: This example demonstrates how to create a contact patch for use with wrapping
to avoid meshing into a narrow contact region between two objects.

Objective
~~~~~~~~~
This example uses a contact patch for wrapping to avoid the interface of a wheel with the ground
to improve mesh quality when growing prism layers in the region of the contacting faces.

.. image:: ../../../images/contact_patch.png
   :align: center
   :width: 600

The preceding image shows the following:


* Top left: Wheel/ground interface
* Top right: Addition of contact patch
* Lower left: Grouping tolerance at 4 with multiple contact patches
* Lower right: Grouping tolerance at 20 with merged single contact patch



Procedure
~~~~~~~~~
#. Launch an Ansys Prime Server instance and instantiate the meshing utilities
   from the ``lucid`` class.
#. Import the wheel ground geometry.
#. Convert the topo parts to mesh parts so that the contact patch can be created.
#. Create a contact patch between the wheel and the ground.
#. Extract the fluid region using wrapping.
#. Volume mesh with polyhedral and prism cells.
#. Write a CAS file for use in the Fluent solver.
#. Exit the PyPrimeMesh session.

.. GENERATED FROM PYTHON SOURCE LINES 68-73

Launch Ansys Prime Server
~~~~~~~~~~~~~~~~~~~~~~~~~
Import all necessary modules and launch an instance of Ansys Prime Server.
From the PyPrimeMesh client, get the model.
Instantiate meshing utilities from the ``lucid`` class.

.. GENERATED FROM PYTHON SOURCE LINES 73-85

.. code-block:: Python


    import os
    import tempfile

    import ansys.meshing.prime as prime
    from ansys.meshing.prime.graphics import PrimePlotter

    client = prime.launch_prime()
    model = client.model

    mesh_util = prime.lucid.Mesh(model)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Using Ansys Prime Server from container ansys-prime-server-11




.. GENERATED FROM PYTHON SOURCE LINES 86-92

Import CAD geometry
~~~~~~~~~~~~~~~~~~~
Download the wheel ground geometry (FMD) file exported by SpaceClaim.
Import the CAD geometry. The geometry consists of two topo parts: a wheel and an enclosing box.
Labels are defined for the ground topo face on the enclosure and for the wheel
as all the topo faces of the wheel part.

.. GENERATED FROM PYTHON SOURCE LINES 92-112

.. code-block:: Python


    # For Windows OS users, SCDOC or DSCO is also available. For example:
    # wheel_ground_file = prime.examples.download_wheel_ground_scdoc()

    wheel_ground_file = prime.examples.download_wheel_ground_fmd()

    mesh_util.read(wheel_ground_file)


    ###################
    # Visualize results
    # =================
    # .. code-block:: python
    #
    #   display = PrimePlotter()
    #   display.plot(model, scope=prime.ScopeDefinition(model, label_expression="ground, wheel"))
    #   display.show()

    print(model)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Part Summary:

    Part Name: enclosure
    Part ID: 2
        12 Topo Edges
        6 Topo Faces
        1 Topo Volumes

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        1 Volume Zones
            Volume Zone Name(s) : [enclosure]

        6 Label(s)
            Names: [back, front, ground, side_left, side_right, top]

        Bounding box (0 -2.30926e-12 0)
                     (453.2 774.6 655.059)

    Part Name: wheel_body
    Part ID: 3
        1900 Topo Edges
        722 Topo Faces
        1 Topo Volumes

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        1 Volume Zones
            Volume Zone Name(s) : [wheel_body]

        1 Label(s)
            Names: [wheel]

        Bounding box (129.1 119.57 0.0104403)
                     (324.1 655.03 535.509)





.. GENERATED FROM PYTHON SOURCE LINES 113-117

Convert topo parts to mesh parts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Convert the faceted geometry of the topology to mesh for all parts as the contact patch
requires face zonelets from mesh parts as input.

.. GENERATED FROM PYTHON SOURCE LINES 117-123

.. code-block:: Python


    wheel_part = model.get_part_by_name("wheel_body")
    enclosure_part = model.get_part_by_name("enclosure")

    [part.delete_topo_entities(prime.DeleteTopoEntitiesParams(model)) for part in model.parts]





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    [<ansys.meshing.prime.autogen.partstructs.DeleteTopoEntitiesResults object at 0x7f2e8d054230>, <ansys.meshing.prime.autogen.partstructs.DeleteTopoEntitiesResults object at 0x7f2e8d055940>]



.. GENERATED FROM PYTHON SOURCE LINES 124-137

Create a contact patch
~~~~~~~~~~~~~~~~~~~~~~
To create a contact patch, a direction is needed to define the resulting shape of the patch.
A new part is created containing the patch.
A prefix can be specified for the label created for the contact patch face zonelets generated.
The offset distance determines the thickness and extent of the patch.  The source face zonelet is
offset to intersect the planar target face and the intersection used to define the contact patch.
Due to the depth of the treads on the wheel, 20.0 is used as the offset to reach the tire surface.
If multiple contact regions are found, they can be merged by grouping them using the grouping
tolerance distance.  With a grouping tolerance of 4.0, separate contact regions are created for
some of the treads of the tire, see the image at the top of the example. To merge these contact
regions into a single patch, the grouping tolerance distance is increased to 20.0, avoiding small
gaps between contact regions.

.. GENERATED FROM PYTHON SOURCE LINES 137-171

.. code-block:: Python


    # The face zonelets of the wheel are defined as the source.
    # The planar surface must be specified as the target.
    # In this instance, the ground provides the planar target.

    source = wheel_part.get_face_zonelets()
    target = enclosure_part.get_face_zonelets_of_label_name_pattern(
        "ground", prime.NamePatternParams(model)
    )

    params = prime.CreateContactPatchParams(
        model,
        contact_patch_axis=prime.ContactPatchAxis.Z,
        offset_distance=20.0,
        grouping_tolerance=20.0,
        suggested_label_prefix="patch",
    )
    result = prime.SurfaceUtilities(model).create_contact_patch(
        source_zonelets=source, target_zonelets=target, params=params
    )
    print(result.error_code)
    print(model)

    ###################
    # Visualize results
    # =================
    # .. code-block:: python
    #
    #   display = PrimePlotter()
    #   display.plot(
    #          model, scope=prime.ScopeDefinition(model, label_expression="ground, patch*, wheel")
    #   )
    #   display.show()





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    0
    Part Summary:

    Part Name: enclosure
    Part ID: 2
        12 Edge Zonelets
        6 Face Zonelets
        0 Cell Zonelets

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        1 Volume Zones
            Volume Zone Name(s) : [enclosure]

        6 Label(s)
            Names: [back, front, ground, side_left, side_right, top]

        Bounding box (0 -2.30926e-12 0)
                     (453.2 774.6 655.059)

    Part Name: wheel_body
    Part ID: 3
        1900 Edge Zonelets
        722 Face Zonelets
        0 Cell Zonelets

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        1 Volume Zones
            Volume Zone Name(s) : [wheel_body]

        1 Label(s)
            Names: [wheel]

        Bounding box (129.1 119.57 0.0104403)
                     (324.1 655.03 535.509)

    Part Name: __contact_patch__
    Part ID: 4
        2 Edge Zonelets
        1 Face Zonelets
        0 Cell Zonelets

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        0 Volume Zones
            Volume Zone Name(s) : []

        1 Label(s)
            Names: [patch___contact_patch__]

        Bounding box (131.611 284.832 -20)
                     (321.599 488.776 60)





.. GENERATED FROM PYTHON SOURCE LINES 172-177

Wrap the fluid region
~~~~~~~~~~~~~~~~~~~~~
The largest internal region in this instance is the fluid region around the wheel.
Intersection loops are created to capture the features at the corners between the
patch, ground, and wheel.

.. GENERATED FROM PYTHON SOURCE LINES 177-193

.. code-block:: Python


    model.set_global_sizing_params(prime.GlobalSizingParams(model, min=4.0, max=100.0, growth_rate=1.4))

    # Create a size control to limit the size of mesh on the wheel.
    size_control = model.control_data.create_size_control(prime.SizingType.SOFT)
    size_control.set_soft_sizing_params(prime.SoftSizingParams(model=model, max=8.0))
    size_control.set_scope(prime.ScopeDefinition(model=model, label_expression="wheel"))

    wrap_part = mesh_util.wrap(
        min_size=4.0,
        max_size=100.0,
        region_extract=prime.WrapRegion.LARGESTINTERNAL,
        create_intersection_loops=True,
        wrap_size_controls=[size_control],
    )








.. GENERATED FROM PYTHON SOURCE LINES 194-204

Open a pyvistaqt window
=======================
.. code-block:: python

    display = PrimePlotter()
    display.plot(
        model,
        scope=prime.ScopeDefinition(model, label_expression="ground, patch*, wheel"), update=True
    )
    display.show()

.. GENERATED FROM PYTHON SOURCE LINES 204-207

.. code-block:: Python


    print(model)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Part Summary:

    Part Name: __wrap__
    Part ID: 5
        1 Edge Zonelets
        617 Face Zonelets
        0 Cell Zonelets

        0 Edge Zones
            Edge Zone Name(s) : []
        0 Face Zones
            Face Zone Name(s) : []
        1 Volume Zones
            Volume Zone Name(s) : [enclosure.1]

        14 Label(s)
            Names: [___geom_features___, __contact_patch__, __extracted__features__, __intersect_loops__, back, enclosure, front, ground, patch___contact_patch__, side_left, side_right, top, wheel, wheel_body]

        Bounding box (0 -2.30926e-12 -20)
                     (453.2 774.6 655.059)





.. GENERATED FROM PYTHON SOURCE LINES 208-211

Volume mesh
~~~~~~~~~~~
Apply five layers of prisms to the wheel, patch, and ground. Mesh with polyhedrals.

.. GENERATED FROM PYTHON SOURCE LINES 211-234

.. code-block:: Python


    model.set_global_sizing_params(prime.GlobalSizingParams(model, min=4.0, max=100.0, growth_rate=1.4))
    mesh_util.volume_mesh(
        volume_fill_type=prime.VolumeFillType.POLY,
        prism_layers=5.0,
        prism_surface_expression="wheel, patch*, ground",
        prism_volume_expression="*",
        scope=prime.lucid.VolumeScope(part_expression=wrap_part.name),
    )

    display = PrimePlotter()
    display.plot(
        model,
        scope=prime.ScopeDefinition(model, label_expression="!front !side_right !top"),
        update=True,
    )
    display.show()

    mesh_util.create_zones_from_labels()

    wrap_part._print_mesh = True
    print(wrap_part)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /examples/gallery_examples/gallery/images/sphx_glr_10_wheel_ground_contact_patch_001.png
        :alt: 10 wheel ground contact patch
        :srcset: /examples/gallery_examples/gallery/images/sphx_glr_10_wheel_ground_contact_patch_001.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/runner/work/pyprimemesh/pyprimemesh/doc/source/examples/gallery_examples/gallery/images/sphx_glr_10_wheel_ground_contact_patch_001.vtksz



.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    Part Name: __wrap__
    Part ID: 5
        1 Edge Zonelets
        617 Face Zonelets
        1 Cell Zonelets

        0 Edge Zones
            Edge Zone Name(s) : []
        8 Face Zones
            Face Zone Name(s) : [__contact_patch___patch___contact_patch__, wheel_wheel_body, back_enclosure, enclosure_top, enclosure_front, enclosure_side_left, enclosure_ground, enclosure_side_right]
        1 Volume Zones
            Volume Zone Name(s) : [enclosure.1]

        14 Label(s)
            Names: [___geom_features___, __contact_patch__, __extracted__features__, __intersect_loops__, back, enclosure, front, ground, patch___contact_patch__, side_left, side_right, top, wheel, wheel_body]

        Bounding box (-1.22259e-18 -2.30926e-12 -20)
                     (453.2 774.6 655.059)

        Mesh Summary: 
            1029675 Nodes 
            64423 Poly Faces 
            0 Quad Faces 
            0 Tri Faces 
            64423 Faces 
            397911 Poly Cells 
            0 Hex Cells 
            0 Prism Cells 
            0 Pyramid Cells 
            0 Tet Cells 
            397911 Cells 





.. GENERATED FROM PYTHON SOURCE LINES 235-238

Write model
~~~~~~~~~~~
Write a CAS file for use in the Fluent solver.

.. GENERATED FROM PYTHON SOURCE LINES 238-248

.. code-block:: Python


    with tempfile.TemporaryDirectory() as temp_folder:
        wheel_model = os.path.join(temp_folder, "wheel_ground_contact.cas.h5")
        prime.FileIO(model).export_fluent_case(
            wheel_model,
            export_fluent_case_params=prime.ExportFluentCaseParams(model, cff_format=True),
        )
        assert os.path.exists(wheel_model)
        print(f"Fluent case exported at {wheel_model}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Fluent case exported at /tmp/tmpyvlapuqb/wheel_ground_contact.cas.h5




.. GENERATED FROM PYTHON SOURCE LINES 249-251

Exit the PyPrimeMesh session
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 251-253

.. code-block:: Python


    client.exit()








.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (2 minutes 59.063 seconds)


.. _sphx_glr_download_examples_gallery_examples_gallery_10_wheel_ground_contact_patch.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: 10_wheel_ground_contact_patch.ipynb <10_wheel_ground_contact_patch.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: 10_wheel_ground_contact_patch.py <10_wheel_ground_contact_patch.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: 10_wheel_ground_contact_patch.zip <10_wheel_ground_contact_patch.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_