# -*- coding: utf-8 -*-
"""
“Mesh”模块包含了有限元网格的不同类型. See the following implementations: * MeshTri,三角剖分网格
* MeshTet, 四面体剖分网格
* MeshQuad, 矩形剖分网格
* MeshHex, 六面体剖分网格
"""
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
import numpy as np
import warnings
from scipy.sparse import coo_matrix import skfem.mapping
import skfem.element

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class Mesh():
"""A finite element mesh. This is an abstract superclass. See the following implementations: * MeshTri, triangular mesh
* MeshTet, tetrahedral mesh
* MeshQuad, quadrilateral mesh
* MeshHex, hexahedral mesh
""" refdom = "none"
brefdom = "none"
meshio_type = "none" p = np.array([])
t = np.array([])

1.1

    def __init__(self):
"""Check that p and t are C_CONTIGUOUS as this leads
to better performance."""
if self.p is not None:
if self.p.flags['F_CONTIGUOUS']:
if self.p.shape[1]>1000:
warnings.warn("Mesh.__init__(): Transforming " +
"over 100 vertices to C_CONTIGUOUS.")
self.p = np.ascontiguousarray(self.p)
if self.t is not None:
if self.t.flags['F_CONTIGUOUS']:
if self.t.shape[1]>1000:
warnings.warn("Mesh.__init__(): Transforming " +
"over 100 elements to C_CONTIGUOUS.")
self.t = np.ascontiguousarray(self.t)

1.2

    def __str__(self):
return self.__repr__()

1.3

    def __repr__(self):
return "Mesh of type '" + str(type(self)) + "' "\
"with " + str(self.p.shape) + " vertices " \
"and " + str(self.t.shape) + " elements."

1.4

    def show(self):
"""A wrapper包装纸 for matplotlib.pyplot.show()."""
plt.show()

1.5

    def dim(self):
"""Return the spatial空间的 dimension of the mesh."""
return int(self.p.shape[0])

1.6

    def mapping(self):
"""Default不履行 local-to-global mapping for the mesh."""
raise NotImplementedError("Default mapping not implemented!")

1.7

    def _uniform_refine(self):
"""Perform执行 a single uniform mesh refinement一致网格加密."""
raise NotImplementedError("Single refine not implemented " +
"for this mesh type!")

1.8

    def refine(self, N=None):
"""Refine the mesh. Parameters
----------
N : int (optional)
Perform N refinements.
"""
if N is None:
return self._uniform_refine()
else:
for itr in range(N):
self._uniform_refine()

1.9

    def remove_elements(self, element_indices):
"""Construct new mesh with elements removed
based on their indices. Parameters
----------
element_indices : numpy array
List of element indices to remove. Returns
-------
skfem.Mesh
A new mesh object with elements removed as per requested.
"""
keep = np.setdiff1d(np.arange(self.t.shape[1]), element_indices)
newt = self.t[:, keep]
ptix = np.unique(newt)
reverse = np.zeros(self.p.shape[1])
reverse[ptix] = np.arange(len(ptix))
newt = reverse[newt]
newp = self.p[:, ptix]
meshclass = type(self)
return meshclass(newp, newt.astype(np.intp))

1.10

    def scale(self, scale):
"""Scale the mesh. Parameters
----------
scale : float OR tuple of size dim
Scale each dimension by a factor. If a floating
point number is provided, same scale is used
for each dimension.
"""
for itr in range(int(self.dim())):
if isinstance(scale, tuple):
self.p[itr, :] *= scale[itr]
else:
self.p[itr, :] *= scale

1.11

    def translate(self, vec):
"""Translate the mesh. Parameters
----------
vec : tuple of size dim
Translate the mesh by a vector.
"""
for itr in range(int(self.dim())):
self.p[itr, :] += vec[itr]

1.12

    def _validate(self):
"""Perform mesh validity checks."""
# check that element connectivity contains integers
# NOTE: this is neccessary for some plotting functionality
if not np.issubdtype(self.t[0, 0], np.signedinteger):
msg = ("Mesh._validate(): Element connectivity "
"must consist of integers.")
raise Exception(msg)
# check that vertex matrix has "correct" size
if self.p.shape[0] > 3:
msg = ("Mesh._validate(): We do not allow meshes "
"embedded into larger than 3-dimensional "
"Euclidean space! Please check that "
"the given vertex matrix is of size Ndim x Nvertices.")
raise Exception(msg)
# check that element connectivity matrix has correct size
nvertices = {'line': 2, 'tri': 3, 'quad': 4, 'tet': 4, 'hex': 8}
if self.t.shape[0] != nvertices[self.refdom]:
msg = ("Mesh._validate(): The given connectivity "
"matrix has wrong shape!")
raise Exception(msg)
# check that there are no duplicate points
tmp = np.ascontiguousarray(self.p.T)
if self.p.shape[1] != np.unique(tmp.view([('', tmp.dtype)]
* tmp.shape[1])).shape[0]:
msg = "Mesh._validate(): Mesh contains duplicate vertices."
warnings.warn(msg)
# check that all points are at least in some element
if len(np.setdiff1d(np.arange(self.p.shape[1]), np.unique(self.t))):
msg = ("Mesh._validate(): Mesh contains a vertex "
"not belonging to any element.")
raise Exception(msg)

1.13

    def save(self, filename, pointData=None, cellData=None):
"""Export the mesh and fields using meshio. Parameters
----------
filename : string
The filename for vtk-file.
pointData : (optional) numpy array for one output or dict for multiple
cellData : (optional) numpy array for one output or dict for multiple
"""
import meshio if pointData is not None:
if type(pointData) != dict:
pointData = {'':pointData} if cellData is not None:
if type(cellData) != dict:
cellData = {'':cellData} cells = { self.meshio_type : self.t.T }
mesh = meshio.Mesh(self.p.T, cells, pointData, cellData)
meshio.write(filename, mesh)

1.14

    @classmethod
def load(cls, filename):
"""Load a mesh from file using meshio. Parameters
----------
filename : string
The filename for the mesh.
"""
import meshio
mesh = meshio.read(filename)
if issubclass(cls, Mesh2D):
return cls(mesh.points[:, :2].T, mesh.cells[cls.meshio_type].T)
else:
return cls(mesh.points.T, mesh.cells[cls.meshio_type].T)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

三维网格

class Mesh3D(Mesh):
"""Three dimensional meshes, common methods. See the following implementations: * MeshTet, tetrahedral mesh
* MeshHex, hexahedral mesh
"""

2.1

    def nodes_satisfying(self, test):
"""Return nodes that satisfy some condition. Parameters
----------
test : lambda function (3 params)
Evaluates to 1 or True for nodes belonging
to the output set.
"""
return np.nonzero(test(self.p[0, :], self.p[1, :], self.p[2, :]))[0]

2.2

    def facets_satisfying(self, test):
"""Return facets whose midpoints satisfy some condition. Parameters
----------
test : lambda functions (3 params)
Evaluates to 1 or True for facet midpoints
of the facets belonging to the output set.
"""
mx = np.sum(self.p[0, self.facets], axis=0)/self.facets.shape[0]
my = np.sum(self.p[1, self.facets], axis=0)/self.facets.shape[0]
mz = np.sum(self.p[2, self.facets], axis=0)/self.facets.shape[0]
return np.nonzero(test(mx, my, mz))[0]

2.3

    def edges_satisfying(self, test):
"""Return edges whose midpoints satisfy some condition. Parameters
----------
test : lambda functions (3 params)
Evaluates to 1 or True for edge midpoints
of the edges belonging to the output set.
"""
mx = 0.5*(self.p[0, self.edges[0, :]] + self.p[0, self.edges[1, :]])
my = 0.5*(self.p[1, self.edges[0, :]] + self.p[1, self.edges[1, :]])
mz = 0.5*(self.p[2, self.edges[0, :]] + self.p[2, self.edges[1, :]])
return np.nonzero(test(mx, my, mz))[0]

2.4

    def boundary_nodes(self):
"""Return an array of boundary node indices."""
return np.unique(self.facets[:, self.boundary_facets()])

2.5

    def boundary_facets(self):
"""Return an array of boundary facet indices."""
return np.nonzero(self.f2t[1, :] == -1)[0]

2.6

    def interior_facets(self):
"""Return an array of interior facet indices."""
return np.nonzero(self.f2t[1, :] >= 0)[0]

2.7

    def boundary_edges(self):
"""Return an array of boundary edge indices."""
bnodes = self.boundary_nodes()[:, None]
return np.nonzero(np.sum(self.edges[0, :] == bnodes, axis=0) *
np.sum(self.edges[1, :] == bnodes, axis=0))[0]

2.8

    def interior_nodes(self):
"""Return an array of interior node indices."""
return np.setdiff1d(np.arange(0, self.p.shape[1]), self.boundary_nodes())

2.9

    def draw_vertices(self):
