Skip to main content

A Python package to build, manipulate and analyze polygonal meshes.

Project description

PolyMesh - A Python Library for Compound Meshes with Jagged Topologies

Binder CircleCI Documentation Status License PyPI Python 3.7‒3.10 Code style: black

Warning PolyMesh is in the early stages of it's lifetime, and some concepts may change in the future. If you want long-term stability, wait until version 1.0, which is planned to be released if the core concepts all seem to sit and the documentation covers all major concepts.

The PolyMesh library aims to provide the tools to build and analyse meshes with complex topologies. Meshes can be built like a dictionary, using arbitarily nested layouts and then be translated to VTK or PyVista. For plotting, there is also support for K3D, Matplotlib and Plotly.

The data model is built around Awkward, which makes it possible to attach nested, variable-sized data to the points or the cells in a mesh, also providing interfaces to other popular libraries like Pandas or PyArrow. Implementations are fast as we rely on the vector math capabilities of NumPy, while other computationally sensitive calculations are JIT-compiled using Numba where necessary.

Here and there we also use NetworkX, SciPy, SymPy and scikit-learn.

Motivating example

from polymesh import PolyData, PointData, LineData
from polymesh.space import CartesianFrame
from polymesh.grid import Grid
from polymesh.cells import H8, TET4, L2
from polymesh.utils.topology import H8_to_TET4, H8_to_L2
from polymesh.utils.space import frames_of_lines
import numpy as np

size = 10, 10, 5
shape = 10, 10, 5
grid = Grid(size=size, shape=shape, eshape='H8')
grid.centralize()

coords = grid.coords()  # coordinates
topo = grid.topology()  # topology
centers = grid.centers()

b_left = centers[:, 0] < 0
b_right = centers[:, 0] >= 0
b_front = centers[:, 1] >= 0
b_back = centers[:, 1] < 0
iTET4 = np.where(b_left)[0]
iH8 = np.where(b_right & b_back)[0]
iL2 = np.where(b_right & b_front)[0]
_, tTET4 = H8_to_TET4(coords, topo[iTET4])
_, tL2 = H8_to_L2(coords, topo[iL2])
tH8 = topo[iH8]

# crate supporting pointcloud
frame = CartesianFrame(dim=3)
pd = PointData(coords=coords, frame=frame)
mesh = PolyData(pd, frame=frame)

# add tetrahedra
cdTET4 = TET4(topo=tTET4, frames=frame)
mesh['tetra'] = PolyData(cdTET4, frame=frame)

# add hexahedra
cdH8 = H8(topo=tH8, frames=frame)
mesh['hex'] = PolyData(cdH8, frame=frame)

# add lines
cdL2 = L2(topo=tL2, frames=frames_of_lines(coords, tL2))
mesh['line'] = LineData(cdL2, frame=frame)

# finalize the mesh and lock the layout
mesh.to_standard_form()
mesh.lock(create_mappers=True)

PolyMesh can also be used as a configuration tool for external plotting libraries:

# configure tetratedra
mesh['tetra'].config['A', 'color'] = 'green'

# configure hexahedra
mesh['hex'].config['A', 'color'] = 'blue'

# configure lines
mesh['line'].config['A', 'color'] = 'red'
mesh['line'].config['A', 'line_width'] = 3
mesh['line'].config['A', 'render_lines_as_tubes'] = True

# plot with PyVista
mesh.plot(notebook=True, jupyter_backend='static', config_key=('A'),
          show_edges=True, window_size=(600, 480))

Attaching data to the cells of the created blocks and plotting the results using PyVista:

scalars_TET4 = 100*np.random.rand(len(cdTET4))
cdTET4.db['scalars'] = scalars_TET4

scalars_H8 = 100*np.random.rand(len(cdH8))
cdH8.db['scalars'] = scalars_H8

scalars_L2 = 100*np.random.rand(len(cdL2))
cdL2.db['scalars'] = scalars_L2
mesh['line'].config['B', 'render_lines_as_tubes'] = True
mesh['line'].config['B', 'line_width'] = 3

mesh.plot(notebook=True, jupyter_backend='static', config_key=('B'), 
          cmap='plasma', show_edges=True, window_size=(600, 480), 
          scalars='scalars')

