def test_raises(meshes_p1): mesh1, mesh2 = meshes_p1[:2] # Wrong FE family V = VectorFunctionSpace(mesh2, "Discontinuous Lagrange", 1) c = Function(V) with pytest.raises(RuntimeError): get_coordinates(c, mesh2.geometry()) with pytest.raises(RuntimeError): set_coordinates(mesh2.geometry(), c) # Wrong value rank V = FunctionSpace(mesh2, "Lagrange", 1) c = Function(V) with pytest.raises(RuntimeError): get_coordinates(c, mesh2.geometry()) with pytest.raises(RuntimeError): set_coordinates(mesh2.geometry(), c) # Wrong value shape V = VectorFunctionSpace(mesh2, "Lagrange", mesh2.geometry().degree(), dim=mesh2.geometry().dim() - 1) c = Function(V) with pytest.raises(RuntimeError): get_coordinates(c, mesh2.geometry()) with pytest.raises(RuntimeError): set_coordinates(mesh2.geometry(), c) # Non-matching degree V = VectorFunctionSpace(mesh2, "Lagrange", mesh2.geometry().degree() + 1) c = Function(V) with pytest.raises(RuntimeError): get_coordinates(c, mesh2.geometry()) with pytest.raises(RuntimeError): set_coordinates(mesh2.geometry(), c)
def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym( grad(v))) * Identity(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc0 = Function(V) with bc0.vector().localForm() as bc_local: bc_local.set(0.0) def boundary(x, only_boundary): return [only_boundary] * x.shape(0) bc = DirichletBC(V.sub(0), bc0, boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector( (1.0, 1.0)), v) * dx # Assemble linear algebra objects A = assemble_matrix(a, [bc]) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector()) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector(), b)
def test_vector_p1_3d(): meshc = UnitCubeMesh(MPI.comm_world, 2, 3, 4) meshf = UnitCubeMesh(MPI.comm_world, 3, 4, 5) Vc = VectorFunctionSpace(meshc, ("CG", 1)) Vf = VectorFunctionSpace(meshf, ("CG", 1)) def u(x): values0 = x[:, 0] + 2.0 * x[:, 1] values1 = 4.0 * x[:, 0] values2 = 3.0 * x[:, 2] + x[:, 0] return np.stack([values0, values1, values2], axis=1) uc, uf = Function(Vc), Function(Vf) uc.interpolate(u) uf.interpolate(u) mat = PETScDMCollection.create_transfer_matrix(Vc._cpp_object, Vf._cpp_object) Vuc = Function(Vf) mat.mult(uc.vector, Vuc.vector) diff = Vuc.vector diff.axpy(-1, uf.vector) assert diff.norm() < 1.0e-12
def test_pointsource_vector_fs(mesh, point): """Tests point source when given constructor PointSource(V, point, mag) with a vector for a vector function space that isn't placed at a node for 1D, 2D and 3D. Global points given to constructor from rank 0 processor. """ rank = MPI.rank(mesh.mpi_comm()) V = VectorFunctionSpace(mesh, "CG", 1) v = TestFunction(V) b = assemble(dot(Constant([0.0] * mesh.geometry().dim()), v) * dx) if rank == 0: ps = PointSource(V, point, 10.0) else: ps = PointSource(V, []) ps.apply(b) # Checks array sums to correct value b_sum = b.sum() assert round(b_sum - 10.0 * V.num_sub_spaces()) == 0 # Checks point source is added to correct part of the array v2d = vertex_to_dof_map(V) for v in vertices(mesh): if near(v.midpoint().distance(point), 0.0): for spc_idx in range(V.num_sub_spaces()): ind = v2d[v.index() * V.num_sub_spaces() + spc_idx] if ind < len(b.get_local()): assert np.round(b.get_local()[ind] - 10.0) == 0
def test_pointsource_vector_fs(mesh, point): """Tests point source when given constructor PointSource(V, point, mag) with a vector for a vector function space that isn't placed at a node for 1D, 2D and 3D. Global points given to constructor from rank 0 processor. """ rank = MPI.rank(mesh.mpi_comm()) V = VectorFunctionSpace(mesh, "CG", 1) v = TestFunction(V) b = assemble(dot(Constant([0.0]*mesh.geometry().dim()), v)*dx) if rank == 0: ps = PointSource(V, point, 10.0) else: ps = PointSource(V, []) ps.apply(b) # Checks array sums to correct value b_sum = b.sum() assert round(b_sum - 10.0*V.num_sub_spaces()) == 0 # Checks point source is added to correct part of the array v2d = vertex_to_dof_map(V) for v in vertices(mesh): if near(v.midpoint().distance(point), 0.0): for spc_idx in range(V.num_sub_spaces()): ind = v2d[v.index()*V.num_sub_spaces() + spc_idx] if ind < len(b.get_local()): assert np.round(b.get_local()[ind] - 10.0) == 0
def get_spaces(mesh): """ Return an object of dolfin FunctionSpace, to be used in the optimization pipeline :param mesh: The mesh :type mesh: :py:class:`dolfin.Mesh` :returns: An object of functionspaces :rtype: object """ from dolfin import FunctionSpace, VectorFunctionSpace, TensorFunctionSpace # Make a dummy object spaces = Object() # A real space with scalars used for dolfin adjoint spaces.r_space = FunctionSpace(mesh, "R", 0) # A space for the strain fields spaces.strainfieldspace = VectorFunctionSpace(mesh, "CG", 1, dim=3) # A space used for scalar strains spaces.strainspace = VectorFunctionSpace(mesh, "R", 0, dim=3) # Spaces for the strain weights spaces.strain_weight_space = TensorFunctionSpace(mesh, "R", 0) return spaces
def cg1_cr_interpolation_matrix(mesh, constrained_domain=None): ''' Compute matrix that allows fast interpolation of CG1 function to Couzeix-Raviart space. ''' CG1 = VectorFunctionSpace(mesh, 'CG', 1, constrained_domain=constrained_domain) CR = VectorFunctionSpace(mesh, 'CR', 1, constrained_domain=constrained_domain) # Get the matrix with approximate sparsity as the interpolation matrix u = TrialFunction(CG1) v = TestFunction(CR) I = PETScMatrix() assemble(dot(u, v) * dx, tensor=I) # Fill the interpolation matrix d = mesh.geometry().dim() compiled_i_module.compute_cg1_cr_interpolation_matrix(I, d) return I
def test_vector_p1_3d(): meshc = UnitCubeMesh(MPI.comm_world, 2, 3, 4) meshf = UnitCubeMesh(MPI.comm_world, 3, 4, 5) Vc = VectorFunctionSpace(meshc, ("CG", 1)) Vf = VectorFunctionSpace(meshf, ("CG", 1)) @function.expression.numba_eval def expr_eval(values, x, cell_idx): values[:, 0] = x[:, 0] + 2.0 * x[:, 1] values[:, 1] = 4.0 * x[:, 0] values[:, 2] = 3.0 * x[:, 2] + x[:, 0] u = Expression(expr_eval, shape=(3, )) uc = interpolate(u, Vc) uf = interpolate(u, Vf) mat = PETScDMCollection.create_transfer_matrix(Vc._cpp_object, Vf._cpp_object) Vuc = Function(Vf) mat.mult(uc.vector(), Vuc.vector()) diff = Vuc.vector() diff.axpy(-1, uf.vector()) assert diff.norm() < 1.0e-12
def gauss_divergence(u, mesh=None): ''' This function uses Gauss divergence theorem to compute divergence of u inside the cell by integrating normal fluxes across the cell boundary. If u is a vector or tensor field the result of computation is diverence of u in the cell center = DG0 scalar/vector function. For scalar fields, the result is grad(u) = DG0 vector function. The fluxes are computed by midpoint rule and as such the computed divergence is exact for linear fields. ''' # Require u to be GenericFunction assert isinstance(u, GenericFunction) # Require u to be scalar/vector/rank 2 tensor rank = u.value_rank() assert rank in [0, 1, 2] # For now, there is no support for manifolds if mesh is None: _mesh = u.function_space().mesh() else: _mesh = mesh tdim = _mesh.topology().dim() gdim = _mesh.geometry().dim() assert tdim == gdim for i in range(rank): assert u.value_dimension(i) == gdim # Based on rank choose the type of CR1 space where u should be interpolated # to to get the midpoint values + choose the type of DG0 space for # divergence if rank == 1: DG = FunctionSpace(_mesh, 'DG', 0) CR = VectorFunctionSpace(_mesh, 'CR', 1) else: DG = VectorFunctionSpace(_mesh, 'DG', 0) if rank == 0: CR = FunctionSpace(_mesh, 'CR', 1) else: CR = TensorFunctionSpace(_mesh, 'CR', 1) divu = Function(DG) _u = interpolate(u, CR) # Use Gauss theorem cell by cell to get the divergence. The implementation # is based on divergence(vector) = scalar and so the spaces for these # two need to be provided if rank == 1: pass # CR, DG are correct already else: DG = FunctionSpace(_mesh, 'DG', 0) CR = VectorFunctionSpace(_mesh, 'CR', 1) compiled_cr_module.cr_divergence(divu, _u, DG, CR) return divu
def __init__(self, u, name="Assigned Vector Function"): self.u = u assert isinstance(u, ListTensor) V = u[0].function_space() mesh = V.mesh() family = V.ufl_element().family() degree = V.ufl_element().degree() constrained_domain = V.dofmap().constrained_domain Vv = VectorFunctionSpace(mesh, family, degree, constrained_domain=constrained_domain) Function.__init__(self, Vv, name=name) self.fa = [FunctionAssigner(Vv.sub(i), V) for i, _u in enumerate(u)]
def get_function_spaces_1(): return ( lambda mesh: FunctionSpace(mesh, "Lagrange", 1), pytest.mark.slow(lambda mesh: FunctionSpace(mesh, "Lagrange", 2)), lambda mesh: VectorFunctionSpace(mesh, "Lagrange", 1), pytest.mark.slow(lambda mesh: VectorFunctionSpace(mesh, "Lagrange", 2)), pytest.mark.slow(lambda mesh: TensorFunctionSpace(mesh, "Lagrange", 1)), pytest.mark.slow(lambda mesh: TensorFunctionSpace(mesh, "Lagrange", 2)), lambda mesh: StokesFunctionSpace(mesh, "Lagrange", 1), pytest.mark.slow(lambda mesh: StokesFunctionSpace(mesh, "Lagrange", 2)), lambda mesh: FunctionSpace(mesh, "Real", 0), pytest.mark.slow(lambda mesh: VectorFunctionSpace(mesh, "Real", 0)), pytest.mark.slow(lambda mesh: FunctionAndRealSpace(mesh, "Lagrange", 1)), pytest.mark.slow(lambda mesh: FunctionAndRealSpace(mesh, "Lagrange", 2)) )
def __init__(self, V, subdomains, shape_parametrization_expression): # Store dolfin data structure related to the geometrical parametrization self.mesh = subdomains.mesh() self.subdomains = subdomains self.reference_coordinates = self.mesh.coordinates().copy() self.deformation_V = VectorFunctionSpace(self.mesh, "Lagrange", 1) self.subdomain_id_to_deformation_dofs = dict() # from int to list for cell in cells(self.mesh): subdomain_id = int( self.subdomains[cell] ) - 1 # tuple start from 0, while subdomains from 1 if subdomain_id not in self.subdomain_id_to_deformation_dofs: self.subdomain_id_to_deformation_dofs[subdomain_id] = list() dofs = self.deformation_V.dofmap().cell_dofs(cell.index()) for dof in dofs: global_dof = self.deformation_V.dofmap().local_to_global_index( dof) if (self.deformation_V.dofmap().ownership_range()[0] <= global_dof and global_dof < self.deformation_V.dofmap().ownership_range()[1]): self.subdomain_id_to_deformation_dofs[subdomain_id].append( dof) # In parallel some subdomains may not be present on all processors. Fill in # the dict with empty lists if that is the case mpi_comm = self.mesh.mpi_comm() if not has_pybind11(): mpi_comm = mpi_comm.tompi4py() min_subdomain_id = mpi_comm.allreduce(min( self.subdomain_id_to_deformation_dofs.keys()), op=MIN) max_subdomain_id = mpi_comm.allreduce(max( self.subdomain_id_to_deformation_dofs.keys()), op=MAX) for subdomain_id in range(min_subdomain_id, max_subdomain_id + 1): if subdomain_id not in self.subdomain_id_to_deformation_dofs: self.subdomain_id_to_deformation_dofs[subdomain_id] = list() # Subdomain numbering is contiguous assert min(self.subdomain_id_to_deformation_dofs.keys()) == 0 assert len(self.subdomain_id_to_deformation_dofs.keys()) == max( self.subdomain_id_to_deformation_dofs.keys()) + 1 # Store the shape parametrization expression self.shape_parametrization_expression = shape_parametrization_expression assert len(self.shape_parametrization_expression) == len( self.subdomain_id_to_deformation_dofs.keys()) # Prepare storage for displacement expression, computed by init() self.displacement_expression = list()
def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym( grad(v))) * Identity(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc0 = Function(V) bc = DirichletBC(V.sub(0), bc0, lambda x, on_boundary: on_boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector( (1.0, 1.0)), v) * dx # Assemble linear algebra objects A, b = assemble_system(a, L, bc) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector()) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector(), b)
def test_read_write_p2_function(tempdir): mesh = cpp.generation.UnitDiscMesh.create(MPI.comm_world, 3, cpp.mesh.GhostMode.none) cmap = fem.create_coordinate_map(mesh.ufl_domain()) mesh.geometry.coord_mapping = cmap Q = FunctionSpace(mesh, ("Lagrange", 2)) F = Function(Q) if has_petsc_complex: F.interpolate(Expression("x[0] + j*x[0]", degree=1)) else: F.interpolate(Expression("x[0]", degree=1)) filename = os.path.join(tempdir, "tri6_function.xdmf") with XDMFFile(mesh.mpi_comm(), filename, encoding=XDMFFile.Encoding.HDF5) as xdmf: xdmf.write(F) Q = VectorFunctionSpace(mesh, ("Lagrange", 1)) F = Function(Q) if has_petsc_complex: F.interpolate(Expression(("x[0] + j*x[0]", "x[1] + j*x[1]"), degree=1)) else: F.interpolate(Expression(("x[0]", "x[1]"), degree=1)) filename = os.path.join(tempdir, "tri6_vector_function.xdmf") with XDMFFile(mesh.mpi_comm(), filename, encoding=XDMFFile.Encoding.HDF5) as xdmf: xdmf.write(F)
def _generate_space(expression: Operator): # Extract mesh from expression (from dolfin/fem/projection.py, _extract_function_space function) meshes = set( [ufl_domain.ufl_cargo() for ufl_domain in extract_domains(expression)]) for t in traverse_unique_terminals( expression): # from ufl/domain.py, extract_domains if hasattr(t, "_mesh"): meshes.add(t._mesh) assert len(meshes) == 1 mesh = meshes.pop() # The EIM algorithm will evaluate the expression at vertices. However, since the Operator expression may # contain e.g. a gradient of a solution defined in a C^0 space, we resort to DG1 spaces. shape = expression.ufl_shape assert len(shape) in (0, 1, 2) if len(shape) == 0: space = FunctionSpace(mesh, "Discontinuous Lagrange", 1) elif len(shape) == 1: space = VectorFunctionSpace(mesh, "Discontinuous Lagrange", 1, dim=shape[0]) elif len(shape) == 2: space = TensorFunctionSpace(mesh, "Discontinuous Lagrange", 1, shape=shape) else: raise ValueError( "Invalid expression in ParametrizedExpressionFactory.__init__().") return space
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
def test_l2projection(polynomial_order, in_expression): # Test l2 projection for scalar and vector valued expression interpolate_expression = Expression(in_expression, degree=3) xmin, xmax = 0., 1. ymin, ymax = 0., 1. property_idx = 5 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 40, 40) if len(interpolate_expression.ufl_shape) == 0: V = FunctionSpace(mesh, "DG", polynomial_order) elif len(interpolate_expression.ufl_shape) == 1: V = VectorFunctionSpace(mesh, "DG", polynomial_order) v_exact = Function(V) v_exact.interpolate(interpolate_expression) x = RandomRectangle(Point(xmin, ymin), Point(xmax, ymax)).generate([500, 500]) s = assign_particle_values(x, interpolate_expression) # Just make a complicated particle, possibly with scalars and vectors mixed p = particles(x, [x, s, x, x, s], mesh) vh = Function(V) lstsq_rho = l2projection(p, V, property_idx) lstsq_rho.project(vh) error_sq = abs(assemble(dot(v_exact - vh, v_exact - vh) * dx)) assert error_sq < 1e-15
def initial_conditions(self): "Return initial conditions for v and s as a dolfin.GenericFunction." n = self.num_states() # (Maximal) Number of states in MultiCellModel VS = VectorFunctionSpace(self.mesh(), "DG", 0, n+1) vs = Function(VS) markers = self.markers() u = TrialFunction(VS) v = TestFunction(VS) dy = Measure("dx", domain=self.mesh(), subdomain_data=markers) # Define projection into multiverse a = inner(u, v)*dy() Ls = list() for (k, model) in enumerate(self.models()): ic = model.initial_conditions() # Extract initial conditions n_k = model.num_states() # Extract number of local states i_k = self.keys()[k] # Extract domain index of cell model k L_k = sum(ic[j]*v[j]*dy(i_k) for j in range(n_k)) Ls.append(L_k) L = sum(Ls) solve(a == L, vs) return vs
def __init__(self, mesh, mf, bc_dict, move_dict): """ Inititalize Stokes solver with a mesh, its corresponding facet function, a dictionary describing boundary conditions and a dictionary describing which boundaries are fixed in the shape optimization setting """ self.mesh = mesh self.backup = mesh.coordinates().copy() self.mf = mf V2 = VectorElement("CG", mesh.ufl_cell(), 2) S1 = FiniteElement("CG", mesh.ufl_cell(), 1) TH = V2 * S1 self.VQ = FunctionSpace(self.mesh, TH) self.w = Function(self.VQ) self.f = Constant([0.]*mesh.geometric_dimension()) self.S = VectorFunctionSpace(self.mesh, "CG", 1) self.move_dict = move_dict self.J = 0 self._init_bcs(bc_dict) self.solve() self.vfac = 1e4 self.bfac = 1e2 self._init_geometric_functions() self.eval_current_J() self.eval_current_dJ() self.outfile = File("output/u_singlemesh.pvd") self.outfile << self.u self.gradient_scale = 1 self.iteration_counter = 1 self.create_mapping_for_moving_boundary()
def test_p4_scalar_vector(): perms = itertools.permutations([1, 2, 3, 4]) for p in perms: cells = numpy.array([[0, 1, 2, 3], p], dtype=numpy.int64) points = numpy.array( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 1.0, 1.0]], dtype=numpy.float64) mesh = Mesh(MPI.comm_world, CellType.Type.tetrahedron, points, cells, [], GhostMode.none) mesh.geometry.coord_mapping = fem.create_coordinate_map(mesh) Q = FunctionSpace(mesh, ("CG", 4)) F0 = interpolate(Expression("x[0]", degree=4), Q) F1 = interpolate(Expression("x[1]", degree=4), Q) F2 = interpolate(Expression("x[2]", degree=4), Q) pts = numpy.array([[0.4, 0.4, 0.1], [0.4, 0.1, 0.4], [0.1, 0.4, 0.4]]) for pt in pts: assert numpy.isclose(pt[0], F0(pt)[0]) assert numpy.isclose(pt[1], F1(pt)[0]) assert numpy.isclose(pt[2], F2(pt)[0]) V = VectorFunctionSpace(mesh, ("CG", 4)) F = interpolate(Expression(("x[0]", "x[1]", "0.0"), degree=4), V) for pt in pts: result = F(pt) assert numpy.isclose(pt[0], result[0]) assert numpy.isclose(pt[1], result[1]) assert numpy.isclose(0.0, result[2])
def test_save_3d_vector(tempdir, encoding): filename = os.path.join(tempdir, "u_3Dv.xdmf") mesh = UnitCubeMesh(MPI.comm_world, 2, 2, 2) u = Function(VectorFunctionSpace(mesh, ("Lagrange", 1))) u.vector.set(1.0 + (1j if has_petsc_complex else 0)) with XDMFFile(mesh.mpi_comm(), filename, encoding=encoding) as file: file.write(u)
def increase_order(V): """ For a given function space, return the same space, but with a higher polynomial degree """ n = V.num_sub_spaces() if n > 0: spaces = [] for i in range(n): V_i = V.sub(i) element = V_i.ufl_element() # Handle VectorFunctionSpaces specially if isinstance(element, ufl.VectorElement): spaces += [ VectorFunctionSpace(V_i.mesh(), element.family(), element.degree() + 1, dim=element.num_sub_elements()) ] # Handle all else as MixedFunctionSpaces else: spaces += [increase_order(V_i)] return MixedFunctionSpace(spaces) if V.ufl_element().family() == "Real": return FunctionSpace(V.mesh(), "Real", 0) return FunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree() + 1)
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG)) * dx()) C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) return C
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_multi_ps_matrix(mesh): """Tests point source PointSource(V, source) for mulitple point sources applied to a matrix for 1D, 2D and 3D. Global points given to constructor from rank 0 processor. """ c_ids = [0, 1, 2] rank = MPI.rank(mesh.mpi_comm()) V = VectorFunctionSpace(mesh, "CG", 1, dim=2) u, v = TrialFunction(V), TestFunction(V) A = assemble(Constant(0.0) * dot(u, v) * dx) source = [] if rank == 0: for c_id in c_ids: cell = Cell(mesh, c_id) point = cell.midpoint() source.append((point, 10.0)) ps = PointSource(V, source) ps.apply(A) # Checks b sums to correct value a_sum = MPI.sum(mesh.mpi_comm(), np.sum(A.array())) assert round(a_sum - 2 * len(c_ids) * 10) == 0
def get_custom_space(self, family, degree, shape, boundary=False): """Get a custom function space. """ if boundary: mesh = self.BoundaryMesh key = (family, degree, shape, boundary) else: mesh = self.mesh key = (family, degree, shape) space = self._spaces.get(key) if space is None: rank = len(shape) if rank == 0: space = FunctionSpace(mesh, family, degree) elif rank == 1: space = VectorFunctionSpace(mesh, family, degree, shape[0]) else: space = TensorFunctionSpace(mesh, family, degree, shape, symmetry={}) self._spaces[key] = space return space
def test_save_1d_vector(tempfile, file_options): mesh = UnitIntervalMesh(MPI.comm_world, 32) u = Function(VectorFunctionSpace(mesh, "Lagrange", 2)) u.vector()[:] = 1.0 VTKFile(tempfile + "u.pvd", "ascii").write(u) for file_option in file_options: VTKFile(tempfile + "u.pvd", file_option).write(u)
def test_nullspace_check(mesh, degree): V = VectorFunctionSpace(mesh, ('Lagrange', degree)) u, v = TrialFunction(V), TestFunction(V) mesh.geometry.coord_mapping = fem.create_coordinate_map(mesh) E, nu = 2.0e2, 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) def sigma(w, gdim): return 2.0 * mu * ufl.sym(grad(w)) + lmbda * ufl.tr( grad(w)) * ufl.Identity(gdim) a = inner(sigma(u, mesh.geometry.dim), grad(v)) * dx zero = Function(V) L = inner(zero, v) * dx # Assemble matrix and create compatible vector A, L = assembling.assemble_system(a, L, []) # Create null space basis and test null_space = build_elastic_nullspace(V) assert null_space.in_nullspace(A, tol=1.0e-8) null_space.orthonormalize() assert null_space.in_nullspace(A, tol=1.0e-8) # Create incorrect null space basis and test null_space = build_broken_elastic_nullspace(V) assert not null_space.in_nullspace(A, tol=1.0e-8) null_space.orthonormalize() assert not null_space.in_nullspace(A, tol=1.0e-8)
def test_advect_periodic(advection_scheme): xmin, ymin, zmin = 0., 0., 0. xmax, ymax, zmax = 1., 1., 1. pres = 10 mesh = UnitCubeMesh(10, 10, 10) lims = np.array([[xmin, xmin, ymin, ymax, zmin, zmax], [xmax, xmax, ymin, ymax, zmin, zmax], [xmin, xmax, ymin, ymin, zmin, zmax], [xmin, xmax, ymax, ymax, zmin, zmax], [xmin, xmax, ymin, ymax, zmin, zmin], [xmin, xmax, ymin, ymax, zmax, zmax]]) vexpr = Constant((1., 1., 1.)) V = VectorFunctionSpace(mesh, "CG", 1) v = Function(V) v.assign(vexpr) x = RandomBox(Point(0., 0., 0.), Point(1., 1., 1.)).generate([pres, pres, pres]) x = comm.bcast(x, root=0) dt = 0.05 p = particles(x, [x * 0, x**2], mesh) if advection_scheme == 'euler': ap = advect_particles(p, V, v, 'periodic', lims.flatten()) elif advection_scheme == 'rk2': ap = advect_rk2(p, V, v, 'periodic', lims.flatten()) elif advection_scheme == 'rk3': ap = advect_rk3(p, V, v, 'periodic', lims.flatten()) else: assert False xp0 = p.positions() t = 0. while t < 1. - 1e-12: ap.do_step(dt) t += dt xpE = p.positions() xp0_root = comm.gather(xp0, root=0) xpE_root = comm.gather(xpE, root=0) assert len(xp0) == len(xpE) num_particles = p.number_of_particles() if comm.Get_rank() == 0: xp0_root = np.float32(np.vstack(xp0_root)) xpE_root = np.float32(np.vstack(xpE_root)) # Sort on x positions xp0_root = xp0_root[xp0_root[:, 0].argsort(), :] xpE_root = xpE_root[xpE_root[:, 0].argsort(), :] error = np.linalg.norm(xp0_root - xpE_root) assert error < 1e-10 assert num_particles - pres**3 == 0
def test_advect_periodic(advection_scheme): # FIXME: this unit test is sensitive to the ordering of the particle # array, i.e. xp0_root and xpE_root may contain exactly the same entries # but only in a different order. This will return an error right now xmin, xmax = 0., 1. ymin, ymax = 0., 1. pres = 3 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10) lims = np.array([[xmin, xmin, ymin, ymax], [xmax, xmax, ymin, ymax], [xmin, xmax, ymin, ymin], [xmin, xmax, ymax, ymax]]) vexpr = Constant((1., 1.)) V = VectorFunctionSpace(mesh, "CG", 1) x = RandomRectangle(Point(0.05, 0.05), Point(0.15, 0.15)).generate([pres, pres]) 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, 'periodic', lims.flatten()) elif advection_scheme == 'rk2': ap = advect_rk2(p, V, v, 'periodic', lims.flatten()) elif advection_scheme == 'rk3': ap = advect_rk3(p, V, v, 'periodic', lims.flatten()) else: assert False xp0 = p.positions() t = 0. while t < 1.-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) num_particles = p.number_of_particles() if comm.Get_rank() == 0: xp0_root = np.float32(np.vstack(xp0_root)) xpE_root = np.float32(np.vstack(xpE_root)) # Sort on x positions xp0_root = xp0_root[xp0_root[:, 0].argsort(), :] xpE_root = xpE_root[xpE_root[:, 0].argsort(), :] error = np.linalg.norm(xp0_root - xpE_root) assert error < 1e-10 assert num_particles - pres**2 == 0
def make_function_spaces(mesh, element): 'Create mixed function space on the mesh.' assert hasattr(element, 'V') and hasattr(element, 'Q') # Create velocity space n = len(element.V) assert n > 0 V = VectorFunctionSpace(mesh, *element.V[0]) for i in range(1, n): V += VectorFunctionSpace(mesh, *element.V[i]) # Create pressure space assert len(element.Q) == 1 Q = FunctionSpace(mesh, *element.Q[0]) M = MixedFunctionSpace([V, Q]) return V, Q, M
class SNDiscretization(Discretization): def __init__(self, problem, SN_order, verbosity=0): super(SNDiscretization, self).__init__(problem, verbosity) if self.verb > 1: print0("Obtaining angular discretization data") t_ordinates = Timer("Angular discretization data") from transport_data import ordinates_ext_module, quadrature_file from common import check_sn_order self.angular_quad = ordinates_ext_module.OrdinatesData(SN_order, self.mesh.topology().dim(), quadrature_file) self.M = self.angular_quad.get_M() self.N = check_sn_order(SN_order) ord_mat = [self.angular_quad.get_xi().tolist(), self.angular_quad.get_eta().tolist()] if self.angular_quad.get_D() == 3: ord_mat.append(self.angular_quad.get_mu().tolist()) self.ordinates_matrix = as_matrix(ord_mat) if self.verb > 2: self.angular_quad.print_info() def init_solution_spaces(self, group_GS=False): if self.verb > 1: print0("Defining function spaces" ) self.t_spaces.start() self.Vpsi1 = VectorFunctionSpace(self.mesh, "CG", self.parameters["p"], self.M) if not group_GS: self.V = MixedFunctionSpace([self.Vpsi1]*self.G) else: # Alias the solution space as Vpsi1 self.V = self.Vpsi1 self.Vphi1 = FunctionSpace(self.mesh, "CG", self.parameters["p"]) self.ndof1 = self.Vpsi1.dim() self.ndof = self.V.dim() if self.verb > 1: print0(" {0} direction(s), {1} group(s), {2}".format(self.M, self.G, "group GS" if group_GS else "full system")) print0(" NDOF (solution): {0}".format(self.ndof) ) print0(" NDOF (1gr): {0}".format(self.ndof1) ) print0(" NDOF (1dir, 1gr): {0}".format(self.Vpsi1.sub(0).dim()) ) print0(" NDOF (XS): {0}".format(self.ndof0) )
def test_multi_ps_matrix_node_vector_fs(mesh): """Tests point source applied to a matrix with given constructor PointSource(V, source) and a vector function space when points placed at 3 vertices for 1D, 2D and 3D. Global points given to constructor from rank 0 processor. """ point = [0.0, 0.5, 1.0] rank = MPI.rank(mesh.mpi_comm()) V = VectorFunctionSpace(mesh, "CG", 1, dim=2) u, v = TrialFunction(V), TestFunction(V) w = Function(V) A = assemble(Constant(0.0)*dot(u, v)*dx) dim = mesh.geometry().dim() source = [] point_coords = np.zeros(dim) for p in point: for i in range(dim): point_coords[i - 1] = p if rank == 0: source.append((Point(point_coords), 10.0)) ps = PointSource(V, source) ps.apply(A) # Checks array sums to correct value A.get_diagonal(w.vector()) a_sum = MPI.sum(mesh.mpi_comm(), np.sum(A.array())) assert round(a_sum - 2*len(point)*10) == 0 # Check if coordinates are in portion of mesh and if so check that # diagonal components sum to the correct value. mesh_coords = V.tabulate_dof_coordinates() for p in point: for i in range(dim): point_coords[i] = p j = 0 for i in range(len(mesh_coords)//(dim)): mesh_coords_check = mesh_coords[j:j+dim-1] if np.array_equal(point_coords, mesh_coords_check) is True: assert np.round(w.vector()[j//(dim)] - 10.0) == 0.0 j += dim
def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, output_timeseries_as_vector, u_components, scalar_components, NS_parameters): """Store solution on current timestep to XDMF file.""" timefolder = path.join(newfolder, 'Timeseries') if output_timeseries_as_vector: # project or store velocity to vector function space for comp, tstepfile in tstepfiles.iteritems(): if comp == "u": if not hasattr(tstepfile, 'uv'): # First time around only V = q_['u0'].function_space() Vv = VectorFunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree(), constrained_domain=constrained_domain) tstepfile.uv = Function(Vv) tstepfile.d = dict((ui, Vv.sub(i).dofmap().collapse(Vv.mesh())[1]) for i, ui in enumerate(u_components)) # The short but timeconsuming way: #tstepfile.uv.assign(project(u_, Vv)) # Or the faster, but more comprehensive way: for ui in u_components: q_[ui].update() vals = tstepfile.d[ui].values() keys = tstepfile.d[ui].keys() tstepfile.uv.vector()[vals] = q_[ui].vector()[keys] tstepfile << (tstepfile.uv, float(tstep)) elif comp in q_: tstepfile << (q_[comp], float(tstep)) else: tstepfile << (tstepfile.function, float(tstep)) else: for comp, tstepfile in tstepfiles.iteritems(): tstepfile << (q_[comp], float(tstep)) if MPI.rank(mpi_comm_world()) == 0: if not path.exists(path.join(timefolder, "params.dat")): f = open(path.join(timefolder, 'params.dat'), 'w') cPickle.dump(NS_parameters, f)
def pot(): # Define mesh and boundaries. mesh = RectangleMesh(0.0, 0.0, 0.4, 0.1, 120, 30, "left/right") V = VectorFunctionSpace(mesh, "CG", 2) Q = FunctionSpace(mesh, "CG", 1) 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] > 0.4 - 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.1 - GMSH_EPS upper_boundary = UpperBoundary() # Boundary conditions for the velocity. u_bcs = [ DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V.sub(1), 0.0, upper_boundary), DirichletBC(V.sub(0), 0.0, right_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), ] p_bcs = [] return mesh, V, Q, u_bcs, p_bcs, [lower_boundary], [right_boundary, left_boundary]
def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, output_timeseries_as_vector, u_components, scalar_components, NS_parameters): """Store solution on current timestep to XDMF file.""" timefolder = path.join(newfolder, 'Timeseries') if output_timeseries_as_vector: # project or store velocity to vector function space for comp, tstepfile in tstepfiles.iteritems(): if comp == "u": V = q_['u0'].function_space() # First time around create vector function and assigners if not hasattr(tstepfile, 'uv'): Vv = VectorFunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree(), constrained_domain=constrained_domain) tstepfile.uv = Function(Vv) tstepfile.fa = [FunctionAssigner(Vv.sub(i), V) for i, ui in enumerate(u_components)] # Assign solution to vector for i, ui in enumerate(u_components): tstepfile.fa[i].assign(tstepfile.uv.sub(i), q_[ui]) # Store solution vector tstepfile << (tstepfile.uv, float(tstep)) elif comp in q_: tstepfile << (q_[comp], float(tstep)) else: tstepfile << (tstepfile.function, float(tstep)) else: for comp, tstepfile in tstepfiles.iteritems(): tstepfile << (q_[comp], float(tstep)) if MPI.rank(mpi_comm_world()) == 0: if not path.exists(path.join(timefolder, "params.dat")): f = open(path.join(timefolder, 'params.dat'), 'w') cPickle.dump(NS_parameters, f)
def init_solution_spaces(self, group_GS=False): if self.verb > 1: print0("Defining function spaces" ) self.t_spaces.start() self.Vpsi1 = VectorFunctionSpace(self.mesh, "CG", self.parameters["p"], self.M) if not group_GS: self.V = MixedFunctionSpace([self.Vpsi1]*self.G) else: # Alias the solution space as Vpsi1 self.V = self.Vpsi1 self.Vphi1 = FunctionSpace(self.mesh, "CG", self.parameters["p"]) self.ndof1 = self.Vpsi1.dim() self.ndof = self.V.dim() if self.verb > 1: print0(" {0} direction(s), {1} group(s), {2}".format(self.M, self.G, "group GS" if group_GS else "full system")) print0(" NDOF (solution): {0}".format(self.ndof) ) print0(" NDOF (1gr): {0}".format(self.ndof1) ) print0(" NDOF (1dir, 1gr): {0}".format(self.Vpsi1.sub(0).dim()) ) print0(" NDOF (XS): {0}".format(self.ndof0) )
def _evaluateLocalEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, epsilon=1e-5): """Evaluation of patch local equilibrated estimator.""" # prepare numerical flux and f sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f) # ################### # ## MIXED PROBLEM ## # ################### # get setup data for mixed problem V = w[mu]._fefunc.function_space() mesh = V.mesh() mesh.init() degree = element_degree(w[mu]._fefunc) # data for nodal bases V_dm = V.dofmap() V_dofs = dict([(i, V_dm.cell_dofs(i)) for i in range(mesh.num_cells())]) V1 = FunctionSpace(mesh, 'CG', 1) # V1 is to define nodal base functions phi_z = Function(V1) phi_coeffs = np.ndarray(V1.dim()) vertex_dof_map = V1.dofmap().vertex_to_dof_map(mesh) # vertex_dof_map = vertex_to_dof_map(V1) dof_list = vertex_dof_map.tolist() # DG0 localisation DG0 = FunctionSpace(mesh, 'DG', 0) DG0_dofs = dict([(c.index(),DG0.dofmap().cell_dofs(c.index())[0]) for c in cells(mesh)]) dg0 = TestFunction(DG0) # characteristic function of patch xi_z = Function(DG0) xi_coeffs = np.ndarray(DG0.dim()) # mesh data h = CellSize(mesh) n = FacetNormal(mesh) cf = CellFunction('size_t', mesh) # setup error estimator vector eq_est = np.zeros(DG0.dim()) # setup global equilibrated flux vector DG = VectorFunctionSpace(mesh, "DG", degree) DG_dofmap = DG.dofmap() # define form functions tau = TrialFunction(DG) v = TestFunction(DG) # define global tau tau_global = Function(DG) tau_global.vector()[:] = 0.0 # iterate vertices for vertex in vertices(mesh): # get patch cell indices vid = vertex.index() patch_cid, FF_inner, FF_boundary = get_vertex_patch(vid, mesh, layers=1) # set nodal base function phi_coeffs[:] = 0 phi_coeffs[dof_list.index(vid)] = 1 phi_z.vector()[:] = phi_coeffs # set characteristic function and mark patch cf.set_all(0) xi_coeffs[:] = 0 for cid in patch_cid: xi_coeffs[DG0_dofs[int(cid)]] = 1 cf[int(cid)] = 1 xi_z.vector()[:] = xi_coeffs # determine local dofs lDG_cell_dofs = dict([(cid, DG_dofmap.cell_dofs(cid)) for cid in patch_cid]) lDG_dofs = [cd.tolist() for cd in lDG_cell_dofs.values()] lDG_dofs = list(iter.chain(*lDG_dofs)) # print "\nlocal DG subspace has dimension", len(lDG_dofs), "degree", degree, "cells", len(patch_cid), patch_cid # print "local DG_cell_dofs", lDG_cell_dofs # print "local DG_dofs", lDG_dofs # create patch measures dx = Measure('dx')[cf] dS = Measure('dS')[FF_inner] # define forms alpha = Constant(1 / epsilon) / h a = inner(tau,v) * phi_z * dx(1) + alpha * div(tau) * div(v) * dx(1) + avg(alpha) * jump(tau,n) * jump(v,n) * dS(1)\ + avg(alpha) * jump(xi_z * tau,n) * jump(v,n) * dS(2) L = -alpha * (div(sigma_mu) + f) * div(v) * phi_z * dx(1)\ - avg(alpha) * jump(sigma_mu,n) * jump(v,n) * avg(phi_z)*dS(1) # print "L2 f + div(sigma)", assemble((f + div(sigma)) * (f + div(sigma)) * dx(0)) # assemble forms lhs = assemble(a, form_compiler_parameters={'quadrature_degree': quadrature_degree}) rhs = assemble(L, form_compiler_parameters={'quadrature_degree': quadrature_degree}) # convert DOLFIN representation to scipy sparse arrays rows, cols, values = lhs.data() lhsA = sps.csr_matrix((values, cols, rows)).tocoo() # slice sparse matrix and solve linear problem lhsA = coo_submatrix_pull(lhsA, lDG_dofs, lDG_dofs) lx = spsolve(lhsA, rhs.array()[lDG_dofs]) # print ">>> local solution lx", type(lx), lx local_tau = Function(DG) local_tau.vector()[lDG_dofs] = lx # print "div(tau)", assemble(inner(div(local_tau),div(local_tau))*dx(1)) # add up local fluxes tau_global.vector()[lDG_dofs] += lx # evaluate estimator # maybe TODO: re-define measure dx eq_est = assemble( inner(tau_global, tau_global) * dg0 * (dx(0)+dx(1)),\ form_compiler_parameters={'quadrature_degree': quadrature_degree}) # reorder according to cell ids eq_est = eq_est[DG0_dofs.values()].array() global_est = np.sqrt(np.sum(eq_est)) # eq_est_global = assemble( inner(tau_global, tau_global) * (dx(0)+dx(1)), form_compiler_parameters={'quadrature_degree': quadrature_degree} ) # global_est2 = np.sqrt(np.sum(eq_est_global)) return global_est, FlatVector(np.sqrt(eq_est))#, tau_global
def karman(): #mesh = Mesh('../meshes/2d/karman.xml') mesh = Mesh('../meshes/2d/karman-coarse2.xml') V = VectorFunctionSpace(mesh, 'CG', 2) Q = FunctionSpace(mesh, 'CG', 1) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 2.5 - DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS lower_boundary = LowerBoundary() class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 0.4-DOLFIN_EPS upper_boundary = UpperBoundary() class ObstacleBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[0] > DOLFIN_EPS and x[0] < 2.5-DOLFIN_EPS \ and x[1] > DOLFIN_EPS and x[1] < 0.4-DOLFIN_EPS obstacle_boundary = ObstacleBoundary() # Boundary conditions for the velocity. # Proper inflow and outflow conditions are a matter of voodoo. See for # example Gresho/Sani, or # # Boundary conditions for open boundaries # for the incompressible Navier-Stokes equation; # B.C.V. Johansson; # J. Comp. Phys. 105, 233-251 (1993). # # The latter in particularly suggest for the inflow: # # u = u0, # d^r v / dx^r = v_r, # div(u) = 0, # # where u and v are the velocities in normal and tangential directions, # respectively, and r\in{0,1,2}. The setting r=0 essentially means to set # (u,v) statically at the left boundary, r=1 means to set u and control # dv/dn, which is what we do here (namely implicitly by dv/dn=0). # At the outflow, # # d^j u / dx^j = 0, # d^q v / dx^q = 0, # p = p0, # # is suggested with j=q+1. Choosing q=0, j=1 means setting the tangential # component of the outflow to 0, and letting the normal component du/dn=0 # (again, this is achieved implicitly by the weak formulation). # inflow = Expression('100*x[1]*(0.4-x[1])', degree=2) u_bcs = [DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), inflow, left_boundary), #DirichletBC(V.sub(1), 0.0, right_boundary), ] dudt_bcs = [DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), #DirichletBC(V.sub(1), 0.0, right_boundary), ] # If there is a penetration boundary (i.e., n.u!=0), then the pressure must # be set at the boundary to make sure that the Navier-Stokes problem # remains consistent. # It is not quite clear now where exactly to set the pressure to 0. Inlet, # outlet, some other place? The PPE system is consistent in all cases. # TODO find out more about it #p_bcs = [DirichletBC(Q, 0.0, right_boundary)] p_bcs = [] return mesh, V, Q, u_bcs, dudt_bcs, p_bcs
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 = FacetFunction('size_t', submesh_workpiece) 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 crucible_without_coils(): base = '../meshes/2d/crucible' mesh = Mesh(base + '.xml') subdomains = MeshFunction('size_t', mesh, base+'_physical_region.xml') workpiece_index = 4 subdomain_materials = {1: 'SiC', 2: 'boron trioxide', 3: 'GaAs (solid)', 4: 'GaAs (liquid)'} submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) V = VectorFunctionSpace(submesh_workpiece, 'CG', 2) P = FunctionSpace(submesh_workpiece, 'CG', 1) Q = FunctionSpace(mesh, 'CG', 2) # Define mesh and 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.366 + GMSH_EPS < x[1] \ and x[1] < 0.411 - GMSH_EPS left_boundary = LeftBoundary() class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): # Make sure to catch the entire surface, so don't be too # restrictive about x[0]. return on_boundary \ and x[1] > 0.38-GMSH_EPS \ and x[0] > 0.04-GMSH_EPS and x[0] < 0.07+GMSH_EPS class OtherBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and not left_boundary.inside(x, on_boundary) # \ #and not surface_boundary.inside(x, on_boundary) other_boundary = OtherBoundary() # Boundary conditions for the velocity. u_bcs = [DirichletBC(V, (0.0, 0.0), other_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), #DirichletBC(V.sub(1), 0.0, surface_boundary), ] #u_bcs = [DirichletBC(V, (0.0, 0.0), 'on_boundary')] p_bcs = [] class HeaterBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and ((x[1] < 0.38 and GMSH_EPS < x[0] and x[0] < 0.075+GMSH_EPS) or x[0] < GMSH_EPS and x[1] < 0.365+GMSH_EPS) heater_boundary = HeaterBoundary() background_temp = 1400.0 # Heat with 1580K at r=0, 1590K at r=0.075. heater_bcs = [(heater_boundary, '1580.0 + 133.0 * x[0]')] return mesh, subdomains, subdomain_materials, workpiece_index, \ V, Q, P, u_bcs, p_bcs, background_temp, heater_bcs