.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "examples/gallery_examples/gallery/09_multi_layer_quad_mesh_pcb.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_09_multi_layer_quad_mesh_pcb.py>`
        to download the full example code.

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

.. _sphx_glr_examples_gallery_examples_gallery_09_multi_layer_quad_mesh_pcb.py:


.. _ref_multi_layer_pcb_mesh:

=====================================================
Mesh a generic PCB geometry with multiple hexa layers
=====================================================

**Summary**: This example demonstrates how to set the base mesh size and number of
layers for each solid in a generic PCB geometry and then generate a mesh.

Objective
~~~~~~~~~~

The example uses PyPrimeMesh to discretize a PCB CAD geometry by means of the
stacker technology. You can easily set up the mesh size of the base face (xy plane
in this example) and the number of mesh layers along the sweep direction (z axis in this example).
The CAD edges along the z direction are assigned with a named selection at a CAD level in Ansys
Discovery/SpaceClaim.

The following image provides a snapshot of the Discovery tree to help you to understand the model's
organization. Share topology in Discovery/SpaceClaim guarantees the generation of a conformal mesh
between the solids. Named selections of edges allow you to specify the number of mesh elements to
generate along the sweep direction. To simplify the process and enhance convenience, this example
uses multiple meshing utilities provided in the ``lucid`` class.

.. image:: ../../../images/multi_layer_quad_mesh_pcb.png
   :align: center
   :width: 800
   :alt: Generic PCB geometry.

The resulting mesh with three layers per solid looks like this:

.. image:: ../../../images/multi_layer_quad_mesh_pcb_3.png
   :align: center
   :width: 500
   :alt: Generic PCB geometry meshed.

.. image:: ../../../images/multi_layer_quad_mesh_pcb_2.png
   :align: center
   :width: 500
   :alt: Generic PCB geometry meshed, zoom in.


Procedure
~~~~~~~~~~
#. Import the fundamental libraries that are necessary to run the script.
#. Launch an Ansys Prime Server instance.
#. Instantiate the meshing utilities from the ``lucid`` class.
#. Define the base mesh size and number of layers along the sweep direction.
#. Import the CAD geometry.
#. Define the edge sizing along the sweep direction using existing edge named selections.
#. Define the parameters for the volume sweeper.
#. Set up, generate, and mesh the base face.
#. Stack the base face along the sweep direction.
#. Set up the zone naming before the mesh output.
#. Write a CAS file for use in the Fluent solver.
#. Exit the PyPrimeMesh session.

.. GENERATED FROM PYTHON SOURCE LINES 84-88

Import all necessary modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Notice that you must install the PyVista library to be able to run the visualization
tools included in this script.

.. GENERATED FROM PYTHON SOURCE LINES 88-95

.. code-block:: Python


    import os
    import tempfile

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








.. GENERATED FROM PYTHON SOURCE LINES 96-101

