Source code for spam.plotting.tetrahedraPlotter

"""
Library of SPAM functions for plotting a tetrahedral mesh
Copyright (C) 2020 SPAM Contributors

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from __future__ import print_function

import numpy
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from progressbar import ProgressBar
pbar = ProgressBar()

[docs] def plotDelaunay3D(points,connectivity,center_fraction,tet_strains,strain_range,axstr=1): """ Plots Delaunay triangulation with strains. Parameters ---------- points: Particles' x,y,z coordinates at original step in Np x 3 array. (Just used for plotting) connectivity: Delaunay triangulation generated by mesh_sandbox.voro_to_connectivity_3d center_fraction: Fraction of center of specimen to plot. tet_strains: List of strain tensors in each tetrahedron, from mesh_sandbox.voro_connectivity_to_strain_3d. strain_range: Upper and lower bounds for plotting strain. axstr: flag for the strain component to plot 1 = 'XX' component 2 = 'YY' component 3 = 'ZZ' component 4 = volumetric strain, XX+YY+ZZ 5 = equivalent strain, sqrt(2/3*e_{ij}^{dev}e_{ij}^{dev}) Returns ------- Nothing, just creates a plot right now Example ------- mesh_sandbox.voro_plot_connectivity_3d(points,connectivity,0.02,tet_sym,0.02,'Z') """ def voro_patch(ax, x, y, z, v, vmin=0, vmax=100, cmap_name='Greens'): cmap = mpl.cm.get_cmap(cmap_name) # Get colormap by name c = cmap(mpl.colors.Normalize(vmin, vmax)(v)) # Normalize value and get color pc = Poly3DCollection([list(zip(x,y,z))]) # Create PolyCollection from coords pc.set_facecolor(c) # Set facecolor to mapped value pc.set_edgecolor('None') # Set edgecolor to black ax.add_collection3d(pc) # Add PolyCollection to axes return pc def voro_view(ax, code): if code == 2: #view(2) sets the default two-dimensional view, az = 0, el = 90. ax.view_init(0, 0) # (args are reversed from MATLAB) # Find centroids within a central x-slice xmin = points[:,0].min() xmax = points[:,0].max() ymin = points[:,1].min() ymax = points[:,1].max() zmin = points[:,2].min() zmax = points[:,2].max() xspan = xmax - xmin idx = np.transpose(np.where((points[:,1]>(xmin+(0.5-center_fraction/2)*xspan)) & (points[:,1]<(xmin+(0.5+center_fraction/2)*xspan)))) # Now find all tetrahedra containing these centroids print("Finding tetrahedra to plot...\n") inconnectivity = np.isin(connectivity,idx) idxtetbool,_ = np.where(inconnectivity) idxtet = np.unique(idxtetbool) print("Getting all node positions of tetrahedra to plot...\n") combs = [[0,1,2],[1,2,3],[2,3,0],[0,1,3]] # All tetrahedra are now unique, but some faces may be plotted twice if # they belong to adjacent tetrahedra being plotted. Fix this... face_plot_ids = [] tet_str_plot = [] for ii in (range(len(idxtet))): if (axstr == 1): tmpstr = tet_strains[idxtet[ii]][0,0] if (axstr == 2): tmpstr = tet_strains[idxtet[ii]][1,1] if (axstr == 3): tmpstr = tet_strains[idxtet[ii]][2,2] if (axstr == 4): tmpstr = (tet_strains[idxtet[ii]][0,0]+tet_strains[idxtet[ii]][1,1]+ tet_strains[idxtet[ii]][2,2]) if (axstr == 5): devstr = tet_strains[idxtet[ii]] devstr = devstr - np.identity(3)*np.trace(devstr) tmpstr = np.sqrt(0.6666666*np.sum(np.tensordot(devstr,devstr,axes=1))) for jj in range(4): face_plot_ids.append(np.sort([connectivity[idxtet[ii]][combs[jj][0]],connectivity[idxtet[ii]][combs[jj][1]],connectivity[idxtet[ii]][combs[jj][2]]])) tet_str_plot.append(tmpstr) # Convert list to np array and remove non-unique rows face_plot_ids = np.array(face_plot_ids) face_plot_ids = np.sort(face_plot_ids,axis=1) y = np.ascontiguousarray(face_plot_ids).view(np.dtype((np.void, face_plot_ids.dtype.itemsize * face_plot_ids.shape[1]))) _, idx = np.unique(y, return_index=True) face_plot_ids_unique = face_plot_ids[idx] tet_str_plot = np.array(tet_str_plot) tet_str_plot = tet_str_plot[idx] # Now construct x,y,z,v to send to patch x = [] y = [] z = [] v = [] for ii in (range((face_plot_ids_unique.shape[0]))): tet_coms = points[face_plot_ids_unique[ii],:] x.append(tet_coms[:,0]) y.append(tet_coms[:,1]) z.append(tet_coms[:,2]) v.append(tet_str_plot[ii]) # Initialize figure as 3D projection #fig = plt.figure() ax = plt.axes(projection='3d') ax.set_xlim(xmin,xmax); ax.set_ylim(ymin,ymax); ax.set_zlim(zmin,zmax); # Scale v[ii] v = np.array(v)/strain_range for ii in range(v.shape[0]): if (v[ii]<-1): v[ii]=-1 if (v[ii]>1): v[ii]=1 v = (v+1)*50 ztmp = [] print("Plotting...\n") for ii in pbar(range(len(x))): ztmp.append(z[ii][0]) voro_patch(ax,x[ii],y[ii],z[ii],v[ii]) ax.view_init(elev=0.,azim=-90.) plt.axis('off') plt.show()