def save_nullspaces(): # points, cells = meshzoo.rectangle_tri((0.0, 0.0), (1.0, 1.0), 20) points, cells = meshzoo.disk(6, 20) @fem.BilinearForm def flux(u, v, w): return dot(w.n, u.grad) * v mesh = fem.MeshTri(points.T, cells.T) basis = fem.InteriorBasis(mesh, fem.ElementTriP1()) facet_basis = fem.FacetBasis(basis.mesh, basis.elem) lap = fem.asm(laplace, basis) boundary_terms = fem.asm(flux, facet_basis) A_dense = (lap - boundary_terms).toarray() # the right null space are the affine-linear functions rns = scipy.linalg.null_space(A_dense).T mesh.save("nullspace-right.vtk", point_data={ "k0": rns[0], "k1": rns[1], "k2": rns[2] }) # the left null space is a bit weird; something around the boundaries lns = scipy.linalg.null_space(A_dense.T).T mesh.save("nullspace-left.vtk", point_data={ "k0": lns[0], "k1": lns[1], "k2": lns[2] })
def __init__(self, edges, coord_sys, tabs): self.edges = edges self.nodes = dict.fromkeys(["y", "z"]) for var in self.nodes.keys(): self.nodes[var] = (self.edges[var][1:] + self.edges[var][:-1]) / 2 self.npts = len(self.edges["y"]) * len(self.edges["z"]) self.coord_sys = coord_sys # create mesh self.fem_mesh = skfem.MeshTri.init_tensor(self.edges["y"], self.edges["z"]) # get coordinates (returns a vector size 2*(Ny*Nz)) self.coordinates = self.fem_mesh.p # create elements and basis self.element = skfem.ElementTriP1() self.basis = skfem.InteriorBasis(self.fem_mesh, self.element) self.facet_basis = skfem.FacetBasis(self.fem_mesh, self.element) # get degrees of freedom and facets which correspond to tabs, and # create facet basis for sub regions self.negative_tab_dofs = self.basis.get_dofs( lambda x: self.on_boundary(x[0], x[1], tabs["negative"])).all() self.positive_tab_dofs = self.basis.get_dofs( lambda x: self.on_boundary(x[0], x[1], tabs["positive"])).all() self.negative_tab_facets = self.fem_mesh.facets_satisfying( lambda x: self.on_boundary(x[0], x[1], tabs["negative"])) self.positive_tab_facets = self.fem_mesh.facets_satisfying( lambda x: self.on_boundary(x[0], x[1], tabs["positive"])) self.negative_tab_basis = skfem.FacetBasis( self.fem_mesh, self.element, facets=self.negative_tab_facets) self.positive_tab_basis = skfem.FacetBasis( self.fem_mesh, self.element, facets=self.positive_tab_facets)
def setup(n): x0 = rng.random((n, 2)) - 0.5 # y0 = np.ones(n) # y0 = x0[:, 0] # y0 = x0[:, 0]**2 # y0 = np.cos(np.pi*x0.T[0]) # y0 = np.cos(np.pi*x0.T[0]) * np.cos(np.pi*x0.T[1]) y0 = np.cos(np.pi * np.sqrt(x0.T[0]**2 + x0.T[1]**2)) points, cells = meshzoo.rectangle_tri((-1.0, -1.0), (1.0, 1.0), n) mesh = skfem.MeshTri(points.T.copy(), cells.T.copy()) element = skfem.ElementTriP1() @skfem.BilinearForm def mass(u, v, _): return u * v @skfem.BilinearForm def flux(u, v, w): return dot(w.n, u.grad) * v basis = skfem.InteriorBasis(mesh, element) facet_basis = skfem.FacetBasis(basis.mesh, basis.elem) lap = skfem.asm(laplace, basis) boundary_terms = skfem.asm(flux, facet_basis) A = lap - boundary_terms # A *= lmbda # get the evaluation matrix E = basis.probes(x0.T) # mass matrix M = skfem.asm(mass, basis) # x = _solve(A, M, E, y0, solver) # # Neumann preconditioner # An = _assemble_eigen(dot(grad(u), grad(v)) * dx).sparray() # # Dirichlet preconditioner # Ad = _assemble_eigen(dot(grad(u), grad(v)) * dx) # bc = DirichletBC(V, 0.0, "on_boundary") # bc.apply(Ad) # # Ad = Ad.sparray() # Aq = _assemble_eigen( # dot(grad(u), grad(v)) * dx - dot(n, grad(u)) * v * ds - dot(n, grad(v)) * u * ds # ).sparray() # ml = pyamg.smoothed_aggregation_solver(A, coarse_solver="jacobi", max_coarse=100) # mln = pyamg.smoothed_aggregation_solver(An, coarse_solver="jacobi", max_coarse=100) # mld = pyamg.smoothed_aggregation_solver(Ad, coarse_solver="jacobi", max_coarse=100) # mlq = pyamg.smoothed_aggregation_solver(Aq, coarse_solver="jacobi", max_coarse=100) ml = pyamg.smoothed_aggregation_solver(A, coarse_solver="jacobi", symmetry="nonsymmetric", max_coarse=100) # mlT = pyamg.smoothed_aggregation_solver( # A.T, coarse_solver="jacobi", symmetry="nonsymmetric", max_coarse=100 # ) P = ml.aspreconditioner() # PT = mlT.aspreconditioner() # construct transpose -- dense, super expensive! I = np.eye(P.shape[0]) PT = (P @ I).T PT = scipy.sparse.csr_matrix(PT) # # make sure it's really the transpose # x = rng.random(A.shape[1]) # y = rng.random(A.shape[1]) # print(np.dot(x, P @ y)) # print(np.dot(PT @ x, y)) def matvec(x): return P @ x def rmatvec(y): return PT @ y precs = [ scipy.sparse.linalg.LinearOperator(A.shape, matvec=matvec, rmatvec=rmatvec) # not working well: # (ml.aspreconditioner(), mlT.aspreconditioner()) ] return A, E, M, precs, y0
height = 0.41 geom = Geometry() cylinder = geom.add_circle([0.2, 0.2, 0.0], radius, lcar=radius / 2) channel = geom.add_rectangle( 0.0, 2.2, 0.0, height, 0, holes=[cylinder], lcar=radius / 2 ) geom.add_physical(channel.surface, "domain") geom.add_physical(channel.lines[1], "outlet") geom.add_physical(channel.lines[3], "inlet") mesh = from_meshio(generate_mesh(geom, dim=2)) element = {"u": skfem.ElementVectorH1(skfem.ElementTriP2()), "p": skfem.ElementTriP1()} basis = { **{v: skfem.InteriorBasis(mesh, e, intorder=4) for v, e in element.items()}, "inlet": skfem.FacetBasis(mesh, element["u"], facets=mesh.boundaries["inlet"]), } M = skfem.asm(vector_mass, basis["u"]) L = {"u": skfem.asm(vector_laplace, basis["u"]), "p": skfem.asm(laplace, basis["p"])} B = -skfem.asm(divergence, basis["u"], basis["p"]) P = B.T + skfem.asm( port_pressure, *( skfem.FacetBasis(mesh, element[v], intorder=3, facets=mesh.boundaries["outlet"]) for v in ["p", "u"] ), ) t_final = 5.0 dt = 0.001
tol = 1.0e-8 for n in range(5, 41, 5): # points, cells = meshzoo.rectangle_tri((0.0, 0.0), (1.0, 1.0), n) points, cells = meshzoo.disk(6, n) print(f"{n = }, {len(points) = }") @fem.BilinearForm def flux(u, v, w): return dot(w.n, u.grad) * v # copy to avoid warnings; better would be to get the transposed arrays from meshzoo # directly mesh = fem.MeshTri(points.T.copy(), cells.T.copy()) basis = fem.InteriorBasis(mesh, fem.ElementTriP1()) facet_basis = fem.FacetBasis(basis.mesh, basis.elem) lap = fem.asm(laplace, basis) boundary_terms = fem.asm(flux, facet_basis) A = lap - boundary_terms b = rng.random(A.shape[1]) # make the system consistent by removing A's left nullspace components from the # right-hand side lns = scipy.linalg.null_space(A.T.toarray()).T for n in lns: b -= np.dot(b, n) / np.dot(n, n) * n ml = pyamg.smoothed_aggregation_solver(
mesh = from_file(Path("cylinder.json")) except Exception as e: from cylinder_dmsh import CylinderDmsh print("Couldn't find cylinder.json; generating in dmsh.") mesher = CylinderDmsh() mesh = mesher.mesh mesher.save() element = { "u": skfem.ElementVectorH1(skfem.ElementTriP2()), "p": skfem.ElementTriP1() } basis = { **{ v: skfem.InteriorBasis(mesh, e, intorder=4) for v, e in element.items() }, "inlet": skfem.FacetBasis(mesh, element["u"], facets=mesh.boundaries["inlet"]), } pressure_probe = probe(basis["p"], np.array([(0.15, 0.2), (0.25, 0.2)]).T) M = skfem.asm(vector_mass, basis["u"]) L = { "u": skfem.asm(vector_laplace, basis["u"]), "p": skfem.asm(laplace, basis["p"]) } B = -skfem.asm(divergence, basis["u"], basis["p"]) P = B.T + skfem.asm(