"""Draw all vertices using mplot3d."""
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(self.p[0, :], self.p[1, :], self.p[2, :])
return fig

2.10

    def param(self):
"""Return (maximum) mesh parameter."""
return np.max(np.sqrt(np.sum((self.p[:, self.edges[0, :]] -
self.p[:, self.edges[1, :]])**2, axis=0)))

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

二维网格

class Mesh2D(Mesh):
"""Two dimensional meshes, common methods. See the following implementations: * MeshTri, triangular mesh
* MeshQuad, quadrilateral mesh
"""

3.1

    def jiggle(self, z=0.2):
"""Jiggle the interior nodes of the mesh. Parameters
----------
z : (optional, default=0.2) float
Mesh parameter is multiplied by this number. The resulting number
corresponds to the standard deviation of the jiggle.
"""
y = z*self.param()
I = self.interior_nodes()
self.p[0, I] = self.p[0, I] + y*np.random.rand(len(I))
self.p[1, I] = self.p[1, I] + y*np.random.rand(len(I))

3.2

    def boundary_nodes(self):
"""Return an array of boundary node indices."""
return np.unique(self.facets[:, self.boundary_facets()])

3.3

    def nodes_satisfying(self, test):
"""Return nodes that satisfy some condition. Parameters
----------
test : lambda
An anonymous function with two parameters (x and y) and which returns True for the set of nodes
that are to be included in the return set. Returns
-------
numpy array
An array of node indices.
"""
return np.nonzero(test(self.p[0, :], self.p[1, :]))[0]

3.4

    def draw_nodes(self, nodes, mark='bo'):
"""Highlight some nodes. Parameters
----------
nodes : numpy array
The indices of the nodes to highlight.
mark : (optional, default='bo') string
A standard matplotlib string to define the highlight style.
"""
plt.plot(self.p[0, nodes], self.p[1, nodes], mark)

3.5

    def param(self):
"""Return mesh parameter."""
return np.max(np.sqrt(np.sum((self.p[:, self.facets[0, :]] -
self.p[:, self.facets[1, :]])**2, axis=0)))

3.6

    def interior_nodes(self):
"""Return an array of interior node indices."""
return np.setdiff1d(np.arange(0, self.p.shape[1]), self.boundary_nodes())

3.7

    def facets_satisfying(self, test):
"""Return facets whose midpoints satisfy some condition. Parameters
----------
test : lambda function (2 params)
An anonymous function with two parameters (x and y) and which
returns True for the midpoints of the set of facets that are
to be included in the return set.
"""
mx = 0.5*(self.p[0, self.facets[0, :]] + self.p[0, self.facets[1, :]])
my = 0.5*(self.p[1, self.facets[0, :]] + self.p[1, self.facets[1, :]])
return np.nonzero(test(mx, my))[0]

3.8

    def elements_satisfying(self, test):
"""Return elements whose midpoints satisfy some condition. Parameters
----------
test : lambda function (2 params)
An anonymous function with two parameters (x and y) and which
returns True for the midpoints of the set of elements that
are to be included in the return set.
"""
mx = np.sum(self.p[0, self.t], axis=0)/self.t.shape[0]
my = np.sum(self.p[1, self.t], axis=0)/self.t.shape[0]
return np.nonzero(test(mx, my))[0]

3.9

    def interior_facets(self):
"""Return an array of interior facet indices."""
return np.nonzero(self.f2t[1, :] >= 0)[0]

3.10

    def boundary_facets(self):
"""Return an array of boundary facet indices."""
return np.nonzero(self.f2t[1, :] == -1)[0]

3.11

    def draw(self, ax=None, node_numbering=False, facet_numbering=False, element_numbering=False):
"""Draw the mesh. Parameters
----------
ax : (optional, default=None) matplotlib axis
Use a predefined axis for plotting.
node_numbering : (optional, default=False)
Draw node numbering.
facet_numbering: (optional, default=False)
Draw facet numbering.
element_numbering : (optional, default=False)
Draw element numbering.
"""
if ax is None:
# create new figure
fig = plt.figure()
ax = fig.add_subplot(111)
# visualize the mesh faster plotting is achieved through
# None insertion trick.
xs = []
ys = []
for s, t, u, v in zip(self.p[0, self.facets[0, :]],
self.p[1, self.facets[0, :]],
self.p[0, self.facets[1, :]],
self.p[1, self.facets[1, :]]):
xs.append(s)
xs.append(u)
xs.append(None)
ys.append(t)
ys.append(v)
ys.append(None)
ax.plot(xs, ys, 'k', linewidth='0.5') if node_numbering:
for itr in range(self.p.shape[1]):
ax.text(self.p[0, itr], self.p[1, itr], str(itr)) if facet_numbering:
mx = .5*(self.p[0, self.facets[0, :]] + self.p[0, self.facets[1, :]])
my = .5*(self.p[1, self.facets[0, :]] + self.p[1, self.facets[1, :]])
for itr in range(self.facets.shape[1]):
ax.text(mx[itr], my[itr], str(itr)) if element_numbering:
mx = np.sum(self.p[0, self.t], axis=0)/self.t.shape[0]
my = np.sum(self.p[1, self.t], axis=0)/self.t.shape[0]
for itr in range(self.t.shape[1]):
ax.text(mx[itr], my[itr], str(itr)) return ax

3.12

    def mirror_mesh(self, a, b, c):
"""Mirror a mesh by the line ax + by + c = 0. Parameters
----------
a : float
b : float
c : float
"""
tmp = -2.0*(a*self.p[0, :] + b*self.p[1, :] + c)/(a**2 + b**2)
newx = a*tmp + self.p[0, :]
newy = b*tmp + self.p[1, :]
newpoints = np.vstack((newx, newy))
points = np.hstack((self.p, newpoints))
tris = np.hstack((self.t, self.t + self.p.shape[1])) # remove duplicates
tmp = np.ascontiguousarray(points.T)
tmp, ixa, ixb = np.unique(tmp.view([('', tmp.dtype)]*tmp.shape[1]), return_index=True, return_inverse=True)
points = points[:, ixa]
tris = ixb[tris] meshclass = type(self) return meshclass(points, tris)

3.13

    def save(self, filename, pointData=None, cellData=None):
"""Export the mesh and fields using meshio. (2D version.) Parameters
----------
filename : string
The filename for vtk-file.
pointData : (optional) numpy array for one output or dict for multiple
cellData : (optional) numpy array for one output or dict for multiple
"""
import meshio # a row of zeros required in 2D
p = np.vstack((np.zeros(self.p.shape[1]), self.p)) if pointData is not None:
if type(pointData) != dict:
pointData = {'':pointData} if cellData is not None:
if type(cellData) != dict:
cellData = {'':cellData} cells = { self.meshio_type : self.t.T }
mesh = meshio.Mesh(p.T, cells, pointData, cellData)
meshio.write(filename, mesh)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class InterfaceMesh1D(Mesh):
"""An interface mesh for mortar methods."""

4.1

    def __init__(self, mesh1, mesh2, rule, param, debug_plot=False):