PolyMesh makes it easy to transfer data from the cells to the supporting point cloud:

# this 'pulls' data from the cells
scalars = mesh.pointdata.pull('scalars') 

Then we can plot the smoothed data:

mesh.plot(notebook=True, jupyter_backend='static', config_key=('A'),
          show_edges=True, window_size=(600, 480), scalars=scalars, 
          cmap='plasma')

Customizing the distribution mechanism

The smoothing procedure can be fine tuned using arbitrary weighting of cellular data. Define some scalar data on the cells and plot it using PyVista:

cdTET4.db['scalars'] = np.full(len(cdTET4), -100)
cdH8.db['scalars'] = np.full(len(cdH8), 100)
cdL2.db['scalars'] = np.full(len(cdL2), 0)

mesh.plot(notebook=True, jupyter_backend='static', config_key=('B'), 
          cmap='jet', show_edges=True, window_size=(600, 480), 
          scalars='scalars')

The default smoothing mechanism uses the volumes of the cells to determine nodal distribution factors.

scalars = mesh.pd.pull('scalars')

mesh.plot(notebook=True, jupyter_backend='static', config_key=('A'),
          show_edges=True, window_size=(600, 480), scalars=scalars, 
          cmap='jet')

If you want you can give more presence to the hexahedral cells by increasing their weights:

v = mesh.volumes()
idH8 = mesh['hex'].cd.id  # cell indices of hexahedra
v[idH8] *= 5  # 500% of original weight
ndf = mesh.nodal_distribution_factors(weights=v)
scalars = mesh.pd.pull('scalars', ndf=ndf)

mesh.plot(notebook=True, jupyter_backend='static', config_key=('A'),
          show_edges=True, window_size=(600, 480), scalars=scalars, 
          cmap='jet')

or by decreasing them:

v = mesh.volumes()
idH8 = mesh['hex'].cd.id  # cell indices of hexahedra
v[idH8] /= 5  # 20% of original weight
ndf = mesh.nodal_distribution_factors(weights=v)
scalars = mesh.pd.pull('scalars', ndf=ndf)

mesh.plot(notebook=True, jupyter_backend='static', config_key=('A'),
          show_edges=True, window_size=(600, 480), scalars=scalars, 
          cmap='jet')

It can be observed how the colors change arounf the boundary of hexahedral cells.

Point-related data alsobe plotted using the K3D library:

from k3d.colormaps import matplotlib_color_maps

cmap=matplotlib_color_maps.Jet
mesh.k3dplot(scalars=scalars, menu_visibility=False, cmap=cmap)

Documentation

The documentation is hosted on ReadTheDocs, where you can find more examples.

Installation

PolyMesh can be installed from PyPI using pip on Python >= 3.7:

>>> pip install polymesh

License

This package is licensed under the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polymesh-0.0.19.tar.gz (111.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polymesh-0.0.19-py3-none-any.whl (130.4 kB view details)

Uploaded Python 3

File details

Details for the file polymesh-0.0.19.tar.gz.

File metadata

  • Download URL: polymesh-0.0.19.tar.gz
  • Upload date:
  • Size: 111.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.11

File hashes

Hashes for polymesh-0.0.19.tar.gz
Algorithm Hash digest
SHA256 4ba0c3feba06cfacfad68f3d2d2dba12a59be9e8d2f1881267f376ba652e2f9a
MD5 9dcb94723b9eeebd08496f51c8479463
BLAKE2b-256 5438b70936f2a7db853af1c603a0e1d244c598700d3ba51fa8bff9dbe07be848

See more details on using hashes here.

File details

Details for the file polymesh-0.0.19-py3-none-any.whl.

File metadata

  • Download URL: polymesh-0.0.19-py3-none-any.whl
  • Upload date:
  • Size: 130.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.11

File hashes

Hashes for polymesh-0.0.19-py3-none-any.whl
Algorithm Hash digest
SHA256 3e7dd6484a818c7d2f587d210d99f9f68282e330621e4134f421dc37de51b15e
MD5 f4ef827c0a9a240fbc8cff542e856794
BLAKE2b-256 cca5d4500325fef44181807f0f81435035f7e78a887dcb2f94dc31433d601329

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page