Launch Prime server and instantiate the ``lucid`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Launch an instance of Ansys Prime Server.
Connect the PyPrimeMesh client and get the model.
Instantiate meshing utilities from the ``lucid`` class.

.. GENERATED FROM PYTHON SOURCE LINES 101-106

.. code-block:: Python


    prime_client = prime.launch_prime()
    model = prime_client.model
    mesh_util = prime.lucid.Mesh(model=model)





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

 .. code-block:: none

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




.. GENERATED FROM PYTHON SOURCE LINES 107-115

Define CAD file and mesh settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Define the number of layers per solid.
Define the size in mm of the quad-dominant mesh on the base size.
Define the path to the CAD file to mesh.
Download the example CAD file using the ``prime.examples`` function. Otherwise,
write the path to the desired CAD file on your machine. Supported file types
are SCDOC, DSCO, and PMDB.

.. GENERATED FROM PYTHON SOURCE LINES 115-124

.. code-block:: Python


    # cad_file='/path/to/any/cad/file.dsco'
    cad_file = prime.examples.download_multi_layer_quad_mesh_pcb_pmdat()
    layers_per_solid = 4  # number of hexa mesh layers in each solid
    base_face_size = 0.5  # surface mesh size in mm on the base face
    # Chose whether to display the CAD/mesh at every stage
    display_intermediate_steps = True  # Use True/False









.. GENERATED FROM PYTHON SOURCE LINES 125-129

Import geometry
~~~~~~~~~~~~~~~
Import the geometry into Prime server.
Use the Workbench ``CadReaderRoute`` to ensure that the shared topology is kept.

.. GENERATED FROM PYTHON SOURCE LINES 129-136

.. code-block:: Python


    mesh_util.read(file_name=cad_file)
    # Use the following command to open CAD files of these types: SCDOC, DSCO, and PMDB.
    # mesh_util.read(
    #     file_name = cad_file,
    #     cad_reader_route = prime.CadReaderRoute.WORKBENCH)








.. GENERATED FROM PYTHON SOURCE LINES 137-139

Display the imported CAD in a PyVista window
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 139-144

.. code-block:: Python

    if display_intermediate_steps:
        display = PrimePlotter()
        display.plot(model)
        display.show()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_001.png
        :alt: 09 multi layer quad mesh pcb
        :srcset: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_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_09_multi_layer_quad_mesh_pcb_001.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 145-152

Define edge sizing constraints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set generic global sizing from 0.002mm to 2mm.
Extract the the edge's length from the named selections, such as "edge_1_0.50_mm"
(extract 0.5 mm length) or "edge_23_0.27_mm" (extract 0.27mm length).
On each edge, assign a size equal to the edge's length divided by the
predefined number of layers per solid.

.. GENERATED FROM PYTHON SOURCE LINES 152-181

.. code-block:: Python


    # Set generic global sizing from 0.002mm to 2mm.
    model.set_global_sizing_params(prime.GlobalSizingParams(model, min=0.002, max=2.0))
    ids = []
    # collect the imported geometry
    part = model.parts[0]
    for label in part.get_labels():
        # Check whether the named selection's name starts with the string "edge"
        if label.startswith('edge'):
            # Extract the edge's length, splitting its name at every "_" string
            # Collect the second to last number
            length = float(label.split("_")[-2])  # get 0.27 from "edge_23_0.27_mm"
            # Initialize a constant-size mesh control (SOFT)
            soft_size_control = model.control_data.create_size_control(prime.SizingType.SOFT)
            # Assign a mesh size equal to the edge's length/number of mesh layers
            soft_size_params = prime.SoftSizingParams(model=model, max=length / layers_per_solid)
            # Finalize the creation of mesh sizing
            soft_size_control.set_soft_sizing_params(soft_size_params)
            soft_size_scope = prime.ScopeDefinition(
                model,
                part_expression=part.name,
                entity_type=prime.ScopeEntity.FACEANDEDGEZONELETS,
                label_expression=label + "*",
            )
            soft_size_control.set_scope(soft_size_scope)
            soft_size_control.set_suggested_name(label)
            # Append the id of the edge sizing to the edge sizings' ids' list
            ids.append(soft_size_control.id)








.. GENERATED FROM PYTHON SOURCE LINES 182-189

Define controls for volume sweeper
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the sweep direction vector.
Set up the geometric tolerances for lateral and stacking defeature.
Select the sweep direction as the z axis (0,0,1).
Append the IDs of the soft local sizings that have been previously defined on
the edges.

.. GENERATED FROM PYTHON SOURCE LINES 189-202

.. code-block:: Python


    # Instantiate the volume sweeper
    sweeper = prime.VolumeSweeper(model)
    # Define the parameters for stacker
    stacker_params = prime.MeshStackerParams(
        model=model,
        direction=[0, 0, 1],  # define the sweep direction for the mesh
        delete_base=True,  # delete the base face in the end of stacker
        lateral_defeature_tolerance=0.001,
        stacking_defeature_tolerance=0.001,
        size_control_ids=ids,
    )  # list of control IDs to be respected by the stacker








.. GENERATED FROM PYTHON SOURCE LINES 203-210

Set up, generate, and mesh the base face
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a soft sizing control.
Assign the previously defined ``base_face_size`` function to the soft sizing.
Create the base face.
Mesh the base face.
Display the base face.

.. GENERATED FROM PYTHON SOURCE LINES 210-241

.. code-block:: Python


    # Set up the necessary parameters for the generation of the base face.
    soft_size_control = model.control_data.create_size_control(prime.SizingType.SOFT)
    soft_size_params = prime.SoftSizingParams(model=model, max=base_face_size)
    soft_size_control.set_soft_sizing_params(soft_size_params)
    soft_size_scope = prime.ScopeDefinition(
        model, part_expression=part.name, entity_type=prime.ScopeEntity.FACEANDEDGEZONELETS
    )
    soft_size_control.set_scope(soft_size_scope)
    soft_size_control.set_suggested_name("b_f_size")

    # Create the base face, appending the the stacker mesh parameters.
    createbase_results = sweeper.create_base_face(
        part_id=model.get_part_by_name(part.name).id,
        topo_volume_ids=model.get_part_by_name(part.name).get_topo_volumes(),
        params=stacker_params,
    )
    base_faces = createbase_results.base_face_ids
    model.get_part_by_name(part.name).add_labels_on_topo_entities(["base_faces"], base_faces)
    scope = prime.ScopeDefinition(model=model, label_expression="base_faces")
    base_scope = prime.lucid.SurfaceScope(
        entity_expression="base_faces",
        part_expression=part.name,
        scope_evaluation_type=prime.ScopeEvaluationType.LABELS,
    )

    # Generate the quad-dominant surface mesh on the base face.
    mesh_util_controls = mesh_util.surface_mesh_with_size_controls(
        size_control_names="b_f_size", scope=base_scope, generate_quads=True
    )








.. GENERATED FROM PYTHON SOURCE LINES 242-244

Display the meshed base face in a PyVista window
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 244-250

.. code-block:: Python


    if display_intermediate_steps:
        display = PrimePlotter()
        display.plot(model, update=True)
        display.show()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_002.png
        :alt: 09 multi layer quad mesh pcb
        :srcset: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_002.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_09_multi_layer_quad_mesh_pcb_002.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 251-257

Stack the base face using the volume sweeper
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the volume sweeper to stack the base face along the previously defined sweep
direction.
Include the previously defined stacker parameters.
Display the final volume mesh.

.. GENERATED FROM PYTHON SOURCE LINES 257-266

.. code-block:: Python


    # Use the ``stack_base_face`` function to generate the volume mesh
    stackbase_results = sweeper.stack_base_face(
        part_id=model.get_part_by_name(part.name).id,
        base_face_ids=base_faces,
        topo_volume_ids=model.get_part_by_name(part.name).get_topo_volumes(),
        params=stacker_params,
    )








.. GENERATED FROM PYTHON SOURCE LINES 267-269

Display the final PCB mesh in a PyVista window
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 269-274

.. code-block:: Python


    if display_intermediate_steps:
        display = PrimePlotter()
        display.plot(model, update=True)
        display.show()







.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_003.png
        :alt: 09 multi layer quad mesh pcb
        :srcset: /examples/gallery_examples/gallery/images/sphx_glr_09_multi_layer_quad_mesh_pcb_003.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_09_multi_layer_quad_mesh_pcb_003.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 275-281

Set up the zone naming before the mesh output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Delete the unnecessary topo entities.
Name the walls of ``solid`` as ``wall_solid``. For example, if the solid's name is ``A``, then
name the walls surrounding the solid ``wall_A``).
Convert the labels to mesh zones.

.. GENERATED FROM PYTHON SOURCE LINES 281-298

.. code-block:: Python


    # Define deletion parameters
    deletion_params = prime.DeleteTopoEntitiesParams(
        model, delete_geom_zonelets=True, delete_mesh_zonelets=False
    )
    # Delete unnecessary geometrical entities.
    part.delete_topo_entities(deletion_params)
    # Rename the walls surrounding any volume of the mesh by appending the string
    # ``wall_`` to the solid's name. For example, if the solid is named ``my_solid``, then
    # name the walls surrounding the solid ``wall_my_solid``.
    for volume in part.get_volumes():
        volume_zone_name = "wall_" + model.get_zone_name(part.get_volume_zone_of_volume(volume))
        label_zonelets = part.get_face_zonelets_of_volumes([volume])
        part.add_labels_on_zonelets([volume_zone_name], label_zonelets)
    # Convert labels into mesh zones to use in the solver.
    mesh_util_create_zones = mesh_util.create_zones_from_labels()








.. GENERATED FROM PYTHON SOURCE LINES 299-302

Mesh output
~~~~~~~~~~~
Create a temporary folder and use it to output the mesh to a CAS file.

.. GENERATED FROM PYTHON SOURCE LINES 302-311

.. code-block:: Python


    with tempfile.TemporaryDirectory() as temp_folder:
        mesh_file = os.path.join(temp_folder, 'multi_layer_quad_mesh_pcb.cas')
        mesh_util.write(mesh_file)
        assert os.path.exists(mesh_file)
        print("\nExported file:\n", mesh_file)
    # Otherwise, specify a path on your local machine:
    # mesh_util.write('local/path/to/your/mesh_file.cas')





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

 .. code-block:: none


    Exported file:
     /tmp/tmpzk9m7s2o/multi_layer_quad_mesh_pcb.cas




.. GENERATED FROM PYTHON SOURCE LINES 312-314

Exit PyPrimeMesh
~~~~~~~~~~~~~~~~

.. GENERATED FROM PYTHON SOURCE LINES 314-316

.. code-block:: Python


    prime_client.exit()








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

   **Total running time of the script:** (1 minutes 54.746 seconds)


.. _sphx_glr_download_examples_gallery_examples_gallery_09_multi_layer_quad_mesh_pcb.py:

.. only:: html

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

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

      :download:`Download Jupyter notebook: 09_multi_layer_quad_mesh_pcb.ipynb <09_multi_layer_quad_mesh_pcb.ipynb>`

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

      :download:`Download Python source code: 09_multi_layer_quad_mesh_pcb.py <09_multi_layer_quad_mesh_pcb.py>`

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

      :download:`Download zipped: 09_multi_layer_quad_mesh_pcb.zip <09_multi_layer_quad_mesh_pcb.zip>`


.. only:: html

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

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