self.brefdom = mesh1.brefdom p1_ix = mesh1.nodes_satisfying(rule)
p2_ix = mesh2.nodes_satisfying(rule) p1 = mesh1.p[:, p1_ix]
p2 = mesh2.p[:, p2_ix]
_, ix = np.unique(np.concatenate((param(p1[0, :], p1[1, :]), param(p2[0, :], p2[1, :]))), return_index=True) np1 = mesh1.p.shape[1]
nt1 = mesh1.t.shape[1]
ixorig = np.concatenate((p1_ix, p2_ix + np1))[ix] self.p = np.hstack((mesh1.p, mesh2.p))
self.t = np.hstack((mesh1.t, mesh2.t + np1))
self.facets = np.array([ixorig[:-1], ixorig[1:]])
self.t2f = -1 + 0*np.hstack((mesh1.t2f, mesh2.t2f)) # construct normals
tangent_x = self.p[0, self.facets[0, :]] - self.p[0, self.facets[1, :]]
tangent_y = self.p[1, self.facets[0, :]] - self.p[1, self.facets[1, :]]
tangent_lengths = np.sqrt(tangent_x**2 + tangent_y**2) self.normals = np.array([-tangent_y/tangent_lengths, tangent_x/tangent_lengths]) if debug_plot:
ax = mesh1.draw()
mesh2.draw(ax=ax)
xs = np.array([self.p[0, self.facets[0, :]], self.p[0, self.facets[1, :]]])
midx = np.sum(xs, axis=0)/2.0
ys = np.array([self.p[1, self.facets[0, :]], self.p[1, self.facets[1, :]]])
midy = np.sum(ys, axis=0)/2.0
xs = 0.9*(xs - midx) + midx
ys = 0.9*(ys - midy) + midy
ax.plot(xs, ys, 'x-') # mappings from facets to the original triangles
# TODO vectorize
self.f2t = self.facets*0-1
for itr in range(self.facets.shape[1]):
mx = .5*(self.p[0, self.facets[0, itr]] + self.p[0, self.facets[1, itr]])
my = .5*(self.p[1, self.facets[0, itr]] + self.p[1, self.facets[1, itr]])
val = param(mx, my)
for jtr in mesh1.boundary_facets():
fix1 = mesh1.facets[0, jtr]
x1 = mesh1.p[0, fix1]
y1 = mesh1.p[1, fix1]
fix2 = mesh1.facets[1, jtr]
x2 = mesh1.p[0, fix2]
y2 = mesh1.p[1, fix2]
if rule(x1, y1) > 0 or rule(x2, y2) > 0:
if val > param(x1, y1) and val < param(x2, y2):
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
elif val < param(x1, y1) and val > param(x2, y2): # ye olde
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
elif val >= param(x1, y1) and val < param(x2, y2):
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
elif val > param(x1, y1) and val <= param(x2, y2):
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
elif val <= param(x1, y1) and val > param(x2, y2):
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
elif val < param(x1, y1) and val >= param(x2, y2):
# OK
self.f2t[0, itr] = mesh1.f2t[0, jtr]
break
for jtr in mesh2.boundary_facets():
fix1 = mesh2.facets[0, jtr]
x1 = mesh2.p[0, fix1]
y1 = mesh2.p[1, fix1]
fix2 = mesh2.facets[1, jtr]
x2 = mesh2.p[0, fix2]
y2 = mesh2.p[1, fix2]
if rule(x1, y1) > 0 or rule(x2, y2) > 0:
if val > param(x1, y1) and val < param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
elif val < param(x1, y1) and val > param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
elif val >= param(x1, y1) and val < param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
elif val > param(x1, y1) and val <= param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
elif val <= param(x1, y1) and val > param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
elif val < param(x1, y1) and val >= param(x2, y2):
# OK
self.f2t[1, itr] = mesh2.f2t[0, jtr] + nt1
break
if (self.f2t>-1).all():
self.f2t[0, :]
return
else:
print(self.f2t)
raise Exception("All mesh facets corresponding to mortar facets not found!")

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一维网格

class MeshLine(Mesh):
"""One-dimensional mesh.""" refdom = "line"
brefdom = "point" p = np.array([])
t = np.array([])

5.1

    def __init__(self, p=None, t=None, validate=True):
if p is None and t is None:
p = np.array([[0, 1]])
t = np.array([[0], [1]])
elif p is not None and t is None:
t = np.array([np.arange(np.max(p.shape)-1), np.arange(np.max(p.shape)-1)+1])
if len(p.shape)==1:
p = np.array([p])
self.p = p
self.t = t
if validate:
self._validate()
super(MeshLine, self).__init__()

5.2

    @classmethod
def init_refdom(cls):
"""Initialize a mesh constisting of the reference interval [0,1]."""
return cls()

5.3

    def adaptive_refine(self, marked):
"""Perform an adaptive refine which splits each marked element into two."""
t = self.t
p = self.p mid = range(len(marked)) + np.max(t) + 1 nonmarked = np.setdiff1d(np.arange(t.shape[1]), marked) newp = np.hstack((p, 0.5*(p[:, self.t[0, marked]] + p[:, self.t[1, marked]])))
newt = np.vstack((t[0, marked], mid))
newt = np.hstack((t[:, nonmarked], newt, np.vstack((mid, t[1, marked]))))
# update fields
self.p = newp
self.t = newt

5.4

    def _uniform_refine(self):
"""Perform a single mesh refine that halves 'h'."""
# rename variables
t = self.t
p = self.p mid = range(self.t.shape[1]) + np.max(t) + 1
# new vertices and elements
newp = np.hstack((p, 0.5*(p[:, self.t[0, :]] + p[:, self.t[1, :]])))
newt = np.vstack((t[0, :], mid))
newt = np.hstack((newt, np.vstack((mid, t[1, :]))))
# update fields
self.p = newp
self.t = newt

5.5

        # TODO implement prolongation

    def boundary_nodes(self):
"""Find the boundary nodes of the mesh."""
_, counts = np.unique(self.t.flatten(), return_counts=True)
return np.nonzero(counts == 1)[0]

5.6

    def interior_nodes(self):
"""Find the interior nodes of the mesh."""
_, counts = np.unique(self.t.flatten(), return_counts=True)
return np.nonzero(counts == 2)[0]

5.7

    def plot(self, u, ax=None, color='ko-'):
"""Plot a function defined at the nodes of the mesh."""
if ax is None:
# create new figure
fig = plt.figure()
ax = fig.add_subplot(111)
xs = []
ys = []
for y1, y2, s, t in zip(u[self.t[0, :]],
u[self.t[1, :]],
self.p[0, self.t[0, :]],
self.p[0, self.t[1, :]]):
xs.append(s)
xs.append(t)
xs.append(None)
ys.append(y1)
ys.append(y2)
ys.append(None)
ax.plot(xs, ys, color) return ax

5.8

    def __mul__(self, other):
"""Tensor product mesh."""
return MeshQuad.init_tensor(self.p[0, :], other.p[0, :])

5.9

    def param(self):
return np.max(np.abs(self.p[0, self.t[1, :]] - self.p[0, self.t[0, :]]))

5.10

    def mapping(self):
return skfem.mapping.MappingAffine(self)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

矩形剖分

class MeshQuad(Mesh2D):
"""A mesh consisting of quadrilateral elements. Attributes
----------
p : numpy array of size 2 x Nvertices
The vertices of the mesh
t : numpy array of size 4 x Nelements
The element connectivity
facets : numpy array of size 2 x Nfacets
Each column contains a pair of indices to p.
f2t : numpy array of size 2 x Nfacets
Each column contains a pair of indices to t
or -1 on the second row if the facet is on
the boundary.
t2f : numpy array of size 4 x Nelements
Each column contains four indices to facets.
""" refdom = "quad"
brefdom = "line"
meshio_type = "quad" p = np.array([])
t = np.array([])
facets = np.array([])
f2t = np.array([])
t2f = np.array([])

6.1

    def __init__(self, p=None, t=None, validate=True):
"""Initialize a quadrilateral mesh. Parameters
----------
p : (optional) numpy array of size 2 x Nvertices
The points of the mesh.
t : (optional) numpy array of size 4 x Nelements
The element connectivity, i.e. indices to p.
These should be in counter-clockwise order.
"""
if p is None and t is None:
p = np.array([[0., 0.], [1., 0.], [1., 1.], [0., 1.]]).T
t = np.array([[0, 1, 2, 3]]).T
elif p is None or t is None:
raise Exception("Must provide p AND t or neither")
self.p = p
self.t = t
if validate:
self._validate()
self._build_mappings()
super(MeshQuad, self).__init__()

6.2

    @classmethod
def init_tensor(cls, x, y):
"""Initialize a tensor product mesh. Parameters
----------
x : numpy array (1d)
The nodal coordinates in dimension x
y : numpy array (1d)
The nodal coordinates in dimension y
"""
npx = len(x)
npy = len(y)
X, Y = np.meshgrid(np.sort(x), np.sort(y))
p = np.vstack((X.flatten('F'), Y.flatten('F')))
ix = np.arange(npx*npy)
ne = (npx-1)*(npy-1)
t = np.zeros((4, ne))
ix = ix.reshape(npy, npx, order='F').copy()
t[0, :] = ix[0:(npy-1), 0:(npx-1)].reshape(ne, 1, order='F').copy().flatten()
t[1, :] = ix[1:npy, 0:(npx-1)].reshape(ne, 1, order='F').copy().flatten()
t[2, :] = ix[1:npy, 1:npx].reshape(ne, 1, order='F').copy().flatten()
t[3, :] = ix[0:(npy-1), 1:npx].reshape(ne, 1, order='F').copy().flatten()
return cls(p, t.astype(np.int64))

6.3

    @classmethod
def init_refdom(cls):
"""Initialize a mesh that includes only the reference quad. The mesh topology is as follows:
(-1,1) *-------------* (1,1)
| |
| |
| |
| |
| |
| |
| |
(-1,-1) *-------------* (1,-1)
"""
p = np.array([[-1., -1.], [1., -1.], [1., 1.], [-1., 1.]]).T
t = np.array([[0, 1, 2, 3]]).T
return cls(p, t)

6.4

    def _build_mappings(self):
# do not sort since order defines counterclockwise order
# self.t=np.sort(self.t,axis=0) # define facets: in the order (0,1) (1,2) (2,3) (0,3)
self.facets = np.sort(np.vstack((self.t[0, :], self.t[1, :])), axis=0)
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[1, :],
self.t[2, :])), axis=0)))
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[2, :],
self.t[3, :])), axis=0)))
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[0, :],
self.t[3, :])), axis=0))) # get unique facets and build quad-to-facet mapping: 4 (edges) x Nquads
tmp = np.ascontiguousarray(self.facets.T)
tmp, ixa, ixb = np.unique(tmp.view([('', tmp.dtype)]*tmp.shape[1]),
return_index=True, return_inverse=True)
self.facets = self.facets[:, ixa]
self.t2f = ixb.reshape((4, self.t.shape[1])) # build facet-to-quadrilateral mapping: 2 (quads) x Nedges
e_tmp = np.hstack((self.t2f[0, :],
self.t2f[1, :],
self.t2f[2, :],
self.t2f[3, :]))
t_tmp = np.tile(np.arange(self.t.shape[1]), (1, 4))[0] e_first, ix_first = np.unique(e_tmp, return_index=True)
# this emulates matlab unique(e_tmp,'last')
e_last, ix_last = np.unique(e_tmp[::-1], return_index=True)
ix_last = e_tmp.shape[0] - ix_last - 1 self.f2t = np.zeros((2, self.facets.shape[1]), dtype=np.int64)
self.f2t[0, e_first] = t_tmp[ix_first]
self.f2t[1, e_last] = t_tmp[ix_last] # second row to -1 if repeated (i.e., on boundary)
self.f2t[1, np.nonzero(self.f2t[0, :] == self.f2t[1, :])[0]] = -1

6.5

    def _uniform_refine(self):
"""Perform a single mesh refine that halves 'h'. Each quadrilateral is split into four.
"""
# rename variables
t = self.t
p = self.p
e = self.facets
sz = p.shape[1]
t2f = self.t2f + sz
# quadrilateral middle point
mid = range(self.t.shape[1]) + np.max(t2f) + 1
# new vertices are the midpoints of edges ...
newp1 = 0.5*np.vstack((p[0, e[0, :]] + p[0, e[1, :]],
p[1, e[0, :]] + p[1, e[1, :]]))
# ... and element middle points
newp2 = 0.25*np.vstack((p[0, t[0, :]] + p[0, t[1, :]] +
p[0, t[2, :]] + p[0, t[3, :]],
p[1, t[0, :]] + p[1, t[1, :]] +
p[1, t[2, :]] + p[1, t[3, :]]))
newp = np.hstack((p, newp1, newp2))
# build new quadrilateral definitions
newt = np.vstack((t[0, :],
t2f[0, :],
mid,
t2f[3, :]))
newt = np.hstack((newt, np.vstack((t2f[0, :],
t[1, :],
t2f[1, :],
mid))))
newt = np.hstack((newt, np.vstack((mid,
t2f[1, :],
t[2, :],
t2f[2, :]))))
newt = np.hstack((newt, np.vstack((t2f[3, :],
mid,
t2f[2, :],
t[3, :]))))
# update fields
self.p = newp
self.t = newt self._build_mappings()

6.6

        # TODO implement prolongation

    def _splitquads(self, x=None):
"""Split each quad into two triangles and return MeshTri."""
t = self.t[[0, 1, 3], :]
t = np.hstack((t, self.t[[1, 2, 3]])) if x is not None:
if len(x) == self.t.shape[1]:
# preserve elemental constant functions
X = np.concatenate((x, x))
else:
raise Exception("The parameter x must have one value per element.")
return MeshTri(self.p, t, validate=False), X
else:
return MeshTri(self.p, t, validate=False)

6.7

    def _splitquads_symmetric(self):
"""Split quads into four triangles."""
t = np.vstack((self.t, np.arange(self.t.shape[1]) + self.p.shape[1]))
newt = t[[0, 1, 4], :]
newt = np.hstack((newt, t[[1, 2, 4], :]))
newt = np.hstack((newt, t[[2, 3, 4], :]))
newt = np.hstack((newt, t[[3, 0, 4], :]))
mx = np.sum(self.p[0, self.t], axis=0)/self.t.shape[0]
my = np.sum(self.p[1, self.t], axis=0)/self.t.shape[0]
return MeshTri(np.hstack((self.p, np.vstack((mx, my)))), newt, validate=False)

6.8

    def plot(self, z, smooth=False, edgecolors=None, ax=None, zlim=None):
"""Visualize nodal or elemental function (2d). The quadrilateral mesh is split into triangular mesh (MeshTri) and
the respective plotting function for the triangular mesh is used.
"""
m, z = self._splitquads(z)
return m.plot(z, smooth, ax=ax, zlim=zlim, edgecolors=edgecolors)

6.9

    def plot3(self, z, smooth=False, ax=None):
"""Visualize nodal function (3d i.e. three axes). The quadrilateral mesh is split into triangular mesh (MeshTri) and
the respective plotting function for the triangular mesh is used.
"""
m, z = self._splitquads(z)
return m.plot3(z, smooth, ax=ax)

6.10

    def mapping(self):
return skfem.mapping.MappingIsoparametric(self, skfem.element.ElementQ1())

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

六面体剖分

class MeshHex(Mesh3D):
"""A mesh consisting of hexahedral elements. Attributes
----------
p : numpy array of size 3 x Nvertices
The vertices of the mesh. Each column corresponds to a point.
t : numpy array of size 8 x Nelements
The element connectivity. Each column corresponds to a element
and contains eight column indices to MeshHex.p.
facets : numpy array of size 4 x Nfacets
Each column contains four column indices to MeshHex.p.
f2t : numpy array of size 2 x Nfacets
Each column contains a pair of column indices to MeshHex.t
or -1 on the second row if the corresponding
facet is located on the boundary.
t2f : numpy array of size 6 x Nelements
Each column contains four indices to MeshHex.facets.
edges : numpy array of size 2 x Nedges
Each column corresponds to an edge and contains two indices to
MeshHex.p.
t2e : numpy array of size 12 x Nelements
Each column contains twelve column indices of MeshHex.edges.
""" refdom = "hex"
brefdom = "quad"
meshio_type = "hexahedron"

7.1

    def __init__(self, p=None, t=None, validate=True):
if p is None and t is None:
p = np.array([[0., 0., 0.], [0., 0., 1.], [0., 1., 0.], [1., 0., 0.],
[0., 1., 1.], [1., 0., 1.], [1., 1., 0.], [1., 1., 1.]]).T
t = np.array([[0, 1, 2, 3, 4, 5, 6, 7]]).T
elif p is None or t is None:
raise Exception("Must provide p AND t or neither")
#
# TODO fix orientation if p and t is provided. refer to
# the default mesh for correct orientation
#
# 2---6
# / /|
# 4---7 3
# | |/
# 1---5
#
# The hidden node is 0.
#
self.p = p
self.t = t
if validate:
self._validate()
self._build_mappings()
super(MeshHex, self).__init__()

7.2

    @classmethod
def init_tensor(cls, x, y, z):
"""Initialize a tensor product mesh. Parameters
----------
x : numpy array (1d)
The nodal coordinates in dimension x
y : numpy array (1d)
The nodal coordinates in dimension y
z : numpy array (1d)
The nodal coordinates in dimension z
"""
npx = len(x)
npy = len(y)
npz = len(z)
X, Y, Z = np.meshgrid(np.sort(x), np.sort(y), np.sort(z))
p = np.vstack((X.flatten('F'), Y.flatten('F'), Z.flatten('F')))
ix = np.arange(npx*npy*npz)
ne = (npx-1)*(npy-1)*(npz-1)
t = np.zeros((8, ne))
ix = ix.reshape(npy, npx, npz, order='F').copy()
t[0, :] = ix[0:(npy-1), 0:(npx-1), 0:(npz-1)].reshape(ne, 1, order='F').copy().flatten()
t[1, :] = ix[1:npy, 0:(npx-1), 0:(npz-1)].reshape(ne, 1, order='F').copy().flatten()
t[2, :] = ix[0:(npy-1), 1:npx, 0:(npz-1)].reshape(ne, 1, order='F').copy().flatten()
t[3, :] = ix[0:(npy-1), 0:(npx-1), 1:npz].reshape(ne, 1, order='F').copy().flatten()
t[4, :] = ix[1:npy, 1:npx, 0:(npz-1)].reshape(ne, 1, order='F').copy().flatten()
t[5, :] = ix[1:npy, 0:(npx-1), 1:npz].reshape(ne, 1, order='F').copy().flatten()
t[6, :] = ix[0:(npy-1), 1:npx, 1:npz].reshape(ne, 1, order='F').copy().flatten()
t[7, :] = ix[1:npy, 1:npx, 1:npz].reshape(ne, 1, order='F').copy().flatten()
return cls(p, t.astype(np.int64))

7.3

    def _build_mappings(self):
