def get_poisson_steps_scikitfem(points, cells, tol): from skfem import ( MeshTri, MeshTet, InteriorBasis, ElementTriP1, ElementTetP1, asm, condense, ) from skfem.models.poisson import laplace, unit_load import krypy if cells.shape[1] == 3: mesh = MeshTri(points.T, cells.T) e = ElementTriP1() else: assert cells.shape[1] == 4 mesh = MeshTet(points.T, cells.T) e = ElementTetP1() basis = InteriorBasis(mesh, e) # assemble A = asm(laplace, basis) b = asm(unit_load, basis) A, b = condense(A, b, I=mesh.interior_nodes(), expand=False) _, info = krypy.cg(A, b, tol=tol) return info.iter
def runTest(self): @LinearForm def load(v, w): x = w.x return (np.sin(np.pi * x[0]) * np.sin(np.pi * x[1]) * (2.0 * np.pi**2) * v) m = self.mesh Nitrs = 9 L2s = np.zeros(Nitrs) H1s = np.zeros(Nitrs) for itr in range(Nitrs): ib = self.create_basis(m, itr + 2) A = asm(laplace, ib) b = asm(load, ib) D = ib.find_dofs() x = solve(*condense(A, b, D=D)) # calculate error L2s[itr], H1s[itr] = self.compute_error(m, ib, x) self.assertLess(H1s[-1], 1e-10) self.assertLess(L2s[-1], 1e-11)
def s(arr: spmatrix, b: np.ndarray) -> LinearSolver: ml = ruge_stuben_solver( skfem.condense(arr, D=dirichlet[v], expand=False)) def f(_: LinearOperator, b: np.ndarray) -> np.ndarray: return ml.solve(b) return f
def test_point_source(etype): mesh = MeshLine1().refined() basis = CellBasis(mesh, etype()) source = np.array([0.7]) u = solve(*condense(asm(laplace, basis), basis.point_source(source), D=basis.get_dofs())) exact = np.stack([(1 - source) * mesh.p, (1 - mesh.p) * source]).min(0) assert_almost_equal(u[basis.nodal_dofs], exact)
def runTest(self): m = self.init_mesh() basis = InteriorBasis(m, self.element_type()) A = laplace.assemble(basis) b = unit_load.assemble(basis) x = solve(*condense(A, b, D=basis.get_dofs())) self.assertAlmostEqual(np.max(x), self.maxval, places=3)
def runTest(self): path = Path(__file__).parents[1] / 'docs' / 'examples' / 'meshes' m = self.mesh_type.load(path / self.filename) basis = InteriorBasis(m, self.element_type()) A = laplace.assemble(basis) b = unit_load.assemble(basis) x = solve(*condense(A, b, D=basis.get_dofs())) self.assertAlmostEqual(np.max(x), 0.06261690318912218, places=3)
def runTest(self): """Solve Stokes problem, try splitting and other small things.""" m = MeshTri().refined() m = m.refined(3).with_boundaries({ 'up': lambda x: x[1] == 1., 'rest': lambda x: x[1] != 1., }) e = ElementVectorH1(ElementTriP2()) * ElementTriP1() basis = CellBasis(m, e) @BilinearForm def bilinf(u, p, v, q, w): from skfem.helpers import grad, ddot, div return (ddot(grad(u), grad(v)) - div(u) * q - div(v) * p - 1e-2 * p * q) S = asm(bilinf, basis) D = basis.find_dofs(skip=['u^2']) x = basis.zeros() x[D['up'].all('u^1^1')] = .1 x = solve(*condense(S, x=x, D=D)) (u, u_basis), (p, p_basis) = basis.split(x) self.assertEqual(len(u), m.p.shape[1] * 2 + m.facets.shape[1] * 2) self.assertEqual(len(p), m.p.shape[1]) self.assertTrue(np.sum(p - x[basis.nodal_dofs[2]]) < 1e-8) U, P = basis.interpolate(x) self.assertTrue(isinstance(U.value, np.ndarray)) self.assertTrue(isinstance(P.value, np.ndarray)) self.assertTrue(P.shape[0] == m.nelements) self.assertTrue((basis.doflocs[:, D['up'].all()][1] == 1.).all()) # test blocks splitting of forms while at it C1 = asm(bilinf.block(1, 1), CellBasis(m, ElementTriP1())) C2 = S[basis.nodal_dofs[-1]].T[basis.nodal_dofs[-1]].T self.assertTrue(abs((C1 - C2).min()) < 1e-10) self.assertTrue(abs((C1 - C2).max()) < 1e-10) # test splitting ElementVector (ux, uxbasis), (uy, uybasis) = u_basis.split(u) assert_allclose(ux[uxbasis.nodal_dofs[0]], u[u_basis.nodal_dofs[0]]) assert_allclose(ux[uxbasis.facet_dofs[0]], u[u_basis.facet_dofs[0]]) assert_allclose(uy[uybasis.nodal_dofs[0]], u[u_basis.nodal_dofs[1]]) assert_allclose(uy[uybasis.facet_dofs[0]], u[u_basis.facet_dofs[1]])
def runTest(self): """Solve Stokes problem, try splitting and other small things.""" m = MeshTri() m.refine() m.define_boundary('centreline', lambda x: x[0] == .5, boundaries_only=False) m.refine(3) e = ElementVectorH1(ElementTriP2()) * ElementTriP1() m.define_boundary('up', lambda x: x[1] == 1.) m.define_boundary('rest', lambda x: x[1] != 1.) basis = InteriorBasis(m, e) self.assertEqual( basis.get_dofs(m.boundaries['centreline']).all().size, (2 + 1) * (2**(1 + 3) + 1) + 2 * 2**(1 + 3)) self.assertEqual(basis.find_dofs()['centreline'].all().size, (2 + 1) * (2**(1 + 3) + 1) + 2 * 2**(1 + 3)) @BilinearForm def bilinf(u, p, v, q, w): from skfem.helpers import grad, ddot, div return (ddot(grad(u), grad(v)) - div(u) * q - div(v) * p - 1e-2 * p * q) S = asm(bilinf, basis) D = basis.find_dofs(skip=['u^2']) x = basis.zeros() x[D['up'].all('u^1^1')] = .1 x = solve(*condense(S, basis.zeros(), x=x, D=D)) (u, u_basis), (p, p_basis) = basis.split(x) self.assertEqual(len(u), m.p.shape[1] * 2 + m.facets.shape[1] * 2) self.assertEqual(len(p), m.p.shape[1]) self.assertTrue(np.sum(p - x[basis.nodal_dofs[2]]) < 1e-8) U, P = basis.interpolate(x) self.assertTrue(isinstance(U.value, np.ndarray)) self.assertTrue(isinstance(P.value, np.ndarray)) self.assertTrue((basis.doflocs[:, D['up'].all()][1] == 1.).all())
def runTest(self): m = MeshLine(np.linspace(0., 1.)).refined(2) ib = InteriorBasis(m, self.e) fb = FacetBasis(m, self.e) @LinearForm def boundary_flux(v, w): return v * (w.x[0] == 1.) L = asm(laplace, ib) b = asm(boundary_flux, fb) D = m.nodes_satisfying(lambda x: x == 0.0) I = ib.complement_dofs(D) # noqa E741 u = solve(*condense(L, b, I=I)) # noqa E741 np.testing.assert_array_almost_equal(u[ib.nodal_dofs[0]], m.p[0], -10)
def runTest(self): m = self.mesh().refined(3) ib = InteriorBasis(m, self.elem()) A = asm(laplace, ib) D = ib.get_dofs().all() I = ib.complement_dofs(D) for X in self.funs: x = self.set_bc(X, ib) Xh = x.copy() x = solve(*condense(A, x=x, I=I)) self.assertLessEqual(np.sum(x - Xh), 1e-10)
def runTest(self): @LinearForm def load(v, w): x = w.x if x.shape[0] == 1: return (np.sin(np.pi * x[0]) * (np.pi**2) * v) elif x.shape[0] == 2: return (np.sin(np.pi * x[0]) * np.sin(np.pi * x[1]) * (2.0 * np.pi**2) * v) elif x.shape[0] == 3: return (np.sin(np.pi * x[0]) * np.sin(np.pi * x[1]) * np.sin(np.pi * x[2]) * (3.0 * np.pi**2) * v) else: raise Exception("The dimension not supported") m = self.mesh Nitrs = 3 L2s = np.zeros(Nitrs) H1s = np.zeros(Nitrs) hs = np.zeros(Nitrs) for itr in range(Nitrs): if itr > 0: m = self.do_refined(m, itr) ib = self.create_basis(m) A = asm(laplace, ib) b = asm(load, ib) D = self.get_bc_nodes(ib) x = solve(*condense(A, b, D=D)) # calculate error L2s[itr], H1s[itr] = self.compute_error(m, ib, x) hs[itr] = m.param() rateL2 = np.polyfit(np.log(hs), np.log(L2s), 1)[0] rateH1 = np.polyfit(np.log(hs), np.log(H1s), 1)[0] self.assertLess(np.abs(rateL2 - self.rateL2), self.eps, msg='observed L2 rate: {}'.format(rateL2)) self.assertLess(np.abs(rateH1 - self.rateH1), self.eps, msg='observed H1 rate: {}'.format(rateH1)) self.assertLess(H1s[-1], 0.3) self.assertLess(L2s[-1], 0.008)
def runTest(self): m = self.case[0]() m.refine(self.prerefs) hs = [] L2s = [] for itr in range(3): e = self.case[1]() ib = InteriorBasis(m, e) @BilinearForm def bilinf(u, v, w): return ddot(dd(u), dd(v)) @LinearForm def linf(v, w): return 1. * v K = asm(bilinf, ib) f = asm(linf, ib) x = solve(*condense(K, f, D=ib.get_dofs().all())) X = ib.interpolate(x) def exact(x): return (x ** 2 - 2. * x ** 3 + x ** 4) / 24. @Functional def error(w): return (w.w - exact(w.x)) ** 2 L2 = np.sqrt(error.assemble(ib, w=X)) L2s.append(L2) hs.append(m.param()) m.refine() hs = np.array(hs) L2s = np.array(L2s) pfit = np.polyfit(np.log10(hs), np.log10(L2s), 1) self.assertGreater(pfit[0], self.limits[0]) self.assertLess(pfit[0], self.limits[1]) self.assertLess(L2s[-1], self.abs_limit)
def runTest(self): m = MeshLine(np.linspace(0., 1.)) m.refine(2) e = ElementLineP1() ib = InteriorBasis(m, e) fb = FacetBasis(m, e) @linear_form def boundary_flux(v, dv, w): return -v * (w.x[0] == 1.) L = asm(laplace, ib) b = asm(boundary_flux, fb) D = m.nodes_satisfying(lambda x: x == 0.0) I = ib.complement_dofs(D) # noqa E741 u = solve(*condense(L, b, I=I)) # noqa E741 self.assertTrue(np.sum(np.abs(u + m.p[0, :])) < 1e-10)
def runTest(self): m = MeshLine(np.linspace(0., 1.)).refined(2) ib = InteriorBasis(m, self.e) m.define_boundary('left', lambda x: x[0] == 0.0) m.define_boundary('right', lambda x: x[0] == 1.0) fb = FacetBasis(m, self.e, facets=m.boundaries['right']) @LinearForm def boundary_flux(v, w): return -w.x[0] * v L = asm(laplace, ib) b = asm(boundary_flux, fb) D = ib.find_dofs()['left'].all() I = ib.complement_dofs(D) # noqa E741 u = solve(*condense(L, b, I=I)) # noqa E741 np.testing.assert_array_almost_equal(u[ib.nodal_dofs[0]], -m.p[0], -10)
def test_periodic_mesh_assembly(m, mdgtype, etype, check1, check2): def _sort(ix): # sort index arrays so that ix[0] matches return ix[np.argsort(np.sum(m.p, axis=0)[ix])] mp = mdgtype.periodic(m, _sort(m.nodes_satisfying(check1)), _sort(m.nodes_satisfying(check2))) basis = Basis(mp, etype()) A = laplace.assemble(basis) f = unit_load.assemble(basis) D = basis.get_dofs() x = solve(*condense(A, f, D=D)) if m.dim() == 2: assert_almost_equal(x.max(), 0.125) else: assert_almost_equal(x.max(), 0.07389930610869411, decimal=3) assert not np.isnan(x).any()
def runTest(self): @bilinear_form def dudv(u, du, v, dv, w): return sum(du * dv) m = self.mesh() m.refine(4) ib = InteriorBasis(m, self.elem()) A = asm(dudv, ib) D = ib.get_dofs().all() I = ib.complement_dofs(D) for X in self.funs: x = self.set_bc(X, ib) Xh = x.copy() x = solve(*condense(A, 0 * x, x=x, I=I)) self.assertLessEqual(np.sum(x - Xh), 1e-10)
def laplace(m, **params): """Solve the Laplace equation using the FEM. Parameters ---------- m A Mesh object. """ e = ElementTriP1() basis = CellBasis(m, e) A = laplacian.assemble(basis) b = unit_load.assemble(basis) u = solve(*condense(A, b, I=m.interior_nodes())) # evaluate the error estimators fbasis = [InteriorFacetBasis(m, e, side=i) for i in [0, 1]] w = {"u" + str(i + 1): fbasis[i].interpolate(u) for i in [0, 1]} @Functional def interior_residual(w): h = w.h return h**2 eta_K = interior_residual.elemental(basis) @Functional def edge_jump(w): h = w.h n = w.n dw1 = grad(w["u1"]) dw2 = grad(w["u2"]) return h * ((dw1[0] - dw2[0]) * n[0] + (dw1[1] - dw2[1]) * n[1])**2 eta_E = edge_jump.elemental(fbasis[0], **w) tmp = np.zeros(m.facets.shape[1]) np.add.at(tmp, fbasis[0].find, eta_E) eta_E = np.sum(0.5 * tmp[m.t2f], axis=0) return eta_E + eta_K
def runTest(self): """Solve Stokes problem, try splitting and other small things.""" m = MeshTri().refined() m = m.refined(3).with_boundaries({ 'up': lambda x: x[1] == 1., 'rest': lambda x: x[1] != 1., }) e = ElementVectorH1(ElementTriP2()) * ElementTriP1() basis = CellBasis(m, e) @BilinearForm def bilinf(u, p, v, q, w): from skfem.helpers import grad, ddot, div return (ddot(grad(u), grad(v)) - div(u) * q - div(v) * p - 1e-2 * p * q) S = asm(bilinf, basis) D = basis.find_dofs(skip=['u^2']) x = basis.zeros() x[D['up'].all('u^1^1')] = .1 x = solve(*condense(S, x=x, D=D)) (u, u_basis), (p, p_basis) = basis.split(x) self.assertEqual(len(u), m.p.shape[1] * 2 + m.facets.shape[1] * 2) self.assertEqual(len(p), m.p.shape[1]) self.assertTrue(np.sum(p - x[basis.nodal_dofs[2]]) < 1e-8) U, P = basis.interpolate(x) self.assertTrue(isinstance(U.value, np.ndarray)) self.assertTrue(isinstance(P.value, np.ndarray)) self.assertTrue((basis.doflocs[:, D['up'].all()][1] == 1.).all())
gamma = 0.4 * delta**2 beta = 1.25 lambda_ = beta g = gamma mesh = MeshTet.init_tensor(np.linspace(0, L, 10 + 1), np.linspace(0, W, 3 + 1), np.linspace(0, W, 3 + 1)) basis = InteriorBasis(mesh, ElementVectorH1(ElementTetP1())) clamped = basis.get_dofs(lambda x: x[0] == 0.0).all() free = basis.complement_dofs(clamped) K = asm(linear_elasticity(lambda_, mu), basis) @LinearForm def load(v, w): return -rho * g * v.value[2] f = asm(load, basis) u = solve(*condense(K, f, I=free)) deformed = MeshTet(mesh.p + u[basis.nodal_dofs], mesh.t) deformed.save("deformed.xdmf") u_magnitude = np.linalg.norm(u.reshape((-1, 3)), axis=1) print("min/max u:", min(u_magnitude), max(u_magnitude))
with TimeSeriesWriter(Path(__file__).with_suffix(".xdmf")) as writer: writer.write_points_cells(embed(mesh.p.T), {"triangle": mesh.t.T}) t = 0.0 while t < t_final: t += dt # Step 1: momentum prediction uv = skfem.solve( *skfem.condense( K_lhs, K_rhs @ uv_ - P @ (2 * p_ - p__) - skfem.asm( acceleration, basis["u"], wind=basis["u"].interpolate(u)), uv0, D=dirichlet["u"], ), solver=solvers[0], ) # Step 2: pressure correction dp = skfem.solve(*skfem.condense(L["p"], (B / dt) @ uv, D=dirichlet["p"]), solver=solvers[1]) # Step 3: velocity correction p = p_ + dp
def runTest(self): m = self.case[0]().refined(self.prerefs) hs = [] L2s = [] for itr in range(3): e = self.case[1]() ib = InteriorBasis(m, e) t = 1. E = 1. nu = 0.3 D = E * t ** 3 / (12. * (1. - nu ** 2)) @BilinearForm def bilinf(u, v, w): def C(T): trT = T[0, 0] + T[1, 1] return E / (1. + nu) * \ np.array([[T[0, 0] + nu / (1. - nu) * trT, T[0, 1]], [T[1, 0], T[1, 1] + nu / (1. - nu) * trT]]) return t ** 3 / 12.0 * ddot(C(dd(u)), dd(v)) def load(x): return np.sin(np.pi * x[0]) * np.sin(np.pi * x[1]) @LinearForm def linf(v, w): return load(w.x) * v K = asm(bilinf, ib) f = asm(linf, ib) # TODO fix boundary conditions # u_x should be zero on top/bottom # u_y should be zero on left/right x = solve(*condense(K, f, D=ib.get_dofs().all('u'))) X = ib.interpolate(x) def exact(x): return 1. / (4. * D * np.pi ** 4) * load(x) @Functional def error(w): return (w.w - exact(w.x)) ** 2 L2 = np.sqrt(error.assemble(ib, w=X)) L2s.append(L2) hs.append(m.param()) m = m.refined() hs = np.array(hs) L2s = np.array(L2s) pfit = np.polyfit(np.log10(hs), np.log10(L2s), 1) self.assertGreater(pfit[0], self.limits[0]) self.assertLess(pfit[0], self.limits[1]) self.assertLess(L2s[-1], self.abs_limit)
uv0 = np.zeros(basis["u"].N) inlet_dofs = basis["u"].get_dofs(mesh.boundaries["inlet"]).all("u^1") inlet_y_lim = [p.x[1] for p in channel.lines[3].points[::-1]] monic = np.polynomial.polynomial.Polynomial.fromroots(inlet_y_lim) uv0[inlet_dofs] = -6 * monic(basis["u"].doflocs[1, inlet_dofs]) / inlet_y_lim[1] ** 2 def embed(xy: np.ndarray) -> np.ndarray: return np.pad(xy, ((0, 0), (0, 1)), "constant") solvers = [ pyamgcl.solver( pyamgcl.amg( skfem.condense(K_lhs, D=dirichlet["u"], expand=False), {"coarsening.type": "aggregation", "relax.type": "ilu0"}, ), {"type": "cg"}, ), pyamgcl.solver( pyamgcl.amg(skfem.condense(L["p"], D=dirichlet["p"], expand=False)), {"type": "cg"}, ), pyamgcl.solver( pyamgcl.amg( skfem.condense(M / dt, D=dirichlet["u"], expand=False), {"relax.type": "gauss_seidel"}, ), {"type": "cg"}, ),
t = 0 with TimeSeriesWriter("channel.xdmf") as writer: writer.write_points_cells(mesh.p.T, {"triangle": mesh.t.T}) while t < t_final: t += dt # Step 1: Momentum prediction (Ern & Guermond 2002, eq. 7.40, p. 274) uv = skfem.solve(*skfem.condense( K, (M / dt) @ uv_ - P @ (2 * p_ - p__), np.zeros_like(uv_), D=dirichlet["u"], )) # Step 2: Projection (Ern & Guermond 2002, eq. 7.41, p. 274) dp = np.zeros(basis["p"].N) dp[inlet_pressure_dofs] = p_inlet - p_[inlet_pressure_dofs] dp = skfem.solve(*skfem.condense(L["p"], B @ uv, dp, D=dirichlet["p"])) # Step 3: Recover pressure and velocity (E. & G. 2002, p. 274) p = p_ + dp print(min(p), "<= p <= ", max(p))