def evalbasis(self, mesh, qps, tind=None): # initialize power basis self._pbasisNinit(self.dim, self.maxdeg) N = len(self._pbasis) # construct Vandermonde matrix and invert it V = self._evaldofs(mesh, tind=tind) V = np.linalg.inv(V) # initialize u = const_cell(0*qps[0], N) du = const_cell(0*qps[0], N, self.dim) ddu = const_cell(0*qps[0], N, self.dim, self.dim) # loop over new basis for jtr in range(N): # loop over power basis for itr in range(N): if self.dim==2: u[jtr] += V[:, itr, jtr][:, None]\ * self._pbasis[itr](qps[0], qps[1]) du[jtr][0] += V[:, itr, jtr][:, None]\ * self._pbasisdx[itr](qps[0], qps[1]) du[jtr][1] += V[:, itr, jtr][:,None]\ * self._pbasisdy[itr](qps[0], qps[1]) ddu[jtr][0][0] += V[:, itr, jtr][:, None]\ * self._pbasisdxx[itr](qps[0], qps[1]) ddu[jtr][0][1] += V[:, itr, jtr][:, None]\ * self._pbasisdxy[itr](qps[0], qps[1]) ddu[jtr][1][1] += V[:, itr, jtr][:, None]\ * self._pbasisdyy[itr](qps[0], qps[1]) else: raise NotImplementedError("!") ddu[jtr][1][0] = ddu[jtr][0][1] return u, du, ddu
def inorm(self, form, interp, intorder=None): # evaluate norm on all elements tind = range(self.mesh.t.shape[1]) if not isinstance(interp, dict): raise Exception("The input solution vector(s) must be in a " "dictionary! Pass e.g. {0:u} instead of u.") if intorder is None: intorder = 2*self.elem_u.maxdeg # check and fix parameters of form oldparams = inspect.getargspec(form).args paramlist = ['u', 'du', 'ddu', 'x', 'h'] fform = self.fillargs(form, paramlist) X, W = get_quadrature(self.mesh.refdom, intorder) # mappings x = self.mapping.F(X, tind) # reference facet to global facet # jacobian at quadrature points detDF = self.mapping.detDF(X, tind) Nbfun_u = self.dofnum_u.t_dof.shape[0] dim = self.mesh.p.shape[0] # interpolate the solution vectors at quadrature points zero = 0.0*x[0] w, dw, ddw = ({} for i in range(3)) for k in interp: w[k] = zero dw[k] = const_cell(zero, dim) ddw[k] = const_cell(zero, dim, dim) for j in range(Nbfun_u): jdofs = self.dofnum_u.t_dof[j, :] w[k] += interp[k][jdofs][:, None]\ * self.u[j] for a in range(dim): dw[k][a] += interp[k][jdofs][:, None]\ * self.du[j][a] for b in range(dim): ddw[k][a][b] += interp[k][jdofs][:, None]\ * self.ddu[j][a][b] # compute the mesh parameter from jacobian determinant h = np.abs(detDF)**(1.0/self.mesh.dim()) return np.dot(fform(w, dw, ddw, x, h)**2*np.abs(detDF), W)
def plot_lagmult(self, mesh, dofnum, sol, minval, maxval, lambdaeval, nref=2, cbar=True): """Draw plate obstacle lagrange multiplier on refined mesh.""" print "Plotting on a refined mesh. This is slowish due to loop over elements..." import copy import spfem.mesh as fmsh plt.figure() totmaxval = 0 for itr in range(mesh.t.shape[1]): m = fmsh.MeshTri( np.array([[ mesh.p[0, mesh.t[0, itr]], mesh.p[0, mesh.t[1, itr]], mesh.p[0, mesh.t[2, itr]] ], [ mesh.p[1, mesh.t[0, itr]], mesh.p[1, mesh.t[1, itr]], mesh.p[1, mesh.t[2, itr]] ]]), np.array([[0], [1], [2]])) M = copy.deepcopy(m) m.refine(nref) qps = {} qps[0] = np.array([m.p[0, :]]) qps[1] = np.array([m.p[1, :]]) u, _, _, d4u = self.evalbasis(M, qps, [0]) newu = u[0].flatten() * 0.0 #newd4u = d4u[0].flatten()*0.0 newd4u = const_cell(0 * qps[0], self.dim, self.dim) for jtr in range(len(u)): newu += sol[dofnum.t_dof[jtr, itr]] * u[jtr].flatten() newd4u[0][0] += sol[dofnum.t_dof[ jtr, itr]] * d4u[jtr][0][0].flatten() newd4u[0][1] += sol[dofnum.t_dof[ jtr, itr]] * d4u[jtr][0][1].flatten() newd4u[1][0] += sol[dofnum.t_dof[ jtr, itr]] * d4u[jtr][1][0].flatten() newd4u[1][1] += sol[dofnum.t_dof[ jtr, itr]] * d4u[jtr][1][1].flatten() tmp = lambdaeval(newu, newd4u, qps, M.param()) #print tmp.shape if np.max(tmp) > totmaxval: totmaxval = np.max(tmp) m.plot(tmp.flatten(), nofig=True, smooth=True, zlim=(minval, maxval)) plt.hold('on') print "Maximum value: " + str(totmaxval) if cbar: plt.colorbar()
def evalbasis(self, mesh, qps, tind=None): # initialize power basis self._pbasisNinit(self.dim, self.maxdeg) N = len(self._pbasis) # construct Vandermonde matrix and invert it V = self._evaldofs(mesh, tind=tind) V = np.linalg.inv(V) # initialize u = const_cell(0 * qps[0], N) du = const_cell(0 * qps[0], N, self.dim) ddu = const_cell(0 * qps[0], N, self.dim, self.dim) d4u = const_cell(0 * qps[0], N, self.dim, self.dim) # loop over new basis for jtr in range(N): # loop over power basis for itr in range(N): if self.dim == 2: u[jtr] += V[:, itr, jtr][:, None]\ * self._pbasis[itr](qps[0], qps[1]) du[jtr][0] += V[:, itr, jtr][:, None]\ * self._pbasisdx[itr](qps[0], qps[1]) du[jtr][1] += V[:, itr, jtr][:,None]\ * self._pbasisdy[itr](qps[0], qps[1]) ddu[jtr][0][0] += V[:, itr, jtr][:, None]\ * self._pbasisdxx[itr](qps[0], qps[1]) ddu[jtr][0][1] += V[:, itr, jtr][:, None]\ * self._pbasisdxy[itr](qps[0], qps[1]) ddu[jtr][1][1] += V[:, itr, jtr][:, None]\ * self._pbasisdyy[itr](qps[0], qps[1]) d4u[jtr][0][0] += V[:, itr, jtr][:, None]\ * self._pbasisdxxxx[itr](qps[0], qps[1]) d4u[jtr][1][1] += V[:, itr, jtr][:, None]\ * self._pbasisdyyyy[itr](qps[0], qps[1]) d4u[jtr][0][1] += V[:, itr, jtr][:, None]\ * self._pbasisdxxyy[itr](qps[0], qps[1]) else: raise NotImplementedError("!") ddu[jtr][1][0] = ddu[jtr][0][1] d4u[jtr][1][0] = d4u[jtr][0][1] return u, du, ddu, d4u
import copy m1defo = copy.deepcopy(m1) m2defo = copy.deepcopy(m2) m1defo.p[0, :] += X[a1.dofnum_u.n_dof[0, :]] m1defo.p[1, :] += X[a1.dofnum_u.n_dof[1, :]] m2defo.p[0, :] += Y[a2.dofnum_u.n_dof[0, :]] m2defo.p[1, :] += Y[a2.dofnum_u.n_dof[1, :]] m1defo.draw() plt.hold('on') m2defo.draw(nofig=True) import spfem.utils as spu Du1 = spu.const_cell(0.0, 2, 2) Du2 = spu.const_cell(0.0, 2, 2) Du1[0][0], Du1[0][1] = spu.gradient(X[a1.dofnum_u.n_dof[0, :]], m1) Du1[1][0], Du1[1][1] = spu.gradient(X[a1.dofnum_u.n_dof[1, :]], m1) Du2[0][0], Du2[0][1] = spu.gradient(Y[a2.dofnum_u.n_dof[0, :]], m2) Du2[1][0], Du2[1][1] = spu.gradient(Y[a2.dofnum_u.n_dof[1, :]], m2) S1 = C1(Eps(Du1)) S2 = C2(Eps(Du2)) smax = np.max((np.max(S1[1][1]), np.max(S1[1][1]))) smin = np.min((np.min(S2[1][1]), np.min(S2[1][1]))) m1.plot(C1(Eps(Du1))[1, 1], zlim=(smin, smax)) plt.hold('on') m2.plot(C2(Eps(Du2))[1, 1], nofig=True, zlim=(smin, smax))
def fasm(self, form, find=None, interior=False, intorder=None, normals=True, interp=None): """Facet assembly.""" if find is None: if interior: find = self.mesh.interior_facets() else: find = self.mesh.boundary_facets() if intorder is None: intorder = self.elem_u.maxdeg + self.elem_v.maxdeg nv = self.mesh.p.shape[1] nt = self.mesh.t.shape[1] ne = find.shape[0] # check and fix parameters of form oldparams = inspect.getargspec(form).args if interior: if 'u1' in oldparams or 'du1' in oldparams: paramlist = ['u1', 'u2', 'v1', 'v2', 'du1', 'du2', 'dv1', 'dv2', 'x', 'h', 'n', 'w'] bilinear = True else: paramlist = ['v1', 'v2', 'dv1', 'dv2', 'x', 'h', 'n', 'w'] bilinear = False else: if 'u' in oldparams or 'du' in oldparams: paramlist = ['u', 'v', 'du', 'dv', 'x', 'h', 'n', 'w'] bilinear = True else: paramlist = ['v', 'dv', 'x', 'h', 'n', 'w'] bilinear = False fform = self.fillargs(form, paramlist) X, W = get_quadrature(self.mesh.brefdom, intorder) # boundary element indices tind1 = self.mesh.f2t[0, find] tind2 = self.mesh.f2t[1, find] # mappings x = self.mapping.G(X, find=find) # reference facet to global facet Y1 = self.mapping.invF(x, tind=tind1) # global facet to ref element Y2 = self.mapping.invF(x, tind=tind2) # global facet to ref element Nbfun_u = self.dofnum_u.t_dof.shape[0] Nbfun_v = self.dofnum_v.t_dof.shape[0] detDG = self.mapping.detDG(X, find) # compute normal vectors n = {} if normals: # normals based on tind1 only n = self.mapping.normals(Y1, tind1, find, self.mesh.t2f) # compute the mesh parameter from jacobian determinant if self.mesh.dim() > 1.0: h = np.abs(detDG)**(1.0/(self.mesh.dim() - 1.0)) else: # exception for 1D mesh (no boundary h defined) h = None # interpolate some previous discrete function at quadrature points w = {} if interp is not None: if not isinstance(interp, dict): raise Exception("The input solution vector(s) must be in a " "dictionary! Pass e.g. {0:u} instead of u.") for k in interp: w[k] = 0.0*x[0] for j in range(Nbfun_u): phi, _ = self.elem_u.gbasis(self.mapping, Y1, j, tind1) w[k] += interp[k][self.dofnum_u.t_dof[j, tind1], None]*phi # bilinear form if bilinear: # initialize sparse matrix structures ndata = Nbfun_u*Nbfun_v*ne if interior: data = np.zeros(4*ndata) rows = np.zeros(4*ndata) cols = np.zeros(4*ndata) else: data = np.zeros(ndata) rows = np.zeros(ndata) cols = np.zeros(ndata) for j in range(Nbfun_u): u1, du1 = self.elem_u.gbasis(self.mapping, Y1, j, tind1) if interior: u2, du2 = self.elem_u.gbasis(self.mapping, Y2, j, tind2) if j == 0: # these are zeros corresponding to the shapes of u,du z = const_cell(0, *cell_shape(u2)) dz = const_cell(0, *cell_shape(du2)) for i in range(Nbfun_v): v1, dv1 = self.elem_v.gbasis(self.mapping, Y1, i, tind1) if interior: v2, dv2 = self.elem_v.gbasis(self.mapping, Y2, i, tind2) # compute entries of local stiffness matrices if interior: ixs1 = slice(ne*(Nbfun_v*j + i), ne*(Nbfun_v*j + i + 1)) ixs2 = slice(ne*(Nbfun_v*j + i) + ndata, ne*(Nbfun_v*j + i + 1) + ndata) ixs3 = slice(ne*(Nbfun_v*j + i) + 2*ndata, ne*(Nbfun_v*j + i + 1) + 2*ndata) ixs4 = slice(ne*(Nbfun_v*j + i) + 3*ndata, ne*(Nbfun_v*j + i + 1) + 3*ndata) data[ixs1] = np.dot(fform(u1, z, v1, z, du1, dz, dv1, dz, x, h, n, w)*np.abs(detDG), W) rows[ixs1] = self.dofnum_v.t_dof[i, tind1] cols[ixs1] = self.dofnum_u.t_dof[j, tind1] data[ixs2] = np.dot(fform(z, u2, z, v2, dz, du2, dz, dv2, x, h, n, w)*np.abs(detDG), W) rows[ixs2] = self.dofnum_v.t_dof[i, tind2] cols[ixs2] = self.dofnum_u.t_dof[j, tind2] data[ixs3] = np.dot(fform(z, u2, v1, z, dz, du2, dv1, dz, x, h, n, w)*np.abs(detDG), W) rows[ixs3] = self.dofnum_v.t_dof[i, tind1] cols[ixs3] = self.dofnum_u.t_dof[j, tind2] data[ixs4] = np.dot(fform(u1, z, z, v2, du1, dz, dz, dv2, x, h, n, w)*np.abs(detDG), W) rows[ixs4] = self.dofnum_v.t_dof[i, tind2] cols[ixs4] = self.dofnum_u.t_dof[j, tind1] else: ixs = slice(ne*(Nbfun_v*j + i), ne*(Nbfun_v*j + i + 1)) data[ixs] = np.dot(fform(u1, v1, du1, dv1, x, h, n, w)*np.abs(detDG), W) rows[ixs] = self.dofnum_v.t_dof[i, tind1] cols[ixs] = self.dofnum_u.t_dof[j, tind1] return coo_matrix((data, (rows, cols)), shape=(self.dofnum_v.N, self.dofnum_u.N)).tocsr() # linear form else: if interior: # could not find any use case raise Exception("No interior support in linear facet form.") # initialize sparse matrix structures data = np.zeros(Nbfun_v*ne) rows = np.zeros(Nbfun_v*ne) cols = np.zeros(Nbfun_v*ne) for i in range(Nbfun_v): v1, dv1 = self.elem_v.gbasis(self.mapping, Y1, i, tind1) # find correct location in data,rows,cols ixs = slice(ne*i, ne*(i + 1)) # compute entries of local stiffness matrices data[ixs] = np.dot(fform(v1, dv1, x, h, n, w)*np.abs(detDG), W) rows[ixs] = self.dofnum_v.t_dof[i, tind1] cols[ixs] = np.zeros(ne) return coo_matrix((data, (rows, cols)), shape=(self.dofnum_v.N, 1)).toarray().T[0]
def fnorm(self, form, interp, intorder=None, interior=False, normals=True): if interior: # evaluate norm on all interior facets find = self.mesh.interior_facets() else: # evaluate norm on all boundary facets find = self.mesh.boundary_facets() if not isinstance(interp, dict): raise Exception("The input solution vector(s) must be in a " "dictionary! Pass e.g. {0:u} instead of u.") if intorder is None: intorder = 2*self.elem_u.maxdeg # check and fix parameters of form oldparams = inspect.getargspec(form).args if 'u1' in oldparams or 'du1' in oldparams or 'ddu1' in oldparams: if interior is False: raise Exception("The supplied form contains u1 although " "no interior=True is given.") if interior: paramlist = ['u1', 'u2', 'du1', 'du2', 'ddu1', 'ddu2', 'x', 'n', 't', 'h'] else: paramlist = ['u', 'du', 'ddu', 'x', 'n', 't', 'h'] fform = self.fillargs(form, paramlist) X, W = get_quadrature(self.mesh.brefdom, intorder) # indices of elements at different sides of facets tind1 = self.mesh.f2t[0, find] tind2 = self.mesh.f2t[1, find] # mappings x = self.mapping.G(X, find=find) # reference facet to global facet detDG = self.mapping.detDG(X, find) # compute basis function values at quadrature points u1, du1, ddu1 = self.elem_u.evalbasis(self.mesh, x, tind=tind1) if interior: u2, du2, ddu2 = self.elem_u.evalbasis(self.mesh, x, tind=tind2) Nbfun_u = self.dofnum_u.t_dof.shape[0] dim = self.mesh.p.shape[0] n = {} t = {} if normals: Y = self.mapping.invF(x, tind=tind1) # global facet to ref element n = self.mapping.normals(Y, tind1, find, self.mesh.t2f) if len(n) == 2: # TODO fix for 3D and other than triangles? t[0] = -n[1] t[1] = n[0] # interpolate the solution vectors at quadrature points zero = np.zeros((len(find), len(W))) w1, dw1, ddw1 = ({} for i in range(3)) if interior: w2, dw2, ddw2 = ({} for i in range(3)) for k in interp: w1[k] = zero dw1[k] = const_cell(zero, dim) ddw1[k] = const_cell(zero, dim, dim) if interior: w2[k] = zero dw2[k] = const_cell(zero, dim) ddw2[k] = const_cell(zero, dim, dim) for j in range(Nbfun_u): jdofs1 = self.dofnum_u.t_dof[j, tind1] jdofs2 = self.dofnum_u.t_dof[j, tind2] w1[k] += interp[k][jdofs1][:, None] * u1[j] if interior: w2[k] += interp[k][jdofs2][:, None] * u2[j] for a in range(dim): dw1[k][a] += interp[k][jdofs1][:, None]\ * du1[j][a] if interior: dw2[k][a] += interp[k][jdofs2][:, None]\ * du2[j][a] for b in range(dim): ddw1[k][a][b] += interp[k][jdofs1][:, None]\ * ddu1[j][a][b] if interior: ddw2[k][a][b] += interp[k][jdofs2][:, None]\ * ddu2[j][a][b] h = np.abs(detDG)**(1.0/(self.mesh.dim()-1.0)) if interior: return np.dot(fform(w1, w2, dw1, dw2, ddw1, ddw2, x, n, t, h)**2*np.abs(detDG), W), find else: return np.dot(fform(w1, dw1, ddw1, x, n, t, h)**2*np.abs(detDG), W), find
import copy m1defo=copy.deepcopy(m1) m2defo=copy.deepcopy(m2) m1defo.p[0,:]+=X[a1.dofnum_u.n_dof[0,:]] m1defo.p[1,:]+=X[a1.dofnum_u.n_dof[1,:]] m2defo.p[0,:]+=Y[a2.dofnum_u.n_dof[0,:]] m2defo.p[1,:]+=Y[a2.dofnum_u.n_dof[1,:]] m1defo.draw() plt.hold('on') m2defo.draw(nofig=True) import spfem.utils as spu Du1=spu.const_cell(0.0,2,2) Du2=spu.const_cell(0.0,2,2) Du1[0][0],Du1[0][1]=spu.gradient(X[a1.dofnum_u.n_dof[0,:]],m1) Du1[1][0],Du1[1][1]=spu.gradient(X[a1.dofnum_u.n_dof[1,:]],m1) Du2[0][0],Du2[0][1]=spu.gradient(Y[a2.dofnum_u.n_dof[0,:]],m2) Du2[1][0],Du2[1][1]=spu.gradient(Y[a2.dofnum_u.n_dof[1,:]],m2) S1=C1(Eps(Du1)) S2=C2(Eps(Du2)) smax=np.max((np.max(S1[1][1]),np.max(S1[1][1]))) smin=np.min((np.min(S2[1][1]),np.min(S2[1][1]))) m1.plot(C1(Eps(Du1))[1,1],zlim=(smin,smax)) plt.hold('on') m2.plot(C2(Eps(Du2))[1,1],nofig=True,zlim=(smin,smax))