"""Build element-to-facet, element-to-edges, etc. mappings."""
self.edges = np.sort(np.vstack((self.t[0, :], self.t[1, :])), axis=0)
e = np.array([0, 2,
0, 3,
1, 4,
1, 5,
2, 4,
2, 6,
3, 5,
3, 6,
4, 7,
5, 7,
6, 7]) # see the picture in init
for i in range(11):
self.edges = np.hstack((self.edges, np.sort(np.vstack((self.t[e[2*i], :],
self.t[e[2*i+1], :])), axis=0))) # unique edges
self.edges, ixa, ixb = np.unique(self.edges, axis=1, return_index=True, return_inverse=True)
self.edges = np.ascontiguousarray(self.edges) self.t2e = ixb.reshape((12, self.t.shape[1])) # define facets
self.facets = np.sort(np.vstack((self.t[0, :],
self.t[1, :],
self.t[4, :],
self.t[2, :])), axis=0)
f = np.array([0, 3, 6, 2,
0, 1, 5, 3,
2, 6, 7, 4,
1, 5, 7, 4,
3, 5, 7, 6])
for i in range(5):
self.facets = np.hstack((self.facets, np.sort(np.vstack((self.t[f[4*i], :],
self.t[f[4*i+1], :],
self.t[f[4*i+2], :],
self.t[f[4*i+3], :])), axis=0))) # unique facets
self.facets, ixa, ixb = np.unique(self.facets, axis=1, return_index=True, return_inverse=True)
self.facets = np.ascontiguousarray(self.facets) self.t2f = ixb.reshape((6, self.t.shape[1])) # build facet-to-hexa mapping: 2 (hexes) x Nfacets
e_tmp = np.hstack((self.t2f[0, :], self.t2f[1, :],
self.t2f[2, :], self.t2f[3, :],
self.t2f[4, :], self.t2f[5, :]))
t_tmp = np.tile(np.arange(self.t.shape[1]), (1, 6))[0] e_first, ix_first = np.unique(e_tmp, return_index=True)
e_last, ix_last = np.unique(e_tmp[::-1], return_index=True)
ix_last = e_tmp.shape[0] - ix_last - 1 self.f2t = np.zeros((2, self.facets.shape[1]), dtype=np.int64)
self.f2t[0, e_first] = t_tmp[ix_first]
self.f2t[1, e_last] = t_tmp[ix_last] ## second row to zero if repeated (i.e., on boundary)
self.f2t[1, np.nonzero(self.f2t[0, :] == self.f2t[1, :])[0]] = -1

7.4

    def _uniform_refine(self):
"""Perform a single mesh refine that halves 'h'. Each hex is split into 8."""
# rename variables
t = self.t
p = self.p
e = self.edges
f = self.facets
sz = p.shape[1]
t2e = self.t2e + sz
t2f = self.t2f + np.max(t2e) + 1
# hex middle point
mid = range(self.t.shape[1]) + np.max(t2f) + 1
# new vertices are the midpoints of edges ...
newp1 = 0.5*np.vstack((p[0, e[0, :]] + p[0, e[1, :]],
p[1, e[0, :]] + p[1, e[1, :]],
p[2, e[0, :]] + p[2, e[1, :]]))
# ... midpoints of facets ...
newp2 = 0.25*np.vstack((p[0, f[0, :]] + p[0, f[1, :]] +
p[0, f[2, :]] + p[0, f[3, :]],
p[1, f[0, :]] + p[1, f[1, :]] +
p[1, f[2, :]] + p[1, f[3, :]],
p[2, f[0, :]] + p[2, f[1, :]] +
p[2, f[2, :]] + p[2, f[3, :]]))
# ... and element middle points
newp3 = 0.125*np.vstack((p[0, t[0, :]] + p[0, t[1, :]] +
p[0, t[2, :]] + p[0, t[3, :]] +
p[0, t[4, :]] + p[0, t[5, :]] +
p[0, t[6, :]] + p[0, t[7, :]],
p[1, t[0, :]] + p[1, t[1, :]] +
p[1, t[2, :]] + p[1, t[3, :]] +
p[1, t[4, :]] + p[1, t[5, :]] +
p[1, t[6, :]] + p[1, t[7, :]],
p[2, t[0, :]] + p[2, t[1, :]] +
p[2, t[2, :]] + p[2, t[3, :]] +
p[2, t[4, :]] + p[2, t[5, :]] +
p[2, t[6, :]] + p[2, t[7, :]]))
newp = np.hstack((p, newp1, newp2, newp3))
# build new hex indexing (this requires some serious meditation)
newt = np.vstack((t[0, :],
t2e[0, :],
t2e[1, :],
t2e[2, :],
t2f[0, :],
t2f[2, :],
t2f[1, :],
mid))
newt = np.hstack((newt, np.vstack((t2e[0, :],
t[1, :],
t2f[0, :],
t2f[2, :],
t2e[3, :],
t2e[4, :],
mid,
t2f[4, :]))))
newt = np.hstack((newt, np.vstack((t2e[1, :],
t2f[0, :],
t[2, :],
t2f[1, :],
t2e[5, :],
mid,
t2e[6, :],
t2f[3, :]
))))
newt = np.hstack((newt, np.vstack((t2e[2, :],
t2f[2, :],
t2f[1, :],
t[3, :],
mid,
t2e[7, :],
t2e[8, :],
t2f[5, :]
))))
newt = np.hstack((newt, np.vstack((t2f[0, :],
t2e[3, :],
t2e[5, :],
mid,
t[4, :],
t2f[4, :],
t2f[3, :],
t2e[9, :]
))))
newt = np.hstack((newt, np.vstack((t2f[2, :],
t2e[4, :],
mid,
t2e[7, :],
t2f[4, :],
t[5, :],
t2f[5, :],
t2e[10, :],
))))
newt = np.hstack((newt, np.vstack((t2f[1, :],
mid,
t2e[6, :],
t2e[8, :],
t2f[3, :],
t2f[5, :],
t[6, :],
t2e[11, :]
))))
newt = np.hstack((newt, np.vstack((mid,
t2f[4, :],
t2f[3, :],
t2f[5, :],
t2e[9, :],
t2e[10, :],
t2e[11, :],
t[7, :]
))))
# update fields
self.p = newp
self.t = newt self._build_mappings()

7.5

        # TODO implement prolongation

    def save(self, filename, pointData=None, cellData=None):
"""Export the mesh and fields using meshio. (Hexahedron version.) Parameters
----------
filename : string
The filename for vtk-file.
pointData : (optional) numpy array for one output or dict for multiple
cellData : (optional) numpy array for one output or dict for multiple
"""
import meshio # vtk requires a different ordering
t = self.t[[0, 3, 6, 2, 1, 5, 7, 4], :] if pointData is not None:
if type(pointData) != dict:
pointData = {'':pointData} if cellData is not None:
if type(cellData) != dict:
cellData = {'':cellData} cells = { 'hexahedron' : t.T }
mesh = meshio.Mesh(self.p.T, cells, pointData, cellData)
meshio.write(filename, mesh)

7.6

    def mapping(self):
return skfem.mapping.MappingIsoparametric(self, skfem.element.ElementHex1())

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

四边体剖分

class MeshTet(Mesh3D):
"""A mesh consisting of tetrahedral elements. Attributes
----------
p : numpy array of size 3 x Nvertices
The vertices of the mesh. Each column corresponds to a point.
t : numpy array of size 4 x Nelements
The element connectivity. Each column corresponds to a element
and contains four column indices to MeshTet.p.
facets : numpy array of size 3 x Nfacets
Each column contains a triplet of column indices to MeshTet.p.
Order: (0, 1, 2) (0, 1, 3) (0, 2, 3) (1, 2, 3)
f2t : numpy array of size 2 x Nfacets
Each column contains a pair of column indices to MeshTet.t
or -1 on the second row if the facet is located on the boundary.
t2f : numpy array of size 4 x Nelements
Each column contains four indices to MeshTet.facets.
edges : numpy array of size 2 x Nedges
Each column corresponds to an edge and contains two indices to
MeshTet.p.
Order: (0, 1) (1, 2) (0, 2) (0, 3) (1, 3) (2, 3)
t2e : numpy array of size 6 x Nelements
Each column contains six indices to MeshTet.edges. Examples
-------- Read a tetrahedral mesh from gmsh-format using meshio. >>> m = MeshTet.load('examples/box.msh')
>>> m.p.shape
(3, 358)
""" refdom = "tet"
brefdom = "tri"
meshio_type = "tetra"

8.1

    def __init__(self, p=None, t=None, validate=True):
if p is None and t is None:
p = np.array([[0., 0., 0.], [0., 0., 1.], [0., 1., 0.], [1., 0., 0.],
[0., 1., 1.], [1., 0., 1.], [1., 1., 0.], [1., 1., 1.]]).T
t = np.array([[0, 1, 2, 3], [3, 5, 1, 7], [2, 3, 6, 7],
[2, 3, 1, 7], [1, 2, 4, 7]]).T
elif p is None or t is None:
raise Exception("Must provide p AND t or neither")
self.p = p
self.t = t
if validate:
self._validate()
self.enable_facets = True
self._build_mappings()
super(MeshTet, self).__init__()

8.2

    def _build_mappings(self):
"""Build element-to-facet, element-to-edges, etc. mappings."""
# define edges: in the order (0,1) (1,2) (0,2) (0,3) (1,3) (2,3)
self.edges = np.sort(np.vstack((self.t[0, :], self.t[1, :])), axis=0)
e = np.array([1, 2,
0, 2,
0, 3,
1, 3,
2, 3])
for i in range(5):
self.edges = np.hstack((self.edges,
np.sort(np.vstack((self.t[e[2*i], :],
self.t[e[2*i+1], :])),
axis=0))) # unique edges
self.edges, ixa, ixb = np.unique(self.edges, axis=1, return_index=True, return_inverse=True)
self.edges = np.ascontiguousarray(self.edges) self.t2e = ixb.reshape((6, self.t.shape[1])) # define facets
if self.enable_facets:
self.facets = np.sort(np.vstack((self.t[0, :],
self.t[1, :],
self.t[2, :])), axis=0)
f = np.array([0, 1, 3,
0, 2, 3,
1, 2, 3])
for i in range(3):
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[f[2*i], :],
self.t[f[2*i+1], :],
self.t[f[2*i+2]])),
axis=0))) # unique facets
self.facets, ixa, ixb = np.unique(self.facets, axis=1, return_index=True, return_inverse=True)
self.facets = np.ascontiguousarray(self.facets) self.t2f = ixb.reshape((4, self.t.shape[1])) # build facet-to-tetra mapping: 2 (tets) x Nfacets
e_tmp = np.hstack((self.t2f[0, :], self.t2f[1, :],
self.t2f[2, :], self.t2f[3, :]))
t_tmp = np.tile(np.arange(self.t.shape[1]), (1, 4))[0] e_first, ix_first = np.unique(e_tmp, return_index=True)
# this emulates matlab unique(e_tmp,'last')
e_last, ix_last = np.unique(e_tmp[::-1], return_index=True)
ix_last = e_tmp.shape[0] - ix_last-1 self.f2t = np.zeros((2, self.facets.shape[1]), dtype=np.int64)
self.f2t[0, e_first] = t_tmp[ix_first]
self.f2t[1, e_last] = t_tmp[ix_last] # second row to zero if repeated (i.e., on boundary)
self.f2t[1, np.nonzero(self.f2t[0, :] == self.f2t[1, :])[0]] = -1

8.3

    def refine(self, N=None):
"""Refine the mesh, tetrahedral optimization. Parameters
----------
N : (optional) int
Perform N refinements.
"""
if N is None:
return self._uniform_refine()
else:
self.enable_facets = False
for itr in range(N-1):
self._uniform_refine()
self.enable_facets = True
self._uniform_refine()

8.4

    def _uniform_refine(self):
"""Perform a single mesh refine. Let the nodes of a tetrahedron be numbered as 0, 1, 2 and 3.
It is assumed that the edges in self.t2e are given in the order I=(0,1), II=(1,2), III=(0,2), IV=(0,3), V=(1,3), VI=(2,3) by self._build_mappings(). Let I denote the midpoint of the edge
(0,1), II denote the midpoint of the edge (1,2), etc. Then each
tetrahedron is split into eight smaller subtetrahedra as follows. The first four subtetrahedra have the following nodes: 1. (0,I,III,IV)
2. (1,I,II,V)
3. (2,II,III,VI)
4. (3,IV,V,VI) The remaining middle-portion of the original tetrahedron consists
of a union of two mirrored pyramids. This bi-pyramid can be splitted
into four tetrahedra in a three different ways by connecting the
midpoints of two opposing edges (there are three different pairs
of opposite edges). For each tetrahedra in the original mesh, we split the bi-pyramid
in such a way that the connection between the opposite edges
is shortest. This minimizes the shape-regularity constant of
the resulting mesh family.
"""
# rename variables
t = self.t
p = self.p
e = self.edges
sz = p.shape[1]
t2e = self.t2e + sz
# new vertices are the midpoints of edges
newp = 0.5*np.vstack((p[0, e[0, :]] + p[0, e[1, :]],
p[1, e[0, :]] + p[1, e[1, :]],
p[2, e[0, :]] + p[2, e[1, :]]))
newp = np.hstack((p, newp))
# new tets
newt = np.vstack((t[0, :], t2e[0, :], t2e[2, :], t2e[3, :]))
newt = np.hstack((newt, np.vstack((t[1, :], t2e[0, :], t2e[1, :], t2e[4, :]))))
newt = np.hstack((newt, np.vstack((t[2, :], t2e[1, :], t2e[2, :], t2e[5, :]))))
newt = np.hstack((newt, np.vstack((t[3, :], t2e[3, :], t2e[4, :], t2e[5, :]))))
# compute middle pyramid diagonal lengths and choose shortest
d1 = ((newp[0, t2e[2, :]] - newp[0, t2e[4, :]])**2 +
(newp[1, t2e[2, :]] - newp[1, t2e[4, :]])**2)
d2 = ((newp[0, t2e[1, :]] - newp[0, t2e[3, :]])**2 +
(newp[1, t2e[1, :]] - newp[1, t2e[3, :]])**2)
d3 = ((newp[0, t2e[0, :]] - newp[0, t2e[5, :]])**2 +
(newp[1, t2e[0, :]] - newp[1, t2e[5, :]])**2)
I1 = d1 < d2
I2 = d1 < d3
I3 = d2 < d3
c1 = I1*I2
c2 = (~I1)*I3
c3 = (~I2)*(~I3)
# splitting the pyramid in the middle.
# diagonals are [2,4], [1,3] and [0,5]
# CASE 1: diagonal [2,4]
newt = np.hstack((newt, np.vstack((t2e[2, c1], t2e[4, c1],
t2e[0, c1], t2e[1, c1]))))
newt = np.hstack((newt, np.vstack((t2e[2, c1], t2e[4, c1],
t2e[0, c1], t2e[3, c1]))))
newt = np.hstack((newt, np.vstack((t2e[2, c1], t2e[4, c1],
t2e[1, c1], t2e[5, c1]))))
newt = np.hstack((newt, np.vstack((t2e[2, c1], t2e[4, c1],
t2e[3, c1], t2e[5, c1]))))
# CASE 2: diagonal [1,3]
newt = np.hstack((newt, np.vstack((t2e[1, c2], t2e[3, c2],
t2e[0, c2], t2e[4, c2]))))
newt = np.hstack((newt, np.vstack((t2e[1, c2], t2e[3, c2],
t2e[4, c2], t2e[5, c2]))))
newt = np.hstack((newt, np.vstack((t2e[1, c2], t2e[3, c2],
t2e[5, c2], t2e[2, c2]))))
newt = np.hstack((newt, np.vstack((t2e[1, c2], t2e[3, c2],
t2e[2, c2], t2e[0, c2]))))
# CASE 3: diagonal [0,5]
newt = np.hstack((newt, np.vstack((t2e[0, c3], t2e[5, c3],
t2e[1, c3], t2e[4, c3]))))
newt = np.hstack((newt, np.vstack((t2e[0, c3], t2e[5, c3],
t2e[4, c3], t2e[3, c3]))))
newt = np.hstack((newt, np.vstack((t2e[0, c3], t2e[5, c3],
t2e[3, c3], t2e[2, c3]))))
newt = np.hstack((newt, np.vstack((t2e[0, c3], t2e[5, c3],
t2e[2, c3], t2e[1, c3]))))
# update fields
self.p = newp
self.t = newt self._build_mappings()

8.5

        # TODO implement prolongation matrix

    def shapereg(self):
"""Return the largest shape-regularity constant."""
def edgelen(n):
return np.sqrt(np.sum((self.p[:, self.edges[0, self.t2e[n, :]]] -
self.p[:, self.edges[1, self.t2e[n, :]]])**2,
axis=0))
edgelenmat = np.vstack(tuple(edgelen(i) for i in range(6)))
return np.max(np.max(edgelenmat, axis=0)/np.min(edgelenmat, axis=0))

8.6

    def mapping(self):
return skfem.mapping.MappingAffine(self)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

三角剖分

class MeshTri(Mesh2D):
"""A mesh consisting of triangular elements. Attributes
----------
p : numpy array of size 2 x Nvertices
The vertices of the mesh
t : numpy array of size 3 x Nelements
The element connectivity
facets : numpy array of size 2 x Nfacets
Each column contains a pair of indices to p.
f2t : numpy array of size 2 x Nfacets
Each column contains a pair of indices to t
or -1 on the second row if the facet is on
the boundary.
t2f : numpy array of size 3 x Nelements
Each column contains three indices to facets. Examples
-------- Initialize a symmetric mesh of the unit square. >>> m = MeshTri.init_sqsymmetric()
>>> m.t.shape
(3, 8) The different constructors are:
* load (requires meshio)
* init_symmetric
* init_sqsymmetric
* init_refdom Facets (edges) and mappings from triangles to facets and vice versa are
automatically constructed. In the following example we have 5 facets
(edges). >>> m = MeshTri()
>>> m.facets
array([[0, 0, 1, 1, 2],
[1, 2, 2, 3, 3]])
>>> m.t2f
array([[0, 2],
[2, 4],
[1, 3]])
>>> m.f2t
array([[ 0, 0, 1, 1, 1],
[-1, -1, 0, -1, -1]]) The value -1 implies that the facet (the edge) is on the boundary. Refine the triangular mesh of the unit square three times. >>> m = MeshTri()
>>> m.refine(3)
>>> m.p.shape
(2, 81)
""" refdom = "tri"
brefdom = "line"
meshio_type = "triangle" p = np.array([])
t = np.array([])
facets = np.array([])
f2t = np.array([])
t2f = np.array([])

9.1

    def __init__(self, p=None, t=None, validate=True, sort_t=True):
"""Initialize a triangular mesh. Parameters
----------
p : (optional) numpy array of size 2 x Nvertices
The points of the mesh.
t : (optional) numpy array of size 3 x Nelements
The element connectivity, i.e. indices to p.
validate : (optional, default=True) bool
Whether to run mesh validity checks or not.
sort_t : (optional, default=True) bool
Sort the element connectivity matrix before building mappings.
"""
if p is None and t is None:
p = np.array([[0., 1., 0., 1.], [0., 0., 1., 1.]], dtype=np.float_)
t = np.array([[0, 1, 2], [1, 3, 2]], dtype=np.intp).T
elif p is None or t is None:
raise Exception("Must provide p AND t or neither")
self.p = p
self.t = t
if validate:
self._validate()
self._build_mappings(sort_t=sort_t)
super(MeshTri, self).__init__()

9.2

    @classmethod
def init_tensor(cls, x, y):
"""Initialize a tensor product mesh. Parameters
----------
x : numpy array (1d)
The nodal coordinates in dimension x
y : numpy array (1d)
The nodal coordinates in dimension y
"""
return MeshQuad.init_tensor(x, y)._splitquads()

9.3

    @classmethod
def init_symmetric(cls):
"""Initialize a symmetric mesh of the unit square. The mesh topology is as follows:
*------------*
|\ /|
| \ / |
| \ / |
| * |
| / \ |
| / \ |
|/ \|
*------------*
"""
p = np.array([[0, 1, 1, 0, 0.5],
[0, 0, 1, 1, 0.5]], dtype=np.float_)
t = np.array([[0, 1, 4],
[1, 2, 4],
[2, 3, 4],
[0, 3, 4]], dtype=np.intp).T
return cls(p, t)

9.4

    @classmethod
def init_sqsymmetric(cls):
"""Initialize a symmetric mesh of the unit square. The mesh topology is as follows:
*------------*
|\ | /|
| \ | / |
| \| / |
|-----*------|
| /| \ |
| / | \ |
|/ | \|
*------------*
"""
p = np.array([[0, 0.5, 1, 0, 0.5, 1, 0, 0.5, 1],
[0, 0, 0, 0.5, 0.5, 0.5, 1, 1, 1]], dtype=np.float_)
t = np.array([[0, 1, 4],
[1, 2, 4],
[2, 4, 5],
[0, 3, 4],
[3, 4, 6],
[4, 6, 7],
[4, 7, 8],
[4, 5, 8]], dtype=np.intp).T
return cls(p, t)

9.5

    @classmethod
def init_refdom(cls):
"""Initialize a mesh that includes only the reference triangle. The mesh topology is as follows:
*
|\
| \
| \
| \
| \
| \
| \
*-------------*
"""
p = np.array([[0., 1., 0.],
[0., 0., 1.]], dtype=np.float_)
t = np.array([[0, 1, 2]], dtype=np.intp).T
return cls(p, t)

9.6

    def _build_mappings(self, sort_t=True):
# sort to preserve orientations etc.
if sort_t:
self.t = np.sort(self.t, axis=0) # define facets: in the order (0,1) (1,2) (0,2)
self.facets = np.sort(np.vstack((self.t[0, :], self.t[1, :])), axis=0)
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[1, :], self.t[2, :])),
axis=0)))
self.facets = np.hstack((self.facets,
np.sort(np.vstack((self.t[0, :], self.t[2, :])),
axis=0))) # get unique facets and build triangle-to-facet
# mapping: 3 (edges) x Ntris
tmp = np.ascontiguousarray(self.facets.T)
tmp, ixa, ixb = np.unique(tmp.view([('', tmp.dtype)] * tmp.shape[1]),
return_index=True, return_inverse=True)
self.facets = self.facets[:, ixa]
self.t2f = ixb.reshape((3, self.t.shape[1])) # build facet-to-triangle mapping: 2 (triangles) x Nedges
e_tmp = np.hstack((self.t2f[0, :], self.t2f[1, :], self.t2f[2, :]))
t_tmp = np.tile(np.arange(self.t.shape[1]), (1, 3))[0] e_first, ix_first = np.unique(e_tmp, return_index=True)
# this emulates matlab unique(e_tmp,'last')
e_last, ix_last = np.unique(e_tmp[::-1], return_index=True)
ix_last = e_tmp.shape[0] - ix_last - 1 self.f2t = np.zeros((2, self.facets.shape[1]), dtype=np.int64)
self.f2t[0, e_first] = t_tmp[ix_first]
self.f2t[1, e_last] = t_tmp[ix_last] # second row to zero if repeated (i.e., on boundary)
self.f2t[1, np.nonzero(self.f2t[0, :] == self.f2t[1, :])[0]] = -1

9.7

    def interpolator(self, x):
"""Return a function which interpolates values with P1 basis."""
triang = mtri.Triangulation(self.p[0, :], self.p[1, :], self.t.T)
interpf = mtri.LinearTriInterpolator(triang, x)
# contruct an interpolator handle
def handle(X, Y):
return interpf(X, Y).data
return handle

9.8

    def const_interpolator(self, x):
"""Return a function which interpolates values with P0 basis."""
triang = mtri.Triangulation(self.p[0, :], self.p[1, :], self.t.T)
finder = triang.get_trifinder()
# construct an interpolator handle
def handle(X, Y):
return x[finder(X, Y)]
return handle

9.9

    def smooth(self, k=1.0):
"""Apply smoothing to interior nodes."""
from skfem.assembly import InteriorBasis, asm
from skfem.element import ElementTriP1
from skfem.utils import solve
from skfem.models.poisson import laplace, mass e = ElementTriP1()
ib = InteriorBasis(self, e) K = asm(laplace, ib)
M = asm(mass, ib) I = self.interior_nodes()
dx = - k*solve(M, K.dot(self.p[0, :]))
dy = - k*solve(M, K.dot(self.p[1, :])) self.p[0, I] += dx[I]
self.p[1, I] += dy[I]

9.10

    def draw_debug(self):
"""Draw without mesh.facets. For debugging self.draw()."""
fig = plt.figure()
plt.hold('on')
for itr in range(self.t.shape[1]):
plt.plot(self.p[0,self.t[[0,1],itr]], self.p[1,self.t[[0,1],itr]], 'k-')
plt.plot(self.p[0,self.t[[1,2],itr]], self.p[1,self.t[[1,2],itr]], 'k-')
plt.plot(self.p[0,self.t[[0,2],itr]], self.p[1,self.t[[0,2],itr]], 'k-')
return fig

9.11

    def plot(self, z, smooth=False, ax=None, zlim=None, edgecolors=None):
"""Visualize nodal or elemental function (2d)."""
if ax is None:
fig = plt.figure()
ax = fig.add_subplot(111)
if edgecolors is None:
edgecolors = 'k'
if zlim == None:
if smooth:
ax.tripcolor(self.p[0, :], self.p[1, :], self.t.T, z,
shading='gouraud', edgecolors=edgecolors)
else:
ax.tripcolor(self.p[0, :], self.p[1, :], self.t.T, z, edgecolors=edgecolors)
else:
if smooth:
ax.tripcolor(self.p[0, :], self.p[1, :], self.t.T, z,
shading='gouraud', vmin=zlim[0], vmax=zlim[1], edgecolors=edgecolors)
else:
ax.tripcolor(self.p[0, :], self.p[1, :], self.t.T, z,
vmin=zlim[0], vmax=zlim[1], edgecolors=edgecolors)
return ax

9.12

    def plot3(self, z, smooth=False, ax=None):
