pythonmeshpyvistaansyspyansys

How to create shared topology using PyAnsys and PyVista


I have created two cylindrical meshes using PyVista with the goal of performing a modal analysis using PyAnsys on both the inner cylinder (shown in blue) and the outer cylinder (shown in grey). Where each of these cylinders have differing material properties and form part of a single model:

Outer Cylinder enter image description here

Inner Cylinder enter image description here

Mesh generation script:

import numpy as np
import pyvista as pv

def create_mesh(inner_radius, thickness, height, z_res, c_res, r_res_pipe, r_res_fluid):

    # Create a pipe mesh using a structured grid using the specified mesh density:
    outer_radius = inner_radius + thickness

    # Create a list of radial divisions between the inner and outer radii:
    if r_res_pipe % 2 != 0:
        r_res_pipe = r_res_pipe + 1 # radial resolution must be even to accommodate array reshaping

    radial_divisions = np.linspace(inner_radius, outer_radius, r_res_pipe)

    grid = pv.CylinderStructured(
        radius=radial_divisions, height=height, theta_resolution=c_res, z_resolution=z_res
    )

    grid.points = grid.points
    original_mesh = pv.UnstructuredGrid(grid)

    pipe_mesh = original_mesh
    points = pipe_mesh.points.reshape(z_res, c_res, r_res_pipe * 3)
    points[:, c_res - 1, :] = points[:, 0, :]
    pipe_mesh.points = points.reshape(z_res * (c_res) * 2, int(r_res_pipe + r_res_pipe / 2))

    pipe_mesh.plot(color='grey', show_edges=True)


    # Create a fluid mesh using a structured grid based on the pipe dimensions:
    # Create a list of radial divisions between the inner and outer radii:
    if r_res_fluid % 2 != 0:
        r_res_fluid = r_res_fluid + 1 # radial resolution must be even to accommodate array reshaping

    radial_divisions = np.linspace(0.0, inner_radius, r_res_fluid)

    grid = pv.CylinderStructured(
        radius=radial_divisions, height=height, theta_resolution=c_res, z_resolution=z_res
    )

    grid.points = grid.points
    original_mesh = pv.UnstructuredGrid(grid)

    fluid_mesh = original_mesh
    points = fluid_mesh.points.reshape(z_res, c_res, r_res_fluid * 3)
    points[:, c_res - 1, :] = points[:, 0, :]
    fluid_mesh.points = points.reshape(z_res * (c_res) * 2, int(r_res_fluid + r_res_fluid / 2))

    fluid_mesh.plot(color='blue', show_edges=True)

    return pipe_mesh, fluid_mesh

In order to do this, I need to share the topology between the grey and blue meshes. Is there an MAPDL command that can handle this?

I have looked through the documentation, but cannot find anything that can do this (however, my understanding of the library is not great and I might be missing something).

https://mapdldocs.pyansys.com/mapdl_commands/index.html


Solution

  • After considering the answer made by @user13974897, I have come up with the following solution to my question.

    Improvements to the initial method:

    It is unnecessary to make use of PyVista in this case, as PyAnsys is capable of handling cylindrical volumes. These cylindrical volumes can be created using the mapdl.cyl4() method, and can be meshed using the mapdl.vsweep() method.

    cyl4: https://mapdldocs.pyansys.com/mapdl_commands/prep7/_autosummary/ansys.mapdl.core.Mapdl.cyl4.html?highlight=cyl4#ansys.mapdl.core.Mapdl.cyl4

    vsweep: https://mapdldocs.pyansys.com/mapdl_commands/prep7/_autosummary/ansys.mapdl.core.Mapdl.vsweep.html?highlight=vsweep#ansys.mapdl.core.Mapdl.vsweep

    The method below can be applied to PyVista polydata. However, this is not advised as it requires the use of a rectangular mesh, which results in severe element distortion within the fluid column (requiring you to compensate by removing volume and adjusting the density to accommodate). This can likely be solved by using a tetrahedral mesh via TetGen, but has not been tested.

    TetGen: https://tetgen.pyvista.org/index.html

    Geometry creation, meshing and sharing of topology:

    Each mesh has to be assigned a numerical tag (to be referenced when assigning seperate material properties). These are named the pipe_tag and fluid_tag in the script below.

    Create the pipe geometry and mesh it:

    mapdl = ansys.mapdl.core.launch_mapdl(loglevel='WARNING', override=True)
    mapdl.units('SI')
    
    # Create pipe mesh (nodal tag = 1):
    pipe_tag = 1
    
    mapdl.clear()
    mapdl.prep7()
    mapdl.et(1, "SOLID186") 
    mapdl.mp('DENS', pipe_tag, pipe_density)
    mapdl.mp('NUXY', pipe_tag, pipe_poissons_ratio)
    mapdl.mp('EX', pipe_tag, pipe_elastic_modulus)
    
    mapdl.cyl4(xcenter=0, ycenter=0, rad1=inner_radius, rad2=outer_radius, depth=length)
    
    mapdl.cm('Pipe','VOLU')
    mapdl.esize(element_size)
    mapdl.mat(pipe_tag)  
    mapdl.vsweep('Pipe')
    

    Similary, create the geometry of the fluid column and mesh it:

    # Create fluid mesh (nodal tag = 2):
    fluid_tag = 2
    
    mapdl.et(2, "SOLID186") 
    mapdl.mp('DENS', fluid_tag, fluid_density)
    mapdl.mp('NUXY', fluid_tag, fluid_poissons_ratio)
    mapdl.mp('EX', fluid_tag, fluid_bulk_modulus)
    
    mapdl.cyl4(xcenter=0, ycenter=0, rad1=inner_radius, depth=length)
    
    mapdl.cm('Fluid','VOLU')
    mapdl.esize(element_size)
    mapdl.mat(fluid_tag)  
    mapdl.vsweep('Fluid')
    

    Lastly, create contact nodes between the two meshes using mapdl.nummrg(), setting the toler parameter. This tolerance dictates the range in which items (in this case, the nodes) are merged.

    nummrg: https://mapdldocs.pyansys.com/mapdl_commands/prep7/_autosummary/ansys.mapdl.core.Mapdl.nummrg.html?highlight=nummrg#ansys.mapdl.core.Mapdl.nummrg

    # Create contact nodes between the two meshes:
    mapdl.nummrg('node', 10e-6)
    

    I realize that this answer is most likely very long winded for such a small issue, but information regarding the above seems sparse enough to warrant such an explanation.