def __init__(self, U_m, mesh): """Function spaces and BCs""" V = VectorFunctionSpace(mesh, 'P', 2) Q = FunctionSpace(mesh, 'P', 1) self.mesh = mesh self.vu, self.vp = TestFunction(V), TestFunction(Q) # for integration self.u_, self.p_ = Function(V), Function(Q) # for the solution self.u_1, self.p_1 = Function(V), Function(Q) # for the prev. solution self.u_k, self.p_k = Function(V), Function(Q) # for the prev. solution self.u, self.p = TrialFunction(V), TrialFunction(Q) # unknown! U0_str = "4.*U_m*x[1]*(.41-x[1])/(.41*.41)" x = [0, .41 / 2] # evaluate the Expression at the center of the channel self.U_mean = np.mean(2 / 3 * eval(U0_str)) U0 = Expression((U0_str, "0"), U_m=U_m, degree=2) bc0 = DirichletBC(V, Constant((0, 0)), cylinderwall) bc1 = DirichletBC(V, Constant((0, 0)), topandbottom) bc2 = DirichletBC(V, U0, inlet) bc3 = DirichletBC(Q, Constant(0), outlet) self.bcu = [bc0, bc1, bc2] self.bcp = [bc3] # ds is needed to compute drag and lift. ASD1 = AutoSubDomain(topandbottom) ASD2 = AutoSubDomain(cylinderwall) mf = MeshFunction("size_t", mesh, 1) mf.set_all(0) ASD1.mark(mf, 1) ASD2.mark(mf, 2) self.ds_ = ds(subdomain_data=mf, domain=mesh) return
class QuarterSphereGrid(object): def __init__(self, x0, y0, z0, R, n): class SphereSurface(SubDomain): def inside(self, x, on_boundary): return on_boundary class X_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[0], x0) class Y_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[1], y0) class Z_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[2], z0) self.geometry = Sphere(Point(x0, y0, z0), R, segments=n) - Box(Point(x0 + R, y0, z0 - R), Point(x0 - R, y0 - R, z0 + R)) - Box(Point(x0 - R, y0 + R, z0), Point(x0 + R, y0, z0 - R)) - Box(Point(x0, y0, z0), Point(x0 - R, y0 + R, z0 + R)) self.mesh = generate_mesh(self.geometry, n) self.domains = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) self.domains.set_all(0) self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.boundaries = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()-1) self.boundaries.set_all(0) self.sphereSurface = SphereSurface() self.sphereSurface.mark(self.boundaries, 1) self.x_symmetric = X_Symmetric() self.x_symmetric.mark(self.boundaries, 2) self.y_symmetric = Y_Symmetric() self.y_symmetric.mark(self.boundaries, 3) self.z_symmetric = Z_Symmetric() self.z_symmetric.mark(self.boundaries, 4) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) self.dS = Measure('dS', domain=self.mesh, subdomain_data=self.boundaries)
def convert_meshfunctions_to_submesh(mesh, submesh, meshfunctions_on_mesh): assert meshfunctions_on_mesh is None or (isinstance( meshfunctions_on_mesh, list) and len(meshfunctions_on_mesh) > 0) if meshfunctions_on_mesh is None: return None meshfunctions_on_submesh = list() # Create submesh subdomains for mesh_subdomain in meshfunctions_on_mesh: submesh_subdomain = MeshFunction("size_t", submesh, mesh_subdomain.dim()) submesh_subdomain.set_all(0) assert submesh_subdomain.dim() in (submesh.topology().dim(), submesh.topology().dim() - 1) if submesh_subdomain.dim() == submesh.topology().dim(): for submesh_cell in cells(submesh): submesh_subdomain.array()[ submesh_cell.index()] = mesh_subdomain.array()[ submesh.submesh_to_mesh_cell_local_indices[ submesh_cell.index()]] elif submesh_subdomain.dim() == submesh.topology().dim() - 1: for submesh_facet in facets(submesh): submesh_subdomain.array()[ submesh_facet.index()] = mesh_subdomain.array()[ submesh.submesh_to_mesh_facet_local_indices[ submesh_facet.index()]] else: # impossible to arrive here anyway, thanks to the assert raise TypeError( "Invalid arguments in convert_meshfunctions_to_submesh.") meshfunctions_on_submesh.append(submesh_subdomain) return meshfunctions_on_submesh
def test_closed_boundary(advection_scheme): # FIXME: rk3 scheme does not bounces off the wall properly xmin, xmax = 0., 1. ymin, ymax = 0., 1. mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10) # Particle x = np.array([[0.975, 0.475]]) # Given velocity field: vexpr = Constant((1., 0.)) # Given time do_step: dt = 0.05 # Then bounced position is x_bounced = np.array([[0.975, 0.475]]) p = particles(x, [x, x], mesh) V = VectorFunctionSpace(mesh, "CG", 1) v = Function(V) v.assign(vexpr) # Different boundary parts bound_left = UnitSquareLeft() bound_right = UnitSquareRight() bound_top = UnitSquareTop() bound_bottom = UnitSquareBottom() # Mark all facets facet_marker = MeshFunction('size_t', mesh, mesh.topology().dim() - 1) facet_marker.set_all(0) # Mark as closed bound_right.mark(facet_marker, 1) # Mark other boundaries as open bound_left.mark(facet_marker, 2) bound_top.mark(facet_marker, 2) bound_bottom.mark(facet_marker, 2) if advection_scheme == 'euler': ap = advect_particles(p, V, v, facet_marker) elif advection_scheme == 'rk2': ap = advect_rk2(p, V, v, facet_marker) elif advection_scheme == 'rk3': ap = advect_rk3(p, V, v, facet_marker) else: assert False # Do one timestep, particle must bounce from wall of ap.do_step(dt) xpE = p.positions() # Check if particle correctly bounced off from closed wall xpE_root = comm.gather(xpE, root=0) if comm.rank == 0: xpE_root = np.float64(np.vstack(xpE_root)) error = np.linalg.norm(x_bounced - xpE_root) assert(error < 1e-10)
def _test_eigen_solver_sparse(callback_type): from rbnics.backends.dolfin import EigenSolver # Define mesh mesh = UnitSquareMesh(10, 10) # Define function space V_element = VectorElement("Lagrange", mesh.ufl_cell(), 2) Q_element = FiniteElement("Lagrange", mesh.ufl_cell(), 1) W_element = MixedElement(V_element, Q_element) W = FunctionSpace(mesh, W_element) # Create boundaries class Wall(SubDomain): def inside(self, x, on_boundary): return on_boundary and (x[1] < 0 + DOLFIN_EPS or x[1] > 1 - DOLFIN_EPS) boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0) wall = Wall() wall.mark(boundaries, 1) # Define variational problem vq = TestFunction(W) (v, q) = split(vq) up = TrialFunction(W) (u, p) = split(up) lhs = inner(grad(u), grad(v)) * dx - div(v) * p * dx - div(u) * q * dx rhs = -inner(p, q) * dx # Define boundary condition bc = [DirichletBC(W.sub(0), Constant((0., 0.)), boundaries, 1)] # Define eigensolver depending on callback type assert callback_type in ("form callbacks", "tensor callbacks") if callback_type == "form callbacks": solver = EigenSolver(W, lhs, rhs, bc) elif callback_type == "tensor callbacks": LHS = assemble(lhs) RHS = assemble(rhs) solver = EigenSolver(W, LHS, RHS, bc) # Solve the eigenproblem solver.set_parameters({ "linear_solver": "mumps", "problem_type": "gen_non_hermitian", "spectrum": "target real", "spectral_transform": "shift-and-invert", "spectral_shift": 1.e-5 }) solver.solve(1) r, c = solver.get_eigenvalue(0) assert abs(c) < 1.e-10 assert r > 0., "r = " + str(r) + " is not positive" print("Sparse inf-sup constant: ", sqrt(r)) return (sqrt(r), solver.condensed_A, solver.condensed_B)
def test_open_boundary(advection_scheme): xmin, xmax = 0.0, 1.0 ymin, ymax = 0.0, 1.0 pres = 3 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10) # Particle x = RandomRectangle(Point(0.955, 0.45), Point(1.0, 0.55)).generate([pres, pres]) x = comm.bcast(x, root=0) # Given velocity field: vexpr = Constant((1.0, 1.0)) # Given time do_step: dt = 0.05 p = particles(x, [x, x], mesh) V = VectorFunctionSpace(mesh, "CG", 1) v = Function(V) v.assign(vexpr) # Different boundary parts bound_left = UnitSquareLeft() bound_right = UnitSquareRight() bound_top = UnitSquareTop() bound_bottom = UnitSquareBottom() # Mark all facets facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) facet_marker.set_all(0) # Mark as open bound_right.mark(facet_marker, 2) # Mark other boundaries as closed bound_left.mark(facet_marker, 1) bound_top.mark(facet_marker, 1) bound_bottom.mark(facet_marker, 1) if advection_scheme == "euler": ap = advect_particles(p, V, v, facet_marker) elif advection_scheme == "rk2": ap = advect_rk2(p, V, v, facet_marker) elif advection_scheme == "rk3": ap = advect_rk3(p, V, v, facet_marker) else: assert False # Do one timestep, particle must bounce from wall of ap.do_step(dt) num_particles = p.number_of_particles() # Check if all particles left domain if comm.rank == 0: assert (num_particles == 0)
def refineMesh(m, l, u): cell_markers = MeshFunction('bool', m, 1) cell_markers.set_all(False) coords = m.coordinates() midpoints = 0.5 * (coords[:-1] + coords[1:]) ref_idx = np.where((midpoints > l) & (midpoints < u))[0] cell_markers.array()[ref_idx] = True m = refine(m, cell_markers) return m
def mesh_generator(n): mesh = UnitSquareMesh(n, n, "left/right") dim = mesh.topology().dim() domains = MeshFunction("size_t", mesh, dim) domains.set_all(0) dx = Measure("dx", subdomain_data=domains) boundaries = MeshFunction("size_t", mesh, dim - 1) boundaries.set_all(0) ds = Measure("ds", subdomain_data=boundaries) return mesh, dx, ds
def test_advect_periodic_facet_marker(advection_scheme): xmin, xmax = 0.0, 1.0 ymin, ymax = 0.0, 1.0 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10) facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) facet_marker.set_all(0) boundaries = Boundaries() boundaries.mark(facet_marker, 3) lims = np.array([ [xmin, xmin, ymin, ymax], [xmax, xmax, ymin, ymax], [xmin, xmax, ymin, ymin], [xmin, xmax, ymax, ymax], ]) vexpr = Constant((1.0, 1.0)) V = VectorFunctionSpace(mesh, "CG", 1) x = RandomRectangle(Point(0.05, 0.05), Point(0.15, 0.15)).generate([3, 3]) x = comm.bcast(x, root=0) dt = 0.05 v = Function(V) v.assign(vexpr) p = particles(x, [x * 0, x**2], mesh) if advection_scheme == "euler": ap = advect_particles(p, V, v, facet_marker, lims.flatten()) elif advection_scheme == "rk2": ap = advect_rk2(p, V, v, facet_marker, lims.flatten()) elif advection_scheme == "rk3": ap = advect_rk3(p, V, v, facet_marker, lims.flatten()) else: assert False xp0 = p.positions() t = 0.0 while t < 1.0 - 1e-12: ap.do_step(dt) t += dt xpE = p.positions() # Check if position correct xp0_root = comm.gather(xp0, root=0) xpE_root = comm.gather(xpE, root=0) if comm.Get_rank() == 0: xp0_root = np.float32(np.vstack(xp0_root)) xpE_root = np.float32(np.vstack(xpE_root)) error = np.linalg.norm(xp0_root - xpE_root) assert error < 1e-10
def navier_stokes_IPCS(mesh, dt, parameter): """ fenics code: weak form of the problem. """ mu, rho, nu = parameter V = VectorFunctionSpace(mesh, 'P', 2) Q = FunctionSpace(mesh, 'P', 1) bc0 = DirichletBC(V, Constant((0, 0)), cylinderwall) bc1 = DirichletBC(V, Constant((0, 0)), topandbottom) bc2 = DirichletBC(V, U0, inlet) bc3 = DirichletBC(Q, Constant(1), outlet) bcs = [bc0, bc1, bc2, bc3] # ds is needed to compute drag and lift. Not used here. ASD1 = AutoSubDomain(topandbottom) ASD2 = AutoSubDomain(cylinderwall) mf = MeshFunction("size_t", mesh, 1) mf.set_all(0) ASD1.mark(mf, 1) ASD2.mark(mf, 2) ds_ = ds(subdomain_data=mf, domain=mesh) vu, vp = TestFunction(V), TestFunction(Q) # for integration u_, p_ = Function(V), Function(Q) # for the solution u_1, p_1 = Function(V), Function(Q) # for the prev. solution u, p = TrialFunction(V), TrialFunction(Q) # unknown! bcu = [bcs[0], bcs[1], bcs[2]] bcp = [bcs[3]] n = FacetNormal(mesh) u_mid = (u + u_1) / 2.0 F1 = rho*dot((u - u_1) / dt, vu)*dx \ + rho*dot(dot(u_1, nabla_grad(u_1)), vu)*dx \ + inner(sigma(u_mid, p_1, mu), epsilon(vu))*dx \ + dot(p_1*n, vu)*ds - dot(mu*nabla_grad(u_mid)*n, vu)*ds a1 = lhs(F1) L1 = rhs(F1) # Define variational problem for step 2 a2 = dot(nabla_grad(p), nabla_grad(vp)) * dx L2 = dot(nabla_grad(p_1), nabla_grad(vp)) * dx - ( rho / dt) * div(u_) * vp * dx # rho missing in FEniCS tutorial # Define variational problem for step 3 a3 = dot(u, vu) * dx L3 = dot(u_, vu) * dx - dt * dot(nabla_grad(p_ - p_1), vu) * dx # Assemble matrices A1 = assemble(a1) A2 = assemble(a2) A3 = assemble(a3) # Apply boundary conditions to matrices [bc.apply(A1) for bc in bcu] [bc.apply(A2) for bc in bcp] return u_, p_, u_1, p_1, L1, A1, L2, A2, L3, A3, bcu, bcp
def generate_footing_square(Nelements, length, refinements=0): from dolfin import UnitSquareMesh, SubDomain, MeshFunction, Measure, near, refine, cells import numpy as np # Start from square mesh = generate_square(Nelements, length, 0)[0] def refine_mesh(mesh): # Refine on top cell_markers = MeshFunction('bool', mesh, mesh.topology().dim()) cell_markers.set_all(False) for c in cells(mesh): verts = np.reshape(c.get_vertex_coordinates(), (3, 2)) verts_x = verts[:, 0] verts_y = verts[:, 1] newval = verts_y.min() > 2 * length / 3 and verts_x.min() > length / \ 8 and verts_x.max() < 7 / 8 * length cell_markers[c] = newval # Redefine markers on new mesh return refine(mesh, cell_markers) mesh = refine_mesh(refine_mesh(mesh)) for i in range(refinements): mesh = refine(mesh) class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) and on_boundary class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], length) and on_boundary class Top(SubDomain): def inside(self, x, on_boundary): return near(x[1], length) and on_boundary class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) and on_boundary left, right, top, bottom = Left(), Right(), Top(), Bottom() LEFT, RIGHT, TOP, BOTTOM = 1, 2, 3, 4 # Set numbering markers = MeshFunction("size_t", mesh, 1) markers.set_all(0) boundaries = (left, right, top, bottom) def_names = (LEFT, RIGHT, TOP, BOTTOM) for side, num in zip(boundaries, def_names): side.mark(markers, num) return mesh, markers, LEFT, RIGHT, TOP, BOTTOM, NONE
def __init__(self, n=16, divide=1, threshold=12.3, left_side_num=3, left_side_denom=4): """ Store parameters, initialize data exports (latex, txt). """ # left_side_num/denom are either height, assuming base is 1, # or left and bottom side lengths self.n = n self.threshold = threshold / left_side_denom ** 2 self.left_side = [0] * (n + 1) self.bottom_side = [0] * (n + 1) self.left_side_len = left_side_num * 1.0 / left_side_denom self.left_side_num = left_side_num self.left_side_denom = left_side_denom self.folder = "results" self.name = "domains_{}_{}_{}".format(n, divide, threshold) self.filename = self.folder + "/" + self.name + ".tex" self.matrixZname = self.folder + "/matrices_Z/" + self.name self.matrixQname = self.folder + "/matrices_Q/" + self.name self.genericname = self.folder + "/" + self.name self.textname = self.folder + "/" + self.name + ".txt" f = open(self.textname, 'w') f.close() self.latex = "cd " + self.folder + "; pdflatex --interaction=batchmode" \ + " {0}.tex; rm {0}.aux {0}.log".format(self.name) self.shift = 0 # common mesh, ready to cut/apply Dirichlet BC self.mesh = Triangle(self.left_side_num, left_side_denom) while self.mesh.size(2) < self.n * self.n: self.mesh = refine(self.mesh) for i in range(divide): self.mesh = refine(self.mesh) boundary = MeshFunction("size_t", self.mesh, 1) boundary.set_all(0) self.plotted = plot( boundary, prefix='animation/animation', scalarbar=False, window_width=1024, window_height=1024) print 'Grid size: ', self.n ** 2 print 'Mesh size: ', self.mesh.size(2) # setup solver self.solver = Solver(self.mesh, left_side_num, left_side_denom) self.mass = self.solver.B self.stiff = self.solver.A print np.unique(self.stiff.data) self.save_matrices(0) # save dofs f = open(self.genericname+'_dofmap.txt', 'w') for vec in self.solver.dofs: print >>f, vec f.close()
def test_advect_open(advection_scheme): pres = 3 mesh = UnitCubeMesh(10, 10, 10) # Particle x = RandomBox(Point(0.955, 0.45, 0.5), Point(0.99, 0.55, 0.6)).generate([pres, pres, pres]) x = comm.bcast(x, root=0) # Given velocity field: vexpr = Constant((1.0, 1.0, 1.0)) # Given time do_step: dt = 0.05 p = particles(x, [x, x], mesh) V = VectorFunctionSpace(mesh, "CG", 1) v = Function(V) v.assign(vexpr) # Different boundary parts bounds = Boundaries() bound_right = UnitCubeRight() # Mark all facets facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) facet_marker.set_all(0) bounds.mark(facet_marker, 1) bound_right.mark(facet_marker, 2) # Mark as open bound_right.mark(facet_marker, 2) if advection_scheme == "euler": ap = advect_particles(p, V, v, facet_marker) elif advection_scheme == "rk2": ap = advect_rk2(p, V, v, facet_marker) elif advection_scheme == "rk3": ap = advect_rk3(p, V, v, facet_marker) else: assert False # Do one timestep, particle must bounce from wall of ap.do_step(dt) num_particles = p.number_of_particles() # Check if all particles left domain if comm.rank == 0: assert num_particles == 0
def refine_mesh(mesh): # Refine on top cell_markers = MeshFunction('bool', mesh, mesh.topology().dim()) cell_markers.set_all(False) for c in cells(mesh): verts = np.reshape(c.get_vertex_coordinates(), (3, 2)) verts_x = verts[:, 0] verts_y = verts[:, 1] newval = verts_y.min() > 2 * length / 3 and verts_x.min() > length / \ 8 and verts_x.max() < 7 / 8 * length cell_markers[c] = newval # Redefine markers on new mesh return refine(mesh, cell_markers)
def square_with_obstacle(): # Create classes for defining parts of the boundaries and the interior # of the domain class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], 1.0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) class Top(SubDomain): def inside(self, x, on_boundary): return near(x[1], 1.0) class Obstacle(SubDomain): def inside(self, x, on_boundary): return between(x[1], (0.5, 0.7)) and between(x[0], (0.2, 1.0)) # Initialize sub-domain instances left = Left() top = Top() right = Right() bottom = Bottom() obstacle = Obstacle() # Define mesh mesh = UnitSquareMesh(100, 100, "crossed") # Initialize mesh function for interior domains domains = CellFunction("size_t", mesh) domains.set_all(0) obstacle.mark(domains, 1) # Initialize mesh function for boundary domains boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0) left.mark(boundaries, 1) top.mark(boundaries, 2) right.mark(boundaries, 3) bottom.mark(boundaries, 4) boundary_indices = {"left": 1, "top": 2, "right": 3, "bottom": 4} f = Constant(0.0) theta0 = Constant(293.0) return mesh, f, boundaries, boundary_indices, theta0
def generate_cube(Nelements, length, refinements=0): """ Creates a square mesh of given elements and length with markers on the sides: left, bottom, right and top """ from dolfin import UnitCubeMesh, SubDomain, MeshFunction, Measure, near, refine mesh = UnitCubeMesh(Nelements, Nelements, Nelements) for i in range(refinements): mesh = refine(mesh) mesh.coordinates()[:] *= length # Subdomains: Solid class Xp(SubDomain): def inside(self, x, on_boundary): return near(x[0], length) and on_boundary class Xm(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) and on_boundary class Yp(SubDomain): def inside(self, x, on_boundary): return near(x[1], length) and on_boundary class Ym(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) and on_boundary class Zp(SubDomain): def inside(self, x, on_boundary): return near(x[2], length) and on_boundary class Zm(SubDomain): def inside(self, x, on_boundary): return near(x[2], 0.0) and on_boundary xp, xm, yp, ym, zp, zm = Xp(), Xm(), Yp(), Ym(), Zp(), Zm() XP, XM, YP, YM, ZP, ZM = 1, 2, 3, 4, 5, 6 # Set numbering markers = MeshFunction("size_t", mesh, 2) markers.set_all(0) boundaries = (xp, xm, yp, ym, zp, zm) def_names = (XP, XM, YP, YM, ZP, ZM) for side, num in zip(boundaries, def_names): side.mark(markers, num) return mesh, markers, XP, XM, YP, YM, ZP, ZM
class BoxGrid(object): def __init__(self, x0, x1, y0, y1, z0, z1, n, unstructured=False): class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], x0) class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], x1) class Back(SubDomain): def inside(self, x, on_boundary): return near(x[1], y0) class Front(SubDomain): def inside(self, x, on_boundary): return near(x[1], y1) class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[2], z0) class Top(SubDomain): def inside(self, x, on_boundary): return near(x[2], z1) if unstructured: self.geometry = Box(Point(x0, y0, z0), Point(x1, y1, z1)) self.mesh = generate_mesh(self.geometry, n) else: nx = int(round(n**(1./3.)*(x1 - x0))) ny = int(round(n**(1./3.)*(y1 - y0))) nz = int(round(n**(1./3.)*(z1 - z0))) self.mesh = BoxMesh(Point(x0, y0, z0), Point(x1, y1, z1), nx, ny, nz) self.domains = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) self.domains.set_all(0) self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.boundaries = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()-1) self.boundaries.set_all(0) self.left = Left() self.left.mark(self.boundaries, 1) self.right = Right() self.right.mark(self.boundaries, 2) self.front = Front() self.front.mark(self.boundaries, 3) self.back = Back() self.back.mark(self.boundaries, 4) self.bottom = Bottom() self.bottom.mark(self.boundaries, 5) self.top = Top() self.top.mark(self.boundaries, 6) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) self.dS = Measure('dS', domain=self.mesh, subdomain_data=self.boundaries)
def _init_for_append_if_needed(self): # Initialize dof to cells map only the first time if len(self.dof_to_cells) == 0: self.dof_to_cells = list() # of size len(V) for (component, V_component) in enumerate(self.V): dof_to_cells = self._compute_dof_to_cells(V_component) # Debugging log(DEBUG, "DOFs to cells map (component " + str(component) + ") on processor " + str(self.mpi_comm.rank) + ":") for (global_dof, cells_) in dof_to_cells.items(): log(DEBUG, "\t" + str(global_dof) + ": " + str([cell.global_index() for cell in cells_])) # Add to storage self.dof_to_cells.append(dof_to_cells) self.dof_to_cells = tuple(self.dof_to_cells) # Initialize cells marker N = self._get_next_index() reduced_mesh_markers = MeshFunction("bool", self.mesh, self.mesh.topology().dim()) reduced_mesh_markers.set_all(False) if N > 0: reduced_mesh_markers.array()[:] = self.reduced_mesh_markers[N - 1].array() assert N not in self.reduced_mesh_markers self.reduced_mesh_markers[N] = reduced_mesh_markers
def test_meshfunction_where_equal(): mesh = UnitSquareMesh(MPI.comm_self, 2, 2) cf = MeshFunction("size_t", mesh, mesh.topology.dim, 0) cf.set_all(1) cf[0] = 3 cf[3] = 3 assert list(cf.where_equal(3)) == [0, 3] assert list(cf.where_equal(1)) == [1, 2, 4, 5, 6, 7] ff = MeshFunction("size_t", mesh, mesh.topology.dim - 1, 100) ff.set_all(0) ff[0] = 1 ff[2] = 3 ff[3] = 3 assert list(ff.where_equal(1)) == [0] assert list(ff.where_equal(3)) == [2, 3] assert list(ff.where_equal(0)) == [1] + list(range(4, ff.size())) vf = MeshFunction("size_t", mesh, 0, 0) vf.set_all(3) vf[1] = 1 vf[2] = 1 assert list(vf.where_equal(1)) == [1, 2] assert list(vf.where_equal(3)) == [0] + list(range(3, vf.size()))
def generate_square(Nelements, length, refinements=0): """ Creates a square mesh of given elements and length with markers on the sides: left, bottom, right and top """ from dolfin import UnitSquareMesh, SubDomain, MeshFunction, Measure, near, refine mesh = UnitSquareMesh(Nelements, Nelements) for i in range(refinements): mesh = refine(mesh) mesh.coordinates()[:] *= length # Subdomains: Solid class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) and on_boundary class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], length) and on_boundary class Top(SubDomain): def inside(self, x, on_boundary): return near(x[1], length) and on_boundary class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) and on_boundary left, right, top, bottom = Left(), Right(), Top(), Bottom() LEFT, RIGHT, TOP, BOTTOM = 1, 2, 3, 4 # Set numbering NONE = 99 # Marker for empty boundary markers = MeshFunction("size_t", mesh, 1) markers.set_all(0) boundaries = (left, right, top, bottom) def_names = (LEFT, RIGHT, TOP, BOTTOM) for side, num in zip(boundaries, def_names): side.mark(markers, num) return mesh, markers, LEFT, RIGHT, TOP, BOTTOM, NONE
def get_norm(u, uh): assert len(subdomains) == len(u) V = uh.function_space() mesh = V.mesh() cell_f = MeshFunction('size_t', mesh, mesh.topology().dim(), 0) error = 0 for subd_i, u_i in zip(subdomains, u): cell_f.set_all(0) # Reset! # Pick an edge subd_i.mark(cell_f, 1) mesh_i = SubMesh(mesh, cell_f, 1) # Edge local function space Vi = FunctionSpace(mesh_i, V.ufl_element()) # The solution on it uh_i = interpolate(uh, Vi) # And the error there error_i = norm(u_i, uh_i) error += error_i**2 error = sqrt(error) return error
def __init__(self, mesh, arg): # Initialize empty list list.__init__(self) # Process depending on the second argument assert isinstance(mesh, Mesh) assert isinstance(arg, (list, str, SubDomain)) or arg is None if isinstance(arg, list): assert all([isinstance(arg_i, SubDomain) for arg_i in arg]) if arg is None: pass # leave the list empty elif isinstance(arg, (list, SubDomain)): D = mesh.topology().dim() for d in range(D + 1): mesh_function_d = MeshFunction("bool", mesh, d) mesh_function_d.set_all(False) if isinstance(arg, SubDomain): arg.mark(mesh_function_d, True) else: for arg_i in arg: arg_i.mark(mesh_function_d, True) self.append(mesh_function_d) elif isinstance(arg, str): self._read(mesh, arg)
def setup_problem(mesh, U0, coupled=True): # Build function space V = VectorFunctionSpace(mesh, 'P', 2) Q = FunctionSpace(mesh, 'P', 1) L = FunctionSpace(mesh, 'P', 1) VQL = (V, Q, L) # bc0 = DirichletBC(V, Constant((0, 0)), cylinderwall) bc1 = DirichletBC(V, Constant((0, 0)), topandbottom) bc2 = DirichletBC(V, U0, inlet) bc3 = DirichletBC(Q, Constant(1), outlet) # bcs = [bc0, bc1, bc2, bc3] bcs = [bc1, bc2, bc3] warnings.warn("no no-slip for cyl-wall!") ASD1 = AutoSubDomain(topandbottom) ASD2 = AutoSubDomain(cylinderwall) mf = MeshFunction("size_t", mesh, 1) mf.set_all(0) ASD1.mark(mf, 1) ASD2.mark(mf, 2) ds_ = ds(subdomain_data=mf, domain=mesh) return VQL, bcs, ds_
def generate_rectangle(x0, y0, x1, y1, nx, ny): """ Creates a square mesh of given elements and length with markers on the sides: left, bottom, right and top """ from dolfin import RectangleMesh, Point, SubDomain, MeshFunction, Measure, near mesh = RectangleMesh(Point(x0, y0), Point(x1, y1), nx, ny) # Subdomains: Solid class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], x0) and on_boundary class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], x1) and on_boundary class Top(SubDomain): def inside(self, x, on_boundary): return near(x[1], y1) and on_boundary class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[1], y0) and on_boundary left, right, top, bottom = Left(), Right(), Top(), Bottom() LEFT, RIGHT, TOP, BOTTOM = 1, 2, 3, 4 # Set numbering NONE = 99 # Marker for empty boundary markers = MeshFunction("size_t", mesh, 1) markers.set_all(0) boundaries = (left, right, top, bottom) def_names = (LEFT, RIGHT, TOP, BOTTOM) for side, num in zip(boundaries, def_names): side.mark(markers, num) return mesh, markers, LEFT, RIGHT, TOP, BOTTOM, NONE
def create_boundary(self, domains, interior, exterior): """ mark commmon facets between two domains with 1 and a return FacetFunction""" edges = MeshFunction("size_t", domains.mesh(), domains.mesh().topology().dim() - 1) edges.set_all(0) # count number of boundary facets Nfacets = 0 for facet in facets(domains.mesh()): cells = facet.entities(2) if facet.exterior() == False: cell1 = cells[0] cell2 = cells[1] domain1 = domains.array()[cells[0]] domain2 = domains.array()[cells[1]] if (sorted([domain1, domain2]) == sorted([interior, exterior])): idx = facet.index() edges.array()[idx] = True Nfacets += 1 return (edges, Nfacets)
class EmbeddedWaveguide(): """ a rectangular waveguide with cladding class builds the mesh and marks domains """ def __init__(self, w_sim, h_sim, w_wg, h_wg, res): # Create mesh with two domains, waveguide + cladding self.res = res domain = Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2)) domain.set_subdomain( 1, Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2))) domain.set_subdomain( 2, Rectangle(Point(-w_wg / 2, -h_wg / 2), Point(w_wg / 2, h_wg / 2))) self.mesh = generate_mesh(domain, self.res) self.mesh.init() # Initialize mesh function for interior domains self.waveguide = Waveguide(w_wg, h_wg) self.domains = MeshFunction("size_t", self.mesh, 2) self.domains.set_all(0) self.waveguide.mark(self.domains, 1) # Define new measures associated with the interior domains self.dx = Measure("dx")(subdomain_data=self.domains)
def peter(): base = "../meshes/2d/peter" # base = '../meshes/2d/peter-fine' mesh = Mesh(base + ".xml") subdomains = MeshFunction("size_t", mesh, base + "_physical_region.xml") workpiece_index = 3 subdomain_materials = {1: "SiC", 2: "carbon steel", 3: "GaAs (liquid)"} submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) W = VectorFunctionSpace(submesh_workpiece, "CG", 2) Q = FunctionSpace(submesh_workpiece, "CG", 2) # Define melt boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): # Be especially careful in the corners when defining the r=0 axis: # For the PPE to be consistent, we need to have n.u=0 *everywhere* # on the non-(r=0) boundaries. return ( on_boundary and x[0] < GMSH_EPS and 0.005 + GMSH_EPS < x[1] and x[1] < 0.050 - GMSH_EPS ) class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and 0.055 - GMSH_EPS < x[1] and 0.030 - GMSH_EPS < x[0] and x[0] < 0.075 + GMSH_EPS ) class StampBoundary(SubDomain): def inside(self, x, on_boundary): # Well well. If we don't include the endpoints here, the PPE turns # out inconsistent. This is weird since the endpoints should be # picked up by RightBoundary and StampBoundary. return ( on_boundary and 0.050 - GMSH_EPS < x[1] and x[1] < 0.055 + GMSH_EPS and x[0] < 0.030 + GMSH_EPS ) class LowerBoundary(SubDomain): def inside(self, x, on_boundary): # Danger, danger. # If the rightmost point (0.075, 0.010) is excluded, the PPE will # end up inconsistent. # This is actually weird since it should be picked up by # RightBoundary. return on_boundary and ( x[1] < 0.005 + GMSH_EPS or (x[0] > 0.070 - GMSH_EPS and x[1] < 0.010 + GMSH_EPS) ) class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 0.075 - GMSH_EPS left_boundary = LeftBoundary() lower_boundary = LowerBoundary() right_boundary = RightBoundary() surface_boundary = SurfaceBoundary() stamp_boundary = StampBoundary() # Define workpiece boundaries. wp_boundaries = MeshFunction( "size_t", submesh_workpiece, self.submesh_workpiece.topology().dim() - 1 ) wp_boundaries.set_all(0) left_boundary.mark(wp_boundaries, 1) lower_boundary.mark(wp_boundaries, 2) right_boundary.mark(wp_boundaries, 3) surface_boundary.mark(wp_boundaries, 4) stamp_boundary.mark(wp_boundaries, 5) # For local use only: wp_boundary_indices = {"left": 1, "lower": 2, "right": 3, "surface": 4, "stamp": 5} # Boundary conditions for the velocity. u_bcs = [ DirichletBC(W, (0.0, 0.0), stamp_boundary), DirichletBC(W, (0.0, 0.0), right_boundary), DirichletBC(W, (0.0, 0.0), lower_boundary), DirichletBC(W.sub(0), 0.0, left_boundary), DirichletBC(W.sub(1), 0.0, surface_boundary), ] p_bcs = [] # Boundary conditions for the heat equation. # Dirichlet theta_bcs_d = [] # Neumann theta_bcs_n = {} # Robin, i.e., # # -dtheta/dn = alpha (theta - theta0) # # (with alpha>0 to preserve coercivity of the scheme). # theta_bcs_r = { wp_boundary_indices["stamp"]: (100.0, 1500.0), wp_boundary_indices["surface"]: (100.0, 1550.0), wp_boundary_indices["right"]: (300.0, Expression("200*x[0] + 1600", degree=1)), wp_boundary_indices["lower"]: ( 300.0, Expression("-1200*x[1] + 1614", degree=1), ), } return ( mesh, subdomains, subdomain_materials, workpiece_index, wp_boundaries, W, u_bcs, p_bcs, Q, theta_bcs_d, theta_bcs_n, theta_bcs_r, )
def coil_in_box(): mesh = Mesh("../meshes/2d/coil-in-box.xml") f = Constant(0.0) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < GMSH_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 2.5 - GMSH_EPS right_boundary = RightBoundary() class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < GMSH_EPS lower_boundary = LowerBoundary() class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 0.4 - GMSH_EPS upper_boundary = UpperBoundary() class CoilBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and x[0] > GMSH_EPS and x[0] < 2.5 - GMSH_EPS and x[1] > GMSH_EPS and x[1] < 0.4 - GMSH_EPS ) coil_boundary = CoilBoundary() # heater_temp = 380.0 # room_temp = 293.0 # bcs = [(coil_boundary, heater_temp), # (left_boundary, room_temp), # (right_boundary, room_temp), # (upper_boundary, room_temp), # (lower_boundary, room_temp) # ] boundaries = {} boundaries["left"] = left_boundary boundaries["right"] = right_boundary boundaries["upper"] = upper_boundary boundaries["lower"] = lower_boundary boundaries["coil"] = coil_boundary boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0) left_boundary.mark(boundaries, 1) right_boundary.mark(boundaries, 2) upper_boundary.mark(boundaries, 3) lower_boundary.mark(boundaries, 4) coil_boundary.mark(boundaries, 5) boundary_indices = {"left": 1, "right": 2, "top": 3, "bottom": 4, "coil": 5} theta0 = Constant(293.0) return mesh, f, boundaries, boundary_indices, theta0
def inside(self, x, on_boundary): return (between(x[0], (-w_wg / 2, w_wg / 2)) and between(x[1], (-h_wg / 2, h_wg / 2))) domain = Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2)) domain.set_subdomain( 1, Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2))) domain.set_subdomain( 2, Rectangle(Point(-w_wg / 2, -h_wg / 2), Point(w_wg / 2, h_wg / 2))) mesh = generate_mesh(domain, res) mesh.init() # Initialize mesh function for interior domains waveguide = Waveguide() domains = MeshFunction("size_t", mesh, 2) domains.set_all(0) waveguide.mark(domains, 1) boundary = InternalBoundary(domains, 1, 0) normal = boundary.normal midpoints = boundary.midpoints plt.quiver(midpoints[:, 0], midpoints[:, 1], normal[:, 0], normal[:, 1], color='r') plt.show()
class Crucible: def __init__(self): GMSH_EPS = 1.0e-15 # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once points, cells, point_data, cell_data, _ = meshes.crucible_with_coils.generate( ) # Convert the cell data to 'uint' so we can pick a size_t MeshFunction # below as usual. for k0 in cell_data: for k1 in cell_data[k0]: cell_data[k0][k1] = numpy.array(cell_data[k0][k1], dtype=numpy.dtype("uint")) with TemporaryDirectory() as temp_dir: tmp_filename = os.path.join(temp_dir, "test.xml") meshio.write_points_cells( tmp_filename, points, cells, cell_data=cell_data, file_format="dolfin-xml", ) self.mesh = Mesh(tmp_filename) self.subdomains = MeshFunction( "size_t", self.mesh, os.path.join(temp_dir, "test_gmsh:physical.xml")) self.subdomain_materials = { 1: my_materials.porcelain, 2: materials.argon, 3: materials.gallium_arsenide_solid, 4: materials.gallium_arsenide_liquid, 27: materials.air, } # coils for k in range(5, 27): self.subdomain_materials[k] = my_materials.ek90 # Define the subdomains which together form a single coil. self.coil_domains = [ [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23], [24, 25, 26], ] self.wpi = 4 self.submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi) # http://fenicsproject.org/qa/2026/submesh-workaround-for-parallel-computation # submesh_parallel_bug_fixed = False # if submesh_parallel_bug_fixed: # submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi) # else: # # To get the mesh in parallel, we need to read it in from a file. # # Writing out can only happen in serial mode, though. :/ # base = os.path.join(current_path, # '../../meshes/2d/crucible-with-coils-submesh' # ) # filename = base + '.xml' # if not os.path.isfile(filename): # warnings.warn( # 'Submesh file \'{}\' does not exist. Creating... '.format( # filename # )) # if MPI.size(mpi_comm_world()) > 1: # raise RuntimeError( # 'Can only write submesh in serial mode.' # ) # submesh_workpiece = \ # SubMesh(self.mesh, self.subdomains, self.wpi) # output_stream = File(filename) # output_stream << submesh_workpiece # # Read the mesh # submesh_workpiece = Mesh(filename) coords = self.submesh_workpiece.coordinates() ymin = min(coords[:, 1]) ymax = max(coords[:, 1]) # Find the top right point. k = numpy.argmax(numpy.sum(coords, 1)) topright = coords[k, :] # Initialize mesh function for boundary domains class Left(SubDomain): def inside(self, x, on_boundary): # Explicitly exclude the lowest and the highest point of the # symmetry axis. # It is necessary for the consistency of the pressure-Poisson # system in the Navier-Stokes solver that the velocity is # exactly 0 at the boundary r>0. Hence, at the corner points # (r=0, melt-crucible, melt-crystal) we must enforce u=0 # already and cannot have a component in z-direction. return (on_boundary and x[0] < GMSH_EPS and x[1] < ymax - GMSH_EPS and x[1] > ymin + GMSH_EPS) class Crucible(SubDomain): def inside(self, x, on_boundary): return on_boundary and ( (x[0] > GMSH_EPS and x[1] < ymax - GMSH_EPS) or (x[0] > topright[0] - GMSH_EPS and x[1] > topright[1] - GMSH_EPS) or (x[0] < GMSH_EPS and x[1] < ymin + GMSH_EPS)) # At the top right part (boundary melt--gas), slip is allowed, so only # n.u=0 is enforced. Very weirdly, the PPE is consistent if and only if # the end points of UpperRight are in UpperRight. This contrasts # Left(), where the end points must NOT belong to Left(). Judging from # the experiments, these settings do the right thing. # TODO try to better understand the PPE system/dolfin's boundary # settings class Upper(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > ymax - GMSH_EPS class UpperRight(SubDomain): def inside(self, x, on_boundary): return (on_boundary and x[1] > ymax - GMSH_EPS and x[0] > 0.038 - GMSH_EPS) # The crystal boundary is taken to reach up to 0.038 where the # Dirichlet boundary data is about the melting point of the crystal, # 1511K. This setting gives pretty acceptable results when there is no # convection except the one induced by buoyancy. Is there is any more # stirring going on, though, the end point of the crystal with its # fixed temperature of 1511K might be the hottest point globally. This # looks rather unphysical. # TODO check out alternatives class UpperLeft(SubDomain): def inside(self, x, on_boundary): return (on_boundary and x[1] > ymax - GMSH_EPS and x[0] < 0.038 + GMSH_EPS) left = Left() crucible = Crucible() upper_left = UpperLeft() upper_right = UpperRight() self.wp_boundaries = MeshFunction( "size_t", self.submesh_workpiece, self.submesh_workpiece.topology().dim() - 1, ) self.wp_boundaries.set_all(0) left.mark(self.wp_boundaries, 1) crucible.mark(self.wp_boundaries, 2) upper_right.mark(self.wp_boundaries, 3) upper_left.mark(self.wp_boundaries, 4) if DEBUG: from dolfin import plot, interactive plot(self.wp_boundaries, title="Boundaries") interactive() submesh_boundary_indices = { "left": 1, "crucible": 2, "upper right": 3, "upper left": 4, } # Boundary conditions for the velocity. # # [1] Incompressible flow and the finite element method; volume two; # Isothermal Laminar Flow; # P.M. Gresho, R.L. Sani; # # For the choice of function space, [1] says: # "In 2D, the triangular elements P_2^+P_1 and P_2^+P_{-1} are very # good [...]. [...] If you wish to avoid bubble functions on # triangular elements, P_2P_1 is not bad, and P_2(P_1+P_0) is even # better [...]." # # It turns out that adding the bubble space significantly hampers the # convergence of the Stokes solver and also considerably increases the # time it takes to construct the Jacobian matrix of the Navier--Stokes # problem if no optimization is applied. V_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 2) with_bubbles = False if with_bubbles: V_element += FiniteElement("B", self.submesh_workpiece.ufl_cell(), 2) self.W_element = MixedElement(3 * [V_element]) self.W = FunctionSpace(self.submesh_workpiece, self.W_element) rot0 = Expression(("0.0", "0.0", "-2*pi*x[0] * 5.0/60.0"), degree=1) # rot0 = (0.0, 0.0, 0.0) rot1 = Expression(("0.0", "0.0", "2*pi*x[0] * 5.0/60.0"), degree=1) self.u_bcs = [ DirichletBC(self.W, rot0, crucible), DirichletBC(self.W.sub(0), 0.0, left), DirichletBC(self.W.sub(2), 0.0, left), # Make sure that u[2] is 0 at r=0. DirichletBC(self.W, rot1, upper_left), DirichletBC(self.W.sub(1), 0.0, upper_right), ] self.p_bcs = [] self.P_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 1) self.P = FunctionSpace(self.submesh_workpiece, self.P_element) self.Q_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 2) self.Q = FunctionSpace(self.submesh_workpiece, self.Q_element) # Dirichlet. # This is a bit of a tough call since the boundary conditions need to # be read from a Tecplot file here. filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/crucible-boundary.dat") data = tecplot_reader.read(filename) RZ = numpy.c_[data["ZONE T"]["node data"]["r"], data["ZONE T"]["node data"]["z"]] T_vals = data["ZONE T"]["node data"]["temp. [K]"] class TecplotDirichletBC(Expression): def eval(self, value, x): # Find on which edge x sits, and raise exception if it doesn't. edge_found = False for edge in data["ZONE T"]["element data"]: # Given a point X and an edge X0--X1, # # (1 - theta) X0 + theta X1, # # the minimum distance is assumed for # # argmin_theta ||(1-theta) X0 + theta X1 - X||^2 # = <X1 - X0, X - X0> / ||X1 - X0||^2. # # If the distance is 0 and 0<=theta<=1, we found the edge. # # Note that edges are 1-based in Tecplot. X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1 - X0, x - X0) / numpy.dot( X1 - X0, X1 - X0) diff = (1.0 - theta) * X0 + theta * X1 - x if (numpy.dot(diff, diff) < 1.0e-10 and 0.0 <= theta and theta <= 1.0): # Linear interpolation of the temperature value. value[0] = (1.0 - theta) * T_vals[ edge[0] - 1] + theta * T_vals[edge[1] - 1] edge_found = True break # This class is supposed to be used for Dirichlet boundary # conditions. For some reason, FEniCS also evaluates # DirichletBC objects at coordinates which do not sit on the # boundary, see # <http://fenicsproject.org/qa/1033/dirichletbc-expressions-evaluated-away-from-the-boundary>. # The assigned values have no meaning though, so not assigning # values[0] here is okay. # # from matplotlib import pyplot as pp # pp.plot(x[0], x[1], 'xg') if not edge_found: value[0] = 0.0 if False: warnings.warn( "Coordinate ({:e}, {:e}) doesn't sit on edge.". format(x[0], x[1])) # pp.plot(RZ[:, 0], RZ[:, 1], '.k') # pp.plot(x[0], x[1], 'xr') # pp.show() # raise RuntimeError('Input coordinate ' # '{} is not on boundary.'.format(x)) return tecplot_dbc = TecplotDirichletBC(degree=5) self.theta_bcs_d = [DirichletBC(self.Q, tecplot_dbc, upper_left)] self.theta_bcs_d_strict = [ DirichletBC(self.Q, tecplot_dbc, upper_right), DirichletBC(self.Q, tecplot_dbc, crucible), DirichletBC(self.Q, tecplot_dbc, upper_left), ] # Neumann dTdr_vals = data["ZONE T"]["node data"]["dTempdx [K/m]"] dTdz_vals = data["ZONE T"]["node data"]["dTempdz [K/m]"] class TecplotNeumannBC(Expression): def eval(self, value, x): # Same problem as above: This expression is not only evaluated # at boundaries. for edge in data["ZONE T"]["element data"]: X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1 - X0, x - X0) / numpy.dot( X1 - X0, X1 - X0) dist = numpy.linalg.norm((1 - theta) * X0 + theta * X1 - x) if dist < 1.0e-5 and 0.0 <= theta and theta <= 1.0: value[0] = (1 - theta) * dTdr_vals[ edge[0] - 1] + theta * dTdr_vals[edge[1] - 1] value[1] = (1 - theta) * dTdz_vals[ edge[0] - 1] + theta * dTdz_vals[edge[1] - 1] break return def value_shape(self): return (2, ) tecplot_nbc = TecplotNeumannBC(degree=5) n = FacetNormal(self.Q.mesh()) self.theta_bcs_n = { submesh_boundary_indices["upper right"]: dot(n, tecplot_nbc), submesh_boundary_indices["crucible"]: dot(n, tecplot_nbc), } self.theta_bcs_r = {} # It seems that the boundary conditions from above are inconsistent in # that solving with Dirichlet overall and mixed Dirichlet-Neumann give # different results; the value *cannot* correspond to one solution. # From looking at the solutions, the pure Dirichlet setting appears # correct, so extract the Neumann values directly from that solution. # Pick fixed coefficients roughly at the temperature that we expect. # This could be made less magic by having the coefficients depend on # theta and solving the quasilinear equation. temp_estimate = 1550.0 # Get material parameters wp_material = self.subdomain_materials[self.wpi] if isinstance(wp_material.specific_heat_capacity, float): cp = wp_material.specific_heat_capacity else: cp = wp_material.specific_heat_capacity(temp_estimate) if isinstance(wp_material.density, float): rho = wp_material.density else: rho = wp_material.density(temp_estimate) if isinstance(wp_material.thermal_conductivity, float): k = wp_material.thermal_conductivity else: k = wp_material.thermal_conductivity(temp_estimate) reference_problem = cyl_heat.Heat( self.Q, convection=None, kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=self.theta_bcs_d_strict, ) theta_reference = reference_problem.solve_stationary() theta_reference.rename("theta", "temperature (Dirichlet)") # Create equivalent boundary conditions from theta_ref. This # makes sure that the potentially expensive Expression evaluation in # theta_bcs_* is replaced by something reasonably cheap. self.theta_bcs_d = [ DirichletBC(bc.function_space(), theta_reference, bc.domain_args[0]) for bc in self.theta_bcs_d ] # Adapt Neumann conditions. n = FacetNormal(self.Q.mesh()) self.theta_bcs_n = { k: dot(n, grad(theta_reference)) # k: Constant(1000.0) for k in self.theta_bcs_n } if DEBUG: # Solve the heat equation with the mixed Dirichlet-Neumann # boundary conditions and compare it to the Dirichlet-only # solution. theta_new = Function(self.Q, name="temperature (Neumann + Dirichlet)") from dolfin import Measure ds_workpiece = Measure("ds", subdomain_data=self.wp_boundaries) heat = cyl_heat.Heat( self.Q, convection=None, kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=self.theta_bcs_d, neumann_bcs=self.theta_bcs_n, robin_bcs=self.theta_bcs_r, my_ds=ds_workpiece, ) theta_new = heat.solve_stationary() theta_new.rename("theta", "temperature (Neumann + Dirichlet)") from dolfin import plot, interactive, errornorm print("||theta_new - theta_ref|| = {:e}".format( errornorm(theta_new, theta_reference))) plot(theta_reference) plot(theta_new) plot(theta_reference - theta_new, title="theta_ref - theta_new") interactive() self.background_temp = 1400.0 # self.omega = 2 * pi * 10.0e3 self.omega = 2 * pi * 300.0 return
def __init__(self, mesh: df.Mesh, time: df.Constant, M_i: tp.Union[df.Expression, tp.Dict[int, df.Expression]], M_e: tp.Union[df.Expression, tp.Dict[int, df.Expression]], I_s: tp.Union[df.Expression, tp.Dict[int, df.Expression]] = None, I_a: tp.Union[df.Expression, tp.Dict[int, df.Expression]] = None, ect_current: tp.Dict[int, df.Expression] = None, v_: df.Function = None, cell_domains: df.MeshFunction = None, facet_domains: df.MeshFunction = None, dirichlet_bc: tp.List[tp.Tuple[df.Expression, int]] = None, dirichlet_bc_v: tp.List[tp.Tuple[df.Expression, int]] = None, periodic_domain: df.SubDomain = None, parameters: df.Parameters = None) -> None: """Initialise solverand check all parametersare correct. NB! The periodic domain has to be set in the cellsolver too. """ self._timestep = None comm = df.MPI.comm_world rank = df.MPI.rank(comm) msg = "Expecting mesh to be a Mesh instance, not {}".format(mesh) assert isinstance(mesh, df.Mesh), msg msg = "Expecting time to be a Constant instance (or None)." assert isinstance(time, df.Constant) or time is None, msg msg = "Expecting parameters to be a Parameters instance (or None)" assert isinstance(parameters, df.Parameters) or parameters is None, msg self._nullspace_basis = None # Store input self._mesh = mesh self._time = time # Initialize and update parameters if given self._parameters = self.default_parameters() if parameters is not None: self._parameters.update(parameters) if self._parameters["Chi"] == -1 or self._parameters["Cm"] == -1: raise ValueError( "Need Chi and Cm to be specified explicitly throug the parameters." ) # Set-up function spaces k = self._parameters["polynomial_degree"] Ve = df.FiniteElement("CG", self._mesh.ufl_cell(), k) V = df.FunctionSpace(self._mesh, "CG", k, constrained_domain=periodic_domain) Ue = df.FiniteElement("CG", self._mesh.ufl_cell(), k) if self._parameters["linear_solver_type"] == "direct": Re = df.FiniteElement("R", self._mesh.ufl_cell(), 0) _element = df.MixedElement((Ve, Ue, Re)) self.VUR = df.FunctionSpace(mesh, _element, constrained_domain=periodic_domain) else: _element = df.MixedElement((Ve, Ue)) self.VUR = df.FunctionSpace(mesh, _element, constrained_domain=periodic_domain) self.V = V if cell_domains is None: cell_domains = df.MeshFunction("size_t", mesh, self._mesh.geometry().dim()) cell_domains.set_all(0) # Chech that it is indeed a cell function. cell_dim = cell_domains.dim() mesh_dim = self._mesh.geometry().dim() msg = "Got {cell_dim}, expected {mesh_dim}.".format(cell_dim=cell_dim, mesh_dim=mesh_dim) assert cell_dim == mesh_dim, msg self._cell_domains = cell_domains if facet_domains is None: facet_domains = df.MeshFunction("size_t", mesh, self._mesh.geometry().dim() - 1) facet_domains.set_all(0) # Check that it is indeed a facet function. facet_dim = facet_domains.dim() msg = "Got {facet_dim}, expected {mesh_dim}.".format( facet_dim=facet_dim, mesh_dim=mesh_dim - 1) assert facet_dim == mesh_dim - 1, msg self._facet_domains = facet_domains # Gather all cell keys on all processes. Greatly simplifies things cell_keys = set(self._cell_domains.array()) all_cell_keys = comm.allgather(cell_keys) all_cell_keys = reduce(or_, all_cell_keys) # If Mi is not dict, make dict if not isinstance(M_i, dict): M_i = {int(i): M_i for i in all_cell_keys} else: # Check that the keys match the cell function M_i_keys = set(M_i.keys()) msg = "Got {M_i_keys}, expected {cell_keys}.".format( M_i_keys=M_i_keys, cell_keys=all_cell_keys) assert M_i_keys == all_cell_keys, msg # If Me is not dict, make dict if not isinstance(M_e, dict): M_e = {int(i): M_e for i in all_cell_keys} else: # Check that the keys match the cell function M_e_keys = set(M_e.keys()) msg = "Got {M_e_keys}, expected {cell_keys}.".format( M_e_keys=M_e_keys, cell_keys=all_cell_keys) assert M_e_keys == all_cell_keys, msg self._M_i = M_i self._M_e = M_e # Store source terms if I_s is not None and not isinstance(I_s, dict): I_s = {key: I_s for key in all_cell_keys} self._I_s = I_s if I_a is not None and not isinstance(I_a, dict): I_a = {key: I_a for key in all_cell_keys} self._I_a = I_a # Set the ECT current, Note, it myst depend on `time` to be updated if ect_current is not None: ect_tags = set(ect_current.keys()) facet_tags = set(self._facet_domains.array()) msg = "{} not in facet domains ({}).".format(ect_tags, facet_tags) assert ect_tags <= facet_tags, msg self._ect_current = ect_current # Set-up solution fields: if v_ is None: self.merger = df.FunctionAssigner(V, self.VUR.sub(0)) self.v_ = df.Function(V, name="v_") else: # df.debug("Experimental: v_ shipped from elsewhere.") self.merger = None self.v_ = v_ self.vur = df.Function(self.VUR, name="vur") # Set Dirichlet bcs for the transmembrane potential self._bcs = [] if dirichlet_bc_v is not None: for function, marker in dirichlet_bc_v: self._bcs.append( df.DirichletBC(self.VUR.sub(0), function, self._facet_domains, marker)) # Set Dirichlet bcs for the extra cellular potential if dirichlet_bc is not None: for function, marker in dirichlet_bc: self._bcs.append( df.DirichletBC(self.VUR.sub(1), function, self._facet_domains, marker))
pres = 400 k = 1 # Directory for output outdir_base = './../../results/MovingMesh/' mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), nx, ny) n = FacetNormal(mesh) outfile = File(mesh.mpi_comm(), outdir_base+"psi_h.pvd") V = VectorFunctionSpace(mesh, 'DG', 2) Vcg = VectorFunctionSpace(mesh, 'CG', 1) boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1) boundaries.set_all(0) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) # Create function spaces Q_E_Rho = FiniteElement("DG", mesh.ufl_cell(), k) T_1 = FunctionSpace(mesh, 'DG', 0) Qbar_E = FiniteElement("DGT", mesh.ufl_cell(), k) Q_Rho = FunctionSpace(mesh, Q_E_Rho) Qbar = FunctionSpace(mesh, Qbar_E) phih, phih0 = Function(Q_Rho), Function(Q_Rho) phibar = Function(Qbar) # Advective velocity # Swirling deformation advection (see LeVeque)
def setup_geometry(interior_circle=True, num_mesh_refinements=0): # Generate mesh xmin, xmax = 0.0, 4.0 ymin, ymax = 0.0, 1.0 mesh_resolution = 30 geometry1 = Rectangle(Point(xmin, ymin), Point(xmax, ymax)) center = Point(0.5, 0.5) r = 0.1 side_length = 0.1 if interior_circle: geometry2 = Circle(center, r) else: l2 = side_length / 2 geometry2 = Rectangle(Point(center[0] - l2, center[1] - l2), Point(center[0] + l2, center[1] + l2)) mesh = generate_mesh(geometry1 - geometry2, mesh_resolution) # Refine mesh around the interior boundary for i in range(0, num_mesh_refinements): cell_markers = MeshFunction("bool", mesh, mesh.topology().dim()) for c in cells(mesh): p = c.midpoint() cell_markers[c] = (abs(p[0] - .5) < .5 and abs(p[1] - .5) < .3 and c.diameter() > .1) or c.diameter() > .2 mesh = refine(mesh, cell_markers) # Mark regions for boundary conditions eps = 1e-5 # Part of the boundary with zero pressure om = Expression("x[0] > XMAX - eps ? 1. : 0.", XMAX=xmax, eps=eps, degree=1) # Part of the boundary with prescribed velocity im = Expression("x[0] < XMIN + eps ? 1. : 0.", XMIN=xmin, eps=eps, degree=1) # Part of the boundary with zero velocity nm = Expression("x[0] > XMIN + eps && x[0] < XMAX - eps ? 1. : 0.", XMIN=xmin, XMAX=xmax, eps=eps, degree=1) # Define interior boundary class InteriorBoundary(SubDomain): def inside(self, x, on_boundary): # Compute squared distance to interior object midpoint d2 = (x[0] - center[0])**2 + (x[1] - center[1])**2 return on_boundary and d2 < (2 * r)**2 # Create mesh function over the cell facets sub_domains = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) # Mark all facets as sub domain 0 sub_domains.set_all(0) # Mark interior boundary facets as sub domain 1 interior_boundary = InteriorBoundary() interior_boundary.mark(sub_domains, 1) return mesh, om, im, nm, ymax, sub_domains
def femsolve(): ''' Bilineaarinen muoto: a(u,v) = L(v) a(u,v) = (inner(grad(u), grad(v)) + u*v)*dx L(v) = f*v*dx - g*v*ds g(x) = -du/dx = -u1, x = x1 u(x0) = u0 Omega = {xeR|x0<=x<=x1} ''' from dolfin import UnitInterval, FunctionSpace, DirichletBC, TrialFunction from dolfin import TestFunction, grad, Constant, Function, solve, inner, dx, ds from dolfin import MeshFunction, assemble import dolfin # from dolfin import set_log_level, PROCESS # Create mesh and define function space mesh = UnitInterval(30) V = FunctionSpace(mesh, 'Lagrange', 2) boundaries = MeshFunction('uint', mesh, mesh.topology().dim()-1) boundaries.set_all(0) class Left(dolfin.SubDomain): def inside(self, x, on_boundary): tol = 1E-14 # tolerance for coordinate comparisons return on_boundary and abs(x[0]) < tol class Right(dolfin.SubDomain): def inside(self, x, on_boundary): return dolfin.near(x[0], 1.0) left = Left() right = Right() left.mark(boundaries, 1) right.mark(boundaries, 2) # def u0_boundary(x): # return abs(x[0]) < tol # # bc = DirichletBC(V, Constant(u0), lambda x: abs(x[0]) < tol) bcs = [DirichletBC(V, Constant(u0), boundaries, 1)] # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = (inner(grad(u), grad(v)) + u*v)*dx g = Constant(-u1) L = Constant(f)*v*dx - g*v*ds(2) # set_log_level(PROCESS) # Compute solution A = assemble(a, exterior_facet_domains=boundaries) b = assemble(L, exterior_facet_domains=boundaries) for bc in bcs: bc.apply(A, b) u = Function(V) solve(A, u.vector(), b, 'lu') coor = mesh.coordinates() u_array = u.vector().array() a = [] b = [] for i in range(mesh.num_vertices()): a.append(coor[i]) b.append(u_array[i]) print('u(%3.2f) = %0.14E'%(coor[i],u_array[i])) import numpy as np np.savez('fem',a,b)
class Solver(object): """ First order FEM with CR elements. Nonconforming CR elements give lower bounds for eigenvalues after apropriate postprocessing is applied. """ def __init__(self, mesh, num, denom, method="CR"): """ Assemble matrices and cache matrices. """ self.V = FunctionSpace(mesh, method, 1) # save coordinates of DOFs self.dofs = np.reshape(self.V.dofmap().tabulate_all_coordinates(mesh), (-1, 2)) u = TrialFunction(self.V) v = TestFunction(self.V) self.boundary = MeshFunction("size_t", mesh, 1) # assemble matrices a = inner(grad(u), grad(v)) * dx b = u * v * dx self.A = uBLASSparseMatrix() self.A = assemble(a, tensor=self.A) self.A.compress() self.B = uBLASSparseMatrix() self.B = assemble(b, tensor=self.B) self.B.compress() size = mesh.size(2) # cell diameter calculation self.H2 = (num ** 2 + denom ** 2) * 1.0 / size # print "Theoretical cell diameter: ", sqrt(self.H2) # print "FEniCS calculated: ", mesh.hmax() # Matrices have rational entries. We can rescale to get integers # and save as scipy matrices scaleB = 6.0*size/num/denom self.scaleB = scaleB self.B *= scaleB r, c, val = self.B.data() val = np.round(val) self.B = sps.csr_matrix((val, c, r)) # check if B is diagonal assert len(self.B.diagonal()) == self.B.nnz # find B inverse self.Binv = sps.csr_matrix((1.0/val, c, r)) scaleA = 1.0*num*denom/2 self.scaleA = scaleA self.A *= scaleA r, c, val = self.A.data() self.A = sps.csr_matrix((np.round(val), c, r)) self.scale = scaleA/scaleB print 'scaling A by: ', scaleA print 'scaling B by: ', scaleB print 'eigenvalues scale by:', self.scale def solve(self, dirichlet=lambda x: False, plotted=None): """ Find eigenvalues given a boundary condition function. dirichlet is a function returning True if x is on Dirichlet BC. """ self.boundary.set_all(0) d = Dirichlet() d.init(dirichlet) d.mark(self.boundary, 1) if plotted is not None: plotted.plot(self.boundary) # plotted.write_png() # indices for non-Dirichlet rows/columns indices = np.nonzero(np.apply_along_axis( lambda x: not dirichlet(x), 1, self.dofs))[0] # remove Dirichlet rows and columns from A self.AA = (self.A[indices, :]).tocsc()[:, indices] # remove Dirichlet rows and columns from B self.BB = (self.B[indices, :]).tocsc()[:, indices] self.BBinv = (self.Binv[indices, :]).tocsc()[:, indices] # solve using scipy eigs, eigfs = ssl.eigsh(self.AA, k=2, M=self.BB, sigma=0, which='LM') self.raweigs = [eigs[0], eigs[1]] eig = eigs[0] # turn eigf into a function eigf = np.array(eigfs[:, 0]).flatten() # we were solving only for some dofs, rest is 0 # u = Function(self.V) # u.vector()[:] = 0 # u.vector()[indices] = eigf # find algebraic residual # both L2 norm of u and B norm of eigf should equal 1 # print assemble(u*u*dx), self.BB.dot(eigf).dot(eigf) res = self.AA.dot(eigf) - eig * self.BB.dot(eigf) resnorm = np.sqrt(self.BBinv.dot(res).dot(res)) self.residual = [resnorm, 0] # apply Carstensen-Gedicke transformations to eig # # kappa^2 less than 0.1932 eig = (eig - resnorm) / (1 + 0.1932 * (eig - resnorm) * self.H2 / self.scale) # scale back the eigenvalue eig = eig/self.scale # find residual for the second eigenvalue (for gap calculations) eigf = np.array(eigfs[:, 1]).flatten() res = self.AA.dot(eigf) - eigs[1] * self.BB.dot(eigf) resnorm = np.sqrt(self.BBinv.dot(res).dot(res)) self.residual[1] = resnorm # return (eig, u) # pair (eigenvalue,eigenfunctions) return (eig, None) # pair (eigenvalue,eigenfunctions)