"""Visualize nodal function (3d i.e. three axes)."""
from mpl_toolkits.mplot3d import Axes3D
if ax is None:
fig = plt.figure()
ax = Axes3D(fig)
if len(z) == self.p.shape[1]:
# use matplotlib
ts = mtri.Triangulation(self.p[0, :], self.p[1, :], self.t.T)
ax.plot_trisurf(self.p[0, :], self.p[1, :], z,
triangles=ts.triangles,
cmap=plt.cm.Spectral)
elif len(z) == self.t.shape[1]:
# one value per element (piecewise const)
nt = self.t.shape[1]
newt = np.arange(3*nt, dtype=np.int64).reshape((nt, 3))
newpx = self.p[0, self.t].flatten(order='F')
newpy = self.p[1, self.t].flatten(order='F')
newz = np.vstack((z, z, z)).flatten(order='F')
ts = mtri.Triangulation(newpx, newpx, newt)
ax.plot_trisurf(newpx, newpy, newz,
triangles=ts.triangles,
cmap=plt.cm.Spectral)
elif len(z) == 3*self.t.shape[1]:
# three values per element (piecewise linear)
nt = self.t.shape[1]
newt = np.arange(3*nt, dtype=np.int64).reshape((nt, 3))
newpx = self.p[0, self.t].flatten(order='F')
newpy = self.p[1, self.t].flatten(order='F')
ts = mtri.Triangulation(newpx, newpx, newt)
ax.plot_trisurf(newpx, newpy, z,
triangles=ts.triangles,
cmap=plt.cm.Spectral)
else:
raise NotImplementedError("MeshTri.plot3: not implemented for "
"the given shape of input vector!")
return ax

9.13

    def _uniform_refine(self):
"""Perform a single mesh refine."""
# rename variables
t = self.t
p = self.p
e = self.facets
sz = p.shape[1]
t2f = self.t2f + sz
# new vertices are the midpoints of edges
newp = 0.5*np.vstack((p[0, e[0, :]] + p[0, e[1, :]],
p[1, e[0, :]] + p[1, e[1, :]]))
newp = np.hstack((p, newp))
# build new triangle definitions
newt = np.vstack((t[0, :], t2f[0, :], t2f[2, :]))
newt = np.hstack((newt, np.vstack((t[1, :], t2f[0, :], t2f[1, :]))))
newt = np.hstack((newt, np.vstack((t[2, :], t2f[2, :], t2f[1, :]))))
newt = np.hstack((newt, np.vstack((t2f[0, :], t2f[1, :], t2f[2, :]))))
# update fields
self.p = newp
self.t = newt self._build_mappings() # prolongation matrix
nsz = newp.shape[1]
return coo_matrix(
(np.hstack((np.ones(sz), .5 * np.ones(2 * (nsz - sz)))),
(np.hstack((np.arange(sz), np.arange(nsz - sz) + sz, np.arange(nsz - sz) + sz)),
np.hstack((np.arange(sz), e[0, :], e[1, :])))),
shape=(nsz, sz)).tocsr()

9.14

    def _uniform_refine(self):
"""Perform a single mesh refine."""
# rename variables
t = self.t
p = self.p
e = self.facets
sz = p.shape[1]
t2f = self.t2f + sz
# new vertices are the midpoints of edges
newp = 0.5*np.vstack((p[0, e[0, :]] + p[0, e[1, :]],
p[1, e[0, :]] + p[1, e[1, :]]))
newp = np.hstack((p, newp))
# build new triangle definitions
newt = np.vstack((t[0, :], t2f[0, :], t2f[2, :]))
newt = np.hstack((newt, np.vstack((t[1, :], t2f[0, :], t2f[1, :]))))
newt = np.hstack((newt, np.vstack((t[2, :], t2f[2, :], t2f[1, :]))))
newt = np.hstack((newt, np.vstack((t2f[0, :], t2f[1, :], t2f[2, :]))))
# update fields
self.p = newp
self.t = newt self._build_mappings() # prolongation matrix
nsz = newp.shape[1]
return coo_matrix(
(np.hstack((np.ones(sz), .5 * np.ones(2 * (nsz - sz)))),
(np.hstack((np.arange(sz), np.arange(nsz - sz) + sz, np.arange(nsz - sz) + sz)),
np.hstack((np.arange(sz), e[0, :], e[1, :])))),
shape=(nsz, sz)).tocsr()

9.15

    def mapping(self):
return skfem.mapping.MappingAffine(self)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

if __name__ == "__main__":
import doctest
doctest.testmod()

scikit-FEM-mesh的更多相关文章

  1. EasyMesh - A Two-Dimensional Quality Mesh Generator

    EasyMesh - A Two-Dimensional Quality Mesh Generator eryar@163.com Abstract. EasyMesh is developed by ...

  2. 在Unity中使用UGUI修改Mesh绘制几何图形

    在商店看到这样一个例子,表示很有兴趣,他们说是用UGUI做的.我想,像这种可以随便变形的图形,我第一个就想到了网格变形. 做法1: 细心的朋友应该会发现,每个UGUI可见元素,都有一个‘Canvas ...

  3. Unity3D 导航网格自动寻路(Navigation Mesh)

    NavMesh(导航网格)是3D游戏世界中用于实现动态物体自动寻路的一种技术,将游戏中复杂的结构组织关系简化为带有一定信息的网格,在这些网格的基础上通过一系列的计算来实现自动寻路..导航时,只需要给导 ...

  4. Mesh Data Structure in OpenCascade

    Mesh Data Structure in OpenCascade eryar@163.com 摘要Abstract:本文对网格数据结构作简要介绍,并结合使用OpenCascade中的数据结构,将网 ...

  5. Mesh Algorithm in OpenCascade

    Mesh Algorithm in OpenCascade eryar@163.com Abstract. Rendering a generic surface is a two steps pro ...

  6. Unity里的Mesh属性

    ----------------------------------------------------------------------------------------------- Mesh ...

  7. 【Unity3D】利用Shader以及更改Mesh实现2D游戏的动态阴影效果

    最近看到一个非常有趣的益智小游戏,是一个盗贼进入房子偷东西的, 其实这种游戏市面上已经很多了,吸引我的是那个类似手电筒的效果, 主角走到哪里,光就到哪里,被挡住的地方还有阴影.有点类似策略游戏里的战争 ...

  8. Netgen mesh library : nglib

    Netgen mesh library : nglib eryar@163.com 摘要Abstract:本文主是对Netgen的库nglib的用法进行介绍.主要参考资料是Netgen用户指南.最后给 ...

  9. 为什么带网格(mesh)的模型添加了刚体Rigidbody和MeshCollider,还是会从地板穿过去?

    两个Gameobject 放置在空中, 一个是Cube,一个是茄子模型 Cube的Collider 是Box Collider , 茄汁的Collider 是mesh collider, 他们都添加了 ...

  10. Unity3d 制作动态Mesh且可以随地面凹凸起伏

    适用情景:主角带着光环,光环用一张贴图,要贴在地面上,并且随地面凹凸起伏 //代码 using UnityEngine; using System.Collections; [RequireCompo ...

随机推荐

  1. 如何让网站在百度有LOGO展示

    什么叫没有了网站logo?准确来说应该是网站索引logo,这个logo确实网站很好的一个展示窗口,我以长沙seo关键词为例,我给大家举例! 我输入长沙SEO,出来的百度索引图,原本所有我标红的框子里都 ...

  2. POJ 2762 Going from u to v or from v to u?- Tarjan

    Description 判断一个有向图是否对于任意两点 $x$,  $y$ 都有一条路径使$x - >y$或 $y - >x$ Solution 对于一个强联通分量内的点 都是可以互相到达 ...

  3. FoxMail提示:请求的名称有效,但是找不到请求的类型的数据

    FoxMail发送或者接收邮件的时候,提示如下信息: <错误信息:请求的名称有效,但是找不到请求的类型的数据> 一,DNS解析不稳定 解决办法:修改本地电脑上面本地连接中的DNS地址< ...

  4. list,set等集合遍历时,不能remove集合中的元素。需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAll(list/set)操作

    list,set等集合遍历时,不能remove集合中的元素.需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAl ...

  5. Minimum Size Subarray Sum LT209

    Given an array of n positive integers and a positive integer s, find the minimal length of a contigu ...

  6. maven下载的jar相应pom文件下载不完整问题。

    今天遇到一个奇葩问题: 同样的项目,我启动报错 : 某个class文件找不到.. 查找maven 依赖也的确没有找到 对应的jar 包. 查找同事项目,可以看到该class对应的 jar 包 是 lo ...

  7. Python 单列

    1.__new__内置方法 在对类进行实例化时自动执行 功能1:为对象分配空间 功能2:返回空间的引用 2.单列实现方法 class MusicPlayer: # 记录对象内存引用,初始值为None ...

  8. User_Agent大全

    'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Ver ...

  9. RNA-Seq数据去接头(Adapter)

    1.adapter是一段短的序列已知的核酸链,用于链接序列未知的目标测序片段. 2.barcode,也称为index,是一段很短的寡居核酸链,用于在多个样品混合测序时,标记不同的样品. 3.inser ...

  10. Emacs, Nano, or Vim 编辑器“三剑客”

    # Vim 强大,多种模式相互切换,不同于传统“录入式“写东西 对后续两个编辑器不熟悉 # nano 退出ctrl + x http://man.linuxde.net/nano # emacs ht ...