Source code for sfepy.mesh.mesh_tools

from sfepy.fem import Domain
import scipy.sparse as sps
import numpy as nm
from sfepy.base.compat import factorial
from sfepy.base.base import output
from numpy.core import intc
from numpy.linalg import lapack_lite

[docs]def elems_q2t(el): nel, nnd = el.shape if nnd > 4: q2t = nm.array([[0, 2, 3, 6], [0, 3, 7, 6], [0, 7, 4, 6], [0, 5, 6, 4], [1, 5, 6, 0], [1, 6, 2, 0]]) else: q2t = nm.array([[0, 1, 2], [0, 2, 3]]) ns, nn = q2t.shape nel *= ns out = nm.zeros((nel, nn), dtype=nm.int32); for ii in range(ns): idxs = nm.arange(ii, nel, ns) out[idxs,:] = el[:, q2t[ii,:]] return nm.ascontiguousarray(out)
[docs]def smooth_mesh(mesh, n_iter=4, lam=0.6307, mu=-0.6347, weights=None, bconstr=True, volume_corr=False): """ FE mesh smoothing. Based on: [1] Steven K. Boyd, Ralph Muller, Smooth surface meshing for automated finite element model generation from 3D image data, Journal of Biomechanics, Volume 39, Issue 7, 2006, Pages 1287-1295, ISSN 0021-9290, 10.1016/j.jbiomech.2005.03.006. (http://www.sciencedirect.com/science/article/pii/S0021929005001442) Parameters ---------- mesh : mesh FE mesh. n_iter : integer, optional Number of iteration steps. lam : float, optional Smoothing factor, see [1]. mu : float, optional Unshrinking factor, see [1]. weights : array, optional Edge weights, see [1]. bconstr: logical, optional Boundary constraints, if True only surface smoothing performed. volume_corr: logical, optional Correct volume after smoothing process. Returns ------- coors : array Coordinates of mesh nodes. """ def laplacian(coors, weights): n_nod = coors.shape[0] displ = (weights - sps.identity(n_nod)) * coors return displ def taubin(coors0, weights, lam, mu, n_iter): coors = coors0.copy() for ii in range(n_iter): displ = laplacian(coors, weights) if nm.mod(ii, 2) == 0: coors += lam * displ else: coors += mu * displ return coors def dets_fast(a): m = a.shape[0] n = a.shape[1] lapack_routine = lapack_lite.dgetrf pivots = nm.zeros((m, n), intc) flags = nm.arange(1, n + 1).reshape(1, -1) for i in xrange(m): tmp = a[i] lapack_routine(n, n, tmp, n, pivots[i], 0) sign = 1. - 2. * (nm.add.reduce(pivots != flags, axis=1) % 2) idx = nm.arange(n) d = a[:, idx, idx] absd = nm.absolute(d) sign *= nm.multiply.reduce(d / absd, axis=1) nm.log(absd, absd) logdet = nm.add.reduce(absd, axis=-1) return sign * nm.exp(logdet) def get_volume(el, nd): dim = nd.shape[1] nnd = el.shape[1] etype = '%d_%d' % (dim, nnd) if etype == '2_4' or etype == '3_8': el = elems_q2t(el) nel = el.shape[0] #bc = nm.zeros((dim, ), dtype=nm.double) mul = 1.0 / factorial(dim) if dim == 3: mul *= -1.0 mtx = nm.ones((nel, dim + 1, dim + 1), dtype=nm.double) mtx[:,:,:-1] = nd[el,:] vols = mul * dets_fast(mtx.copy()) # copy() ??? vol = vols.sum() bc = nm.dot(vols, mtx.sum(1)[:,:-1] / nnd) bc /= vol return vol, bc import time output('smoothing...') tt = time.clock() domain = Domain('mesh', mesh) n_nod = mesh.n_nod edges = domain.ed if weights is None: # initiate all vertices as inner - hierarchy = 2 node_group = nm.ones((n_nod,), dtype=nm.int16) * 2 # boundary vertices - set hierarchy = 4 if bconstr: # get "nodes of surface" if domain.fa: # 3D. fa = domain.fa else: fa = domain.ed flag = fa.mark_surface_facets() ii = nm.where( flag > 0 )[0] aux = nm.unique(fa.facets[ii]) if aux[0] == -1: # Triangular faces have -1 as 4. point. aux = aux[1:] node_group[aux] = 4 # generate costs matrix mtx_ed = edges.mtx.tocoo() _, idxs = nm.unique(mtx_ed.row, return_index=True) aux = edges.facets[mtx_ed.col[idxs]] fc1 = aux[:,0] fc2 = aux[:,1] idxs = nm.where(node_group[fc2] >= node_group[fc1]) rows1 = fc1[idxs] cols1 = fc2[idxs] idxs = nm.where(node_group[fc1] >= node_group[fc2]) rows2 = fc2[idxs] cols2 = fc1[idxs] crows = nm.concatenate((rows1, rows2)) ccols = nm.concatenate((cols1, cols2)) costs = sps.coo_matrix((nm.ones_like(crows), (crows, ccols)), shape=(n_nod, n_nod), dtype=nm.double) # generate weights matrix idxs = range(n_nod) aux = sps.coo_matrix((1.0 / nm.asarray(costs.sum(1)).squeeze(), (idxs, idxs)), shape=(n_nod, n_nod), dtype=nm.double) #aux.setdiag(1.0 / costs.sum(1)) weights = (aux.tocsc() * costs.tocsc()).tocsr() coors = taubin(mesh.coors, weights, lam, mu, n_iter) output('...done in %.2f s' % (time.clock() - tt)) if volume_corr: output('rescaling...') volume0, bc = get_volume(mesh.conns[0], mesh.coors) volume, _ = get_volume(mesh.conns[0], coors) scale = volume0 / volume output('scale factor: %.2f' % scale) coors = (coors - bc) * scale + bc output('...done in %.2f s' % (time.clock() - tt)) return coors