def test_matrix_assembly_block(mode): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures. """ mesh = UnitSquareMesh(MPI.COMM_WORLD, 4, 8, ghost_mode=mode) p0, p1 = 1, 2 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfinx.function.FunctionSpace(mesh, P0) V1 = dolfinx.function.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) # Locate facets on boundary facetdim = mesh.topology.dim - 1 bndry_facets = dolfinx.mesh.locate_entities_boundary(mesh, facetdim, boundary) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc = dolfinx.function.Function(V1) with u_bc.vector.localForm() as u_local: u_local.set(50.0) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsV1) # Define variational problem u, p = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfinx.Function(V0) a00 = inner(u, v) * dx a01 = inner(p, v) * dx a10 = inner(u, q) * dx a11 = inner(p, q) * dx L0 = zero * inner(f, v) * dx L1 = inner(g, q) * dx a_block = [[a00, a01], [a10, a11]] L_block = [L0, L1] # Monolithic blocked A0 = dolfinx.fem.assemble_matrix_block(a_block, [bc]) A0.assemble() b0 = dolfinx.fem.assemble_vector_block(L_block, a_block, [bc]) assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) A1 = dolfinx.fem.assemble_matrix_nest(a_block, [bc]) A1.assemble() Anorm1 = nest_matrix_norm(A1) assert Anorm0 == pytest.approx(Anorm1, 1.0e-12) b1 = dolfinx.fem.assemble_vector_nest(L_block) dolfinx.fem.apply_lifting_nest(b1, a_block, [bc]) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows(dolfinx.fem.assemble._create_cpp_form(L_block), [bc]) dolfinx.fem.set_bc_nest(b1, bcs0) b1.assemble() bnorm1 = math.sqrt(sum([x.norm()**2 for x in b1.getNestSubVecs()])) assert bnorm0 == pytest.approx(bnorm1, 1.0e-12) # Monolithic version E = P0 * P1 W = dolfinx.function.FunctionSpace(mesh, E) u0, u1 = ufl.TrialFunctions(W) v0, v1 = ufl.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx + inner(u0, v1) * dx + inner( u1, v0) * dx L = zero * inner(f, v0) * ufl.dx + inner(g, v1) * dx bdofsW_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), mesh.topology.dim - 1, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsW_V1, W.sub(1)) A2 = dolfinx.fem.assemble_matrix(a, [bc]) A2.assemble() b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [[bc]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc]) assert A2.getType() != "nest" assert A2.norm() == pytest.approx(Anorm0, 1.0e-9) assert b2.norm() == pytest.approx(bnorm0, 1.0e-9)
subdomain_data=subdomains, metadata={"quadrature_degree": 4}) ds = ufl.Measure("ds", domain=mesh, subdomain_data=interfaces, metadata={"quadrature_degree": 4}) # Inner ring velocity def v_inner_(t=0.0, vt=v_inner_max, g=5, a=1, b=3): return vt * 0.25 * (np.tanh(g * (t - a)) + 1) * (np.tanh(-g * (t - b)) + 1) # Function spaces Ve = ufl.VectorElement("CG", mesh.ufl_cell(), 2) Pe = ufl.FiniteElement("CG", mesh.ufl_cell(), 1) Le = ufl.FiniteElement("CG", mesh.ufl_cell(), 2) V = dolfinx.fem.FunctionSpace(mesh, Ve) P = dolfinx.fem.FunctionSpace(mesh, Pe) N = dolfinx.fem.FunctionSpace(mesh, Le) T = dolfinx.fem.FunctionSpace(mesh, Le) # Define functions v = dolfinx.fem.Function(V, name="v") p = dolfinx.fem.Function(P, name="p") n = dolfinx.fem.Function(N, name="n") t = dolfinx.fem.Function(T, name="t") vt = dolfinx.fem.Function(V, name="vt") pt = dolfinx.fem.Function(P, name="pt")
def test_quadrilateral_variant_spectral_q(): element = create_element( ufl.FiniteElement('Q', ufl.quadrilateral, 3, variant='spectral')) assert isinstance(element.element.A, FIAT.GaussLobattoLegendre) assert isinstance(element.element.B, FIAT.GaussLobattoLegendre)
def test_quadrilateral_variant_spectral_dq(): element = create_element( ufl.FiniteElement('DQ', ufl.quadrilateral, 1, variant='spectral')) assert isinstance(element.product.factors[0], finat.GaussLegendre) assert isinstance(element.product.factors[1], finat.GaussLegendre)
#In order to define the vec(function_forme), the ufl library is used. #A VectorElement represents a combination of basic elements such that each #component of a vector is represented by the basic element. The size is usually #omitted, the default size equals the geometry dimension. #ulf.VectorElement(<Type of the element>, <Geometry of the element>, #degree=<Degree of element: 1 - Linear, 2 - Quadratic, etc.>, dim= <Target #dimension of the element: 1 - Line, 2 - Area, 3 - Volume>) #Lagrange is a familly type of elements -> polynomial functions of forme; #The Lagrange elements are going to be defined in the mesh as such we take the #geometry of elements present in the mesh. element_u = ufl.VectorElement("Lagrange", mesh.ufl_cell(), degree=1, dim=2) element_alpha = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), degree=1) #After defining the Finite Element in ufl, a association with dolfinx is made. #To inputs are necessary, the mesh and the element type created. In some sense, #we obtain the "discretised model w/ elements definied". V_u = dolfinx.fem.FunctionSpace(mesh, element_u) V_alpha = dolfinx.fem.FunctionSpace(mesh, element_alpha) #In this model, we also defines functions necessaries to solve the problem. #This functions are definied in the entire space/model. u = dolfinx.fem.Function(V_u, name="Displacement") #The discrete nodal valeus of #the displacement u_ = dolfinx.fem.Function(V_u, name="BC_Displacement") u_imposed = dolfinx.fem.Function(V_u, name="Imposed_Displacement") alpha = dolfinx.fem.Function(V_alpha, name="Damage")
def ufl_A(request, tensor_name): return ufl.FiniteElement(tensor_name, request.param, 1)
def test_interval_variant(family, variant, expected_cls): ufl_element = ufl.FiniteElement(family, ufl.interval, 3, variant=variant) assert isinstance(create_element(ufl_element), expected_cls)
p_z = μ * dolfinx.Constant(mesh, 1.0 * 0) m_y = μ * dolfinx.Constant(mesh, 1.0 * 0) F_x = μ * dolfinx.Constant( mesh, (2.0 * np.pi / L)**2 * E * I * 0) # prescribed F_x: 2, 4 F_z = μ * dolfinx.Constant( mesh, (0.5 * np.pi / L)**2 * E * I * 0) # prescribed F_z: 4, 8 M_y = μ * dolfinx.Constant( mesh, (2.0 * np.pi / L)**1 * E * I * 1) # prescribed M_y: 1, 2 # Define integration measures dx = ufl.Measure("dx", domain=mesh, subdomain_data=subdomains) ds = ufl.Measure("ds", domain=mesh, subdomain_data=interfaces) # Function spaces Ue = ufl.FiniteElement("CG", mesh.ufl_cell(), p) We = ufl.FiniteElement("CG", mesh.ufl_cell(), p) Re = ufl.FiniteElement("CG", mesh.ufl_cell(), p) U = dolfinx.FunctionSpace(mesh, Ue) W = dolfinx.FunctionSpace(mesh, We) R = dolfinx.FunctionSpace(mesh, Re) # Define functions u = dolfinx.Function(U, name='u') w = dolfinx.Function(W, name='w') r = dolfinx.Function(R, name='r') δu = ufl.TestFunction(U) δw = ufl.TestFunction(W) δr = ufl.TestFunction(R)
def __init__(self, value, cell=None, name=None): """ Create constant-valued function with given value. *Arguments* value The value may be either a single scalar value, or a tuple/list of values for vector-valued functions, or nested lists or a numpy array for tensor-valued functions. cell Optional argument. A :py:class:`Cell <ufl.Cell>` which defines the geometrical dimensions the Constant is defined for. name Optional argument. A str which overrules the default name of the Constant. The data type Constant represents a constant value that is unknown at compile-time. Its values can thus be changed without requiring re-generation and re-compilation of C++ code. *Examples of usage* .. code-block:: python p = Constant(pi/4) # scalar C = Constant((0.0, -1.0, 0.0)) # constant vector """ if cell is None: domain = None else: #deprecation_warning("The cell argument is no longer necessary.") domain = ufl.as_domain(cell) if not isinstance(domain, ufl.Domain): raise TypeError( "Expected an ufl.Domain as the second argument") array = numpy.array(value) rank = len(array.shape) floats = list(map(float, array.flat)) # Create UFL element and initialize constant if rank == 0: self._ufl_element = ufl.FiniteElement("Real", domain, 0) cpp.Constant.__init__(self, floats[0]) elif rank == 1: self._ufl_element = ufl.VectorElement("Real", domain, 0, len(floats)) cpp.Constant.__init__(self, floats) else: self._ufl_element = ufl.TensorElement("Real", domain, 0, shape=array.shape) cpp.Constant.__init__(self, list(array.shape), floats) # Initialize base classes ufl.Coefficient.__init__(self, self._ufl_element, count=self.id()) # Set name as given or automatic name = name or "f_%d" % self.count() self.rename(name, "a Constant")
def __init__(self, value, cell=None, name=None): """ Create constant-valued function with given value. *Arguments* value The value may be either a single scalar value, or a tuple/list of values for vector-valued functions, or nested lists or a numpy array for tensor-valued functions. cell Optional argument. A :py:class:`Cell <ufl.Cell>` which defines the geometrical dimensions the Constant is defined for. name Optional argument. A str which overrules the default name of the Constant. The data type Constant represents a constant value that is unknown at compile-time. Its values can thus be changed without requiring re-generation and re-compilation of C++ code. *Examples of usage* .. code-block:: python p = Constant(pi/4) # scalar C = Constant((0.0, -1.0, 0.0)) # constant vector """ # TODO: Either take mesh instead of cell, or drop cell and let # grad(c) be undefined. if cell is not None: cell = ufl.as_cell(cell) ufl_domain = None array = numpy.array(value) rank = len(array.shape) if cpp.common.has_petsc_complex(): value_list = list(map(numpy.complex128, array.flat)) else: value_list = list(map(float, array.flat)) # Create UFL element and initialize constant if rank == 0: ufl_element = ufl.FiniteElement("Real", cell, 0) self._cpp_object = cpp.function.Constant(value_list[0]) elif rank == 1: ufl_element = ufl.VectorElement("Real", cell, 0, dim=len(value_list)) self._cpp_object = cpp.function.Constant(value_list) else: ufl_element = ufl.TensorElement("Real", cell, 0, shape=array.shape) self._cpp_object = cpp.function.Constant(list(array.shape), value_list) # Initialize base classes ufl_function_space = ufl.FunctionSpace(ufl_domain, ufl_element) ufl.Coefficient.__init__(self, ufl_function_space, count=self.id()) # Set name as given or automatic name = name or "f_%d" % self.count() self.rename(name)
import ufl import timeit from minidolfin.meshing import build_unit_cube_mesh from minidolfin.dofmap import build_dofmap from minidolfin.dofmap import build_sparsity_pattern from minidolfin.dofmap import pattern_to_csr from minidolfin.petsc import create_matrix_from_csr from minidolfin.assembling import assemble import dijitso dijitso.set_log_level("debug") # UFL form element = ufl.FiniteElement("N1E", ufl.tetrahedron, 2) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) omega2 = 1e3 a = (ufl.inner(ufl.curl(u), ufl.curl(v)) - omega2 * ufl.dot(u, v)) * ufl.dx # Build mesh mesh = build_unit_cube_mesh(1, 1, 1) tdim = mesh.reference_cell.get_dimension() print('Number cells: {}'.format(mesh.num_entities(tdim))) # Build dofmap dofmap = build_dofmap(element, mesh) print('Number dofs: {}'.format(dofmap.dim)) # Build sparsity pattern pattern = build_sparsity_pattern(dofmap)
def initialize_functions(mesh): STRESS_elem = ufl.TensorElement("DG", mesh.ufl_cell(), args.disp_degree - 1) DMG_elem = ufl.FiniteElement("Quadrature", mesh.ufl_cell(), degree=quad_degree_stress, quad_scheme="default") # Space for dashpot viscosity should ideally be Quadrature, but this wouldn't # work since we use it to update other non-Quadrature functions ETA_DASH_elem = ufl.FiniteElement("DG", mesh.ufl_cell(), 2) DISPL_elem = ufl.VectorElement("CG", mesh.ufl_cell(), args.disp_degree) TEMP_elem = ufl.FiniteElement("CG", mesh.ufl_cell(), temp_degree) HUM_elem = ufl.FiniteElement("CG", mesh.ufl_cell(), hum_degree) CO2_elem = ufl.FiniteElement("CG", mesh.ufl_cell(), co2_degree) STRESS = FunctionSpace(mesh, STRESS_elem) DMG = FunctionSpace(mesh, DMG_elem) ETA_DASH = FunctionSpace(mesh, ETA_DASH_elem) DISPL = FunctionSpace(mesh, DISPL_elem) TEMP = FunctionSpace(mesh, TEMP_elem) HUM = FunctionSpace(mesh, HUM_elem) CO2 = FunctionSpace(mesh, CO2_elem) W = [] W.append(DISPL) W.append(TEMP) W.append(HUM) W.append(CO2) # Initial temperature temp0 = Function(W[1], name="temp0") temp1 = Function(W[1], name="temp1") # Initial humidity phi0 = Function(W[2], name="phi0") phi1 = Function(W[2], name="phi1") # Initial CO2 concentration co20 = Function(W[3], name="co20") co21 = Function(W[3], name="co21") # Displacement displ0 = Function(W[0], name="displ0") displ1 = Function(W[0], name="displ1") # Pack all internal variables # This is done just for brevity of solve method interface intern_var0 = OrderedDict() intern_var0["eta_dash"] = Function(ETA_DASH) intern_var0["caco3"] = Function(CO2, name="caco3") intern_var0["eps_cr_kel"] = Function(STRESS, name="eps_cr_kel") intern_var0["eps_cr_dash"] = Function(STRESS, name="eps_cr_dash") intern_var0["eps_sh_dr"] = Function(STRESS) intern_var0["eps_th"] = Function(STRESS) intern_var0["eps_eqv"] = Function(DMG, name="eps_eqv") intern_var0["sigma"] = Function(STRESS, name="sigma") intern_var0["dmg"] = Function(DMG, name="dmg") for i in range(mps.M): intern_var0[f"gamma_{i}"] = Function(STRESS) intern_var1 = OrderedDict() intern_var1["eta_dash"] = Function(intern_var0["eta_dash"].function_space) intern_var1["caco3"] = Function(intern_var0["caco3"].function_space) intern_var1["eps_cr_kel"] = Function( intern_var0["eps_cr_kel"].function_space) intern_var1["eps_cr_dash"] = Function( intern_var0["eps_cr_dash"].function_space) intern_var1["eps_sh_dr"] = Function( intern_var0["eps_sh_dr"].function_space) intern_var1["eps_th"] = Function(intern_var0["eps_th"].function_space) intern_var1["eps_eqv"] = Function(intern_var0["eps_eqv"].function_space) intern_var1["sigma"] = Function(intern_var0["sigma"].function_space) intern_var1["dmg"] = Function(intern_var0["dmg"].function_space) for i in range(mps.M): intern_var1[f"gamma_{i}"] = Function( intern_var0[f"gamma_{i}"].function_space) # Pack all "solved-for" quantities w0 = OrderedDict() w0["displ"] = displ0 w0["temp"] = temp0 w0["phi"] = phi0 w0["co2"] = co20 # Pack all "solved-for" quantities w1 = OrderedDict() w1["displ"] = displ1 w1["temp"] = temp1 w1["phi"] = phi1 w1["co2"] = co21 return w0, w1, intern_var0, intern_var1
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" P2 = function.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = function.FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return x[0] < 10 * numpy.finfo(float).eps def boundary1(x): """Define boundary x = 1""" return x[0] > (1.0 - 10 * numpy.finfo(float).eps) # Locate facets on boundaries facetdim = mesh.topology.dim - 1 bndry_facets0 = dolfinx.mesh.locate_entities_boundary(mesh, facetdim, boundary0) bndry_facets1 = dolfinx.mesh.locate_entities_boundary(mesh, facetdim, boundary1) bdofs0 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets1) u0 = dolfinx.Function(P2) u0.vector.set(1.0) u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc0 = dolfinx.DirichletBC(u0, bdofs0) bc1 = dolfinx.DirichletBC(u0, bdofs1) u, p = ufl.TrialFunction(P2), ufl.TrialFunction(P1) v, q = ufl.TestFunction(P2), ufl.TestFunction(P1) a00 = inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a11 = None p00 = a00 p01, p10 = None, None p11 = inner(p, q) * dx # FIXME # We need zero function for the 'zero' part of L p_zero = dolfinx.Function(P1) f = dolfinx.Function(P2) L0 = ufl.inner(f, v) * dx L1 = ufl.inner(p_zero, q) * dx # -- Blocked (nested) A0 = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], [bc0, bc1]) A0.assemble() A0norm = nest_matrix_norm(A0) P0 = dolfinx.fem.assemble_matrix_nest([[p00, p01], [p10, p11]], [bc0, bc1]) P0.assemble() P0norm = nest_matrix_norm(P0) b0 = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b0, [[a00, a01], [a10, a11]], [bc0, bc1]) for b_sub in b0.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows(dolfinx.fem.assemble._create_cpp_form([L0, L1]), [bc0, bc1]) dolfinx.fem.set_bc_nest(b0, bcs0) b0.assemble() b0norm = b0.norm() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0, P0) nested_IS = P0.getNestISs() ksp.setType("minres") pc = ksp.getPC() pc.setType("fieldsplit") pc.setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = pc.getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('superlu_dist') ksp_p.setType("preonly") def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x0 = b0.copy() ksp.solve(b0, x0) assert ksp.getConvergedReason() > 0 # -- Blocked (monolithic) A1 = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], [bc0, bc1]) A1.assemble() assert A1.norm() == pytest.approx(A0norm, 1.0e-12) P1 = dolfinx.fem.assemble_matrix_block([[p00, p01], [p10, p11]], [bc0, bc1]) P1.assemble() assert P1.norm() == pytest.approx(P0norm, 1.0e-12) b1 = dolfinx.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) assert b1.norm() == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A1, P1) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('superlu_dist') ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setFromOptions() x1 = A1.createVecRight() ksp.solve(b1, x1) assert ksp.getConvergedReason() > 0 assert x1.norm() == pytest.approx(x0.norm(), 1e-8) # -- Monolithic P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = dolfinx.FunctionSpace(mesh, TH) (u, p) = ufl.TrialFunctions(W) (v, q) = ufl.TestFunctions(W) a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a = a00 + a01 + a10 p00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx p11 = ufl.inner(p, q) * dx p_form = p00 + p11 f = dolfinx.Function(W.sub(0).collapse()) p_zero = dolfinx.Function(W.sub(1).collapse()) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bc0 = dolfinx.DirichletBC(u0, bdofsW0_P2_0, W.sub(0)) bc1 = dolfinx.DirichletBC(u0, bdofsW0_P2_1, W.sub(0)) A2 = dolfinx.fem.assemble_matrix(a, [bc0, bc1]) A2.assemble() assert A2.norm() == pytest.approx(A0norm, 1.0e-12) P2 = dolfinx.fem.assemble_matrix(p_form, [bc0, bc1]) P2.assemble() assert P2.norm() == pytest.approx(P0norm, 1.0e-12) b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [[bc0, bc1]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc0, bc1]) b2norm = b2.norm() assert b2norm == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A2, P2) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('superlu_dist') def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x2 = A2.createVecRight() ksp.solve(b2, x2) assert ksp.getConvergedReason() > 0 assert x0.norm() == pytest.approx(x2.norm(), 1e-8)
def test_assembly_solve_block(mode): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = UnitSquareMesh(MPI.COMM_WORLD, 32, 31, ghost_mode=mode) P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V0 = dolfinx.function.FunctionSpace(mesh, P) V1 = V0.clone() def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) # Locate facets on boundary facetdim = mesh.topology.dim - 1 bndry_facets = dolfinx.mesh.locate_entities_boundary(mesh, facetdim, boundary) bdofsV0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc0 = dolfinx.function.Function(V0) u_bc0.vector.set(50.0) u_bc0.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u_bc1 = dolfinx.function.Function(V1) u_bc1.vector.set(20.0) u_bc1.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofsV0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofsV1) ] # Variational problem u, p = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfinx.Function(V0) a00 = inner(u, v) * dx a01 = zero * inner(p, v) * dx a10 = zero * inner(u, q) * dx a11 = inner(p, q) * dx L0 = inner(f, v) * dx L1 = inner(g, q) * dx def monitor(ksp, its, rnorm): pass # print("Norm:", its, rnorm) A0 = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], bcs) b0 = dolfinx.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], bcs) A0.assemble() A0norm = A0.norm() b0norm = b0.norm() x0 = A0.createVecLeft() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0) ksp.setMonitor(monitor) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-14) ksp.setFromOptions() ksp.solve(b0, x0) x0norm = x0.norm() # Nested (MatNest) A1 = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], bcs) A1.assemble() b1 = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b1, [[a00, a01], [a10, a11]], bcs) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows(dolfinx.fem.assemble._create_cpp_form([L0, L1]), bcs) dolfinx.fem.set_bc_nest(b1, bcs0) b1.assemble() b1norm = b1.norm() assert b1norm == pytest.approx(b0norm, 1.0e-12) A1norm = nest_matrix_norm(A1) assert A0norm == pytest.approx(A1norm, 1.0e-12) x1 = b1.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A1) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b1, x1) x1norm = x1.norm() assert x1norm == pytest.approx(x0norm, rel=1.0e-12) # Monolithic version E = P * P W = dolfinx.function.FunctionSpace(mesh, E) u0, u1 = ufl.TrialFunctions(W) v0, v1 = ufl.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx L = inner(f, v0) * ufl.dx + inner(g, v1) * dx u0_bc = dolfinx.function.Function(V0) u0_bc.vector.set(50.0) u0_bc.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u1_bc = dolfinx.function.Function(V1) u1_bc.vector.set(20.0) u1_bc.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] A2 = dolfinx.fem.assemble_matrix(a, bcs) A2.assemble() b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [bcs]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, bcs) A2norm = A2.norm() b2norm = b2.norm() assert A2norm == pytest.approx(A0norm, 1.0e-12) assert b2norm == pytest.approx(b0norm, 1.0e-12) x2 = b2.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A2) ksp.setType('cg') ksp.getPC().setType('jacobi') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b2, x2) x2norm = x2.norm() assert x2norm == pytest.approx(x0norm, 1.0e-10)
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" gdim = mesh.geometry.dim P2 = dolfinx.function.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = dolfinx.function.FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return x[0] < 10 * numpy.finfo(float).eps def boundary1(x): """Define boundary x = 1""" return x[0] > (1.0 - 10 * numpy.finfo(float).eps) def initial_guess_u(x): u_init = numpy.row_stack((numpy.sin(x[0]) * numpy.sin(x[1]), numpy.cos(x[0]) * numpy.cos(x[1]))) if gdim == 3: u_init = numpy.row_stack((u_init, numpy.cos(x[2]))) return u_init def initial_guess_p(x): return -x[0]**2 - x[1]**3 u_bc_0 = dolfinx.Function(P2) u_bc_0.interpolate( lambda x: numpy.row_stack(tuple(x[j] + float(j) for j in range(gdim)))) u_bc_1 = dolfinx.Function(P2) u_bc_1.interpolate( lambda x: numpy.row_stack(tuple(numpy.sin(x[j]) for j in range(gdim)))) facetdim = mesh.topology.dim - 1 bndry_facets0 = locate_entities_boundary(mesh, facetdim, boundary0) bndry_facets1 = locate_entities_boundary(mesh, facetdim, boundary1) bdofs0 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets1) bcs = [ dolfinx.DirichletBC(u_bc_0, bdofs0), dolfinx.DirichletBC(u_bc_1, bdofs1) ] u, p = dolfinx.Function(P2), dolfinx.Function(P1) du, dp = ufl.TrialFunction(P2), ufl.TrialFunction(P1) v, q = ufl.TestFunction(P2), ufl.TestFunction(P1) F = [ inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx, inner(ufl.div(u), q) * dx ] J = [[derivative(F[0], u, du), derivative(F[0], p, dp)], [derivative(F[1], u, du), derivative(F[1], p, dp)]] P = [[J[0][0], None], [None, inner(dp, q) * dx]] # -- Blocked and monolithic Jmat0 = dolfinx.fem.create_matrix_block(J) Pmat0 = dolfinx.fem.create_matrix_block(P) Fvec0 = dolfinx.fem.create_vector_block(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P) snes.setFunction(problem.F_block, Fvec0) snes.setJacobian(problem.J_block, J=Jmat0, P=Pmat0) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x0 = dolfinx.fem.create_vector_block(F) with u.vector.localForm() as _u, p.vector.localForm() as _p: dolfinx.cpp.la.scatter_local_vectors(x0, [_u.array_r, _p.array_r], [ u.function_space.dofmap.index_map, p.function_space.dofmap.index_map ]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getConvergedReason() > 0 # -- Blocked and nested Jmat1 = dolfinx.fem.create_matrix_nest(J) Pmat1 = dolfinx.fem.create_matrix_nest(P) Fvec1 = dolfinx.fem.create_vector_nest(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat1.getNestISs() snes.getKSP().setType("minres") snes.getKSP().setTolerances(rtol=1e-12) snes.getKSP().getPC().setType("fieldsplit") snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('superlu_dist') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('superlu_dist') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P) snes.setFunction(problem.F_nest, Fvec1) snes.setJacobian(problem.J_nest, J=Jmat1, P=Pmat1) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x1 = dolfinx.fem.create_vector_nest(F) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) x1.set(0.0) snes.solve(None, x1) assert snes.getConvergedReason() > 0 assert nest_matrix_norm(Jmat1) == pytest.approx(Jmat0.norm(), 1.0e-12) assert Fvec1.norm() == pytest.approx(Fvec0.norm(), 1.0e-12) assert x1.norm() == pytest.approx(x0.norm(), 1.0e-12) # -- Monolithic P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = dolfinx.FunctionSpace(mesh, TH) U = dolfinx.Function(W) dU = ufl.TrialFunction(W) u, p = ufl.split(U) du, dp = ufl.split(dU) v, q = ufl.TestFunctions(W) F = inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx \ + inner(ufl.div(u), q) * dx J = derivative(F, U, dU) P = inner(ufl.grad(du), ufl.grad(v)) * dx + inner(dp, q) * dx bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bcs = [ dolfinx.DirichletBC(u_bc_0, bdofsW0_P2_0, W.sub(0)), dolfinx.DirichletBC(u_bc_1, bdofsW0_P2_1, W.sub(0)) ] Jmat2 = dolfinx.fem.create_matrix(J) Pmat2 = dolfinx.fem.create_matrix(P) Fvec2 = dolfinx.fem.create_vector(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, U, bcs, P=P) snes.setFunction(problem.F_mono, Fvec2) snes.setJacobian(problem.J_mono, J=Jmat2, P=Pmat2) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) x2 = dolfinx.fem.create_vector(F) x2.array = U.vector.array_r snes.solve(None, x2) assert snes.getConvergedReason() > 0 assert Jmat2.norm() == pytest.approx(Jmat0.norm(), 1.0e-12) assert Fvec2.norm() == pytest.approx(Fvec0.norm(), 1.0e-12) assert x2.norm() == pytest.approx(x0.norm(), 1.0e-12)
def test_ufl(): import ufl argyris = ufl.FiniteElement("Argyris", degree=6, cell=ufl.triangle)
def ufl_element(triangle_names): return ufl.FiniteElement(triangle_names, ufl.triangle, 2)
def __init__(self, mesh, family, degree, form_degree=None, constrained_domain=None, restriction=None): """ Create finite element function space. *Arguments* mesh (:py:class:`Mesh <dolfin.cpp.Mesh>`) the mesh family (string) specification of the element family, see below for alternatives. degree (int) the degree of the element. form_degree (int) the form degree (FEEC notation, used when field is viewed as k-form) constrained_domain constrained subdomain with map function. restriction restriction of the element (e.g. to cell facets). Which families and degrees that are supported is determined by the form compiler used to generate the element, but typical families include ================================= ========= Name Usage ================================= ========= Argyris* "ARG" Arnold-Winther* "AW" Brezzi-Douglas-Fortin-Marini* "BDFM" Brezzi-Douglas-Marini "BDM" Bubble "B" Crouzeix-Raviart "CR" Discontinuous Lagrange "DG" Hermite* "HER" Lagrange "CG" Mardal-Tai-Winther* "MTW" Morley* "MOR" Nedelec 1st kind H(curl) "N1curl" Nedelec 2nd kind H(curl) "N2curl" Quadrature "Q" Raviart-Thomas "RT" Real "R" ================================= ========= *only partly supported. *Examples of usage* To define a discrete function space over e.g. the unit square: .. code-block:: python mesh = UnitSquare(32,32) V = FunctionSpace(mesh, "CG", 1) Here, ``"CG"`` stands for Continuous Galerkin, implying the standard Lagrange family of elements. Instead of ``"CG"``, we could have written ``"Lagrange"``. With degree 1, we get the linear Lagrange element. Other examples include: .. code-block:: python # Discontinuous element of degree 0 V = FunctionSpace(mesh, "DG", 0) # Brezzi-Douglas-Marini element of degree 2 W = FunctionSpace(mesh, "BDM", 2) # Real element with one global degree of freedom R = FunctionSpace(mesh, "R", 0) """ # Check arguments if not isinstance(mesh, (cpp.Mesh, cpp.Restriction)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a mesh or restriction: " + str(mesh)) if not isinstance(family, str): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument for finite element family, not a string: " + str(family)) if not isinstance(degree, int): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument for degree, not an integer: " + str(degree)) # Create element # FIXME: Get a ufl.Domain instead of cell somehow. cell = mesh.ufl_cell() if isinstance(mesh, cpp.Mesh) else mesh.mesh().ufl_cell() element = ufl.FiniteElement(family, cell, degree, form_degree=form_degree) if restriction is not None: element = element[restriction] # Initialize base class FunctionSpaceBase.__init__(self, mesh, element, constrained_domain) self.___degree = degree self.___family = family self.___mesh = mesh if isinstance(mesh, cpp.Mesh) else mesh.mesh() self.___form_degree = form_degree
def ufl_B(tensor_name): return ufl.FiniteElement(tensor_name, ufl.interval, 1)
def _create_fiat_element(ufl_element): """Create FIAT element corresponding to given finite element.""" # Get element data family = ufl_element.family() cell = ufl_element.cell() cellname = cell.cellname() degree = ufl_element.degree() # Check that FFC supports this element if family not in supported_families: raise RuntimeError("This element family (%s) is not supported by FFC." % family) # Create FIAT cell fiat_cell = reference_cell(cellname) # Handle the space of the constant if family == "Real": element = _create_fiat_element(ufl.FiniteElement("DG", cell, 0)) element.__class__ = type('SpaceOfReals', (type(element), SpaceOfReals), {}) return element if cellname == "quadrilateral": # Handle quadrilateral case by reconstructing the element with # cell TensorProductCell (interval x interval) quadrilateral_tpc = ufl.TensorProductCell(ufl.Cell("interval"), ufl.Cell("interval")) return FlattenedDimensions( _create_fiat_element(ufl_element.reconstruct(cell=quadrilateral_tpc))) elif cellname == "hexahedron": # Handle hexahedron case by reconstructing the element with cell # TensorProductCell (quadrilateral x interval). This creates # TensorProductElement(TensorProductElement(interval, interval), # interval) Therefore dof entities consists of nested tuples, # example: ((0, 1), 1) hexahedron_tpc = ufl.TensorProductCell(ufl.Cell("quadrilateral"), ufl.Cell("interval")) return FlattenedDimensions( _create_fiat_element(ufl_element.reconstruct(cell=hexahedron_tpc))) # FIXME: AL: Should this really be here? # Handle QuadratureElement if family == "Quadrature": # Compute number of points per axis from the degree of the element scheme = ufl_element.quadrature_scheme() assert degree is not None assert scheme is not None # Create quadrature (only interested in points) # TODO: KBO: What should we do about quadrature functions that live on ds, dS? # Get cell and facet names. points, weights = create_quadrature(cellname, degree, scheme) # Make element element = QuadratureElement(fiat_cell, points) else: # Check if finite element family is supported by FIAT if family not in FIAT.supported_elements: raise RuntimeError("Sorry, finite element of type \"%s\" are not supported by FIAT.", family) ElementClass = FIAT.supported_elements[family] # Create tensor product FIAT finite element if isinstance(ufl_element, ufl.TensorProductElement): A = create_element(ufl_element.sub_elements()[0]) B = create_element(ufl_element.sub_elements()[1]) element = ElementClass(A, B) # Create normal FIAT finite element else: if degree is None: element = ElementClass(fiat_cell) else: element = ElementClass(fiat_cell, degree) if element.value_shape() != ufl_element.reference_value_shape(): # Consistency check between UFL and FIAT elements. raise RuntimeError("Something went wrong in the construction of FIAT element from UFL element." + "Shapes are {} and {}.".format(element.value_shape(), ufl_element.reference_value_shape())) return element
def test_triangle_variant_spectral_fail(): ufl_element = ufl.FiniteElement('DP', ufl.triangle, 2, variant='spectral') with pytest.raises(ValueError): create_element(ufl_element)
import ufl from ufl import inner, curl, dx from minidolfin.assembling import jit_compile_form # for fixing https://github.com/FEniCS/ffcx/pull/25 cell = ufl.tetrahedron element = ufl.FiniteElement("Nedelec 1st kind H(curl)", cell, 3) u = ufl.TrialFunction(element) v = ufl.TestFunction(element) a = inner(curl(u), curl(v)) * dx - inner(u, v) * dx jit_compile_form(a, { "compiler": "ffc", "max_preintegrated_unrolled_table_size": 2000 })
return np.isclose(x[1], 1.0) # Lid velocity def lid_velocity_expression(x): return np.stack((np.ones(x.shape[1]), np.zeros(x.shape[1]))) # We define two :py:class:`FunctionSpace # <dolfinx.function.FunctionSpace>` instances with different finite # elements. ``P2`` corresponds to piecewise quadratics for the velocity # field and ``P1`` to continuous piecewise linears for the pressure # field:: P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V, Q = FunctionSpace(mesh, P2), FunctionSpace(mesh, P1) # We can define boundary conditions:: # No-slip boundary condition for velocity field (`V`) on boundaries # where x = 0, x = 1, and y = 0 noslip = Function(V) with noslip.vector.localForm() as bc_local: bc_local.set(0.0) facets = locate_entities_boundary(mesh, 1, noslip_boundary) bc0 = DirichletBC(noslip, locate_dofs_topological(V, 1, facets)) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V)
def __init__(self, value, name=None, cell=None): """ Create constant-valued function with given value. *Arguments* value The value may be either a single scalar value, or a tuple/list of values for vector-valued functions, or nested lists or a numpy array for tensor-valued functions. cell Optional argument. A :py:class:`Cell <ufl.Cell>` which defines the geometrical dimensions the Constant is defined for. name Optional argument. A str which overrules the default name of the Constant. The data type Constant represents a constant value that is unknown at compile-time. Its values can thus be changed without requiring re-generation and re-compilation of C++ code. *Examples of usage* .. code-block:: python p = Constant(pi/4) # scalar C = Constant((0.0, -1.0, 0.0)) # constant vector """ # TODO: Either take mesh instead of cell, or drop cell and let # grad(c) be undefined. if cell is not None: cell = ufl.as_cell(cell) ufl_domain = None array = numpy.array(value) rank = len(array.shape) floats = list(map(float, array.flat)) # Create UFL element and initialize constant if rank == 0: ufl_element = ufl.FiniteElement("Real", cell, 0) elif rank == 1: ufl_element = ufl.VectorElement("Real", cell, 0, dim=len(floats)) else: ufl_element = ufl.TensorElement("Real", cell, 0, shape=array.shape) # Initialize base classes ufl_function_space = ufl.FunctionSpace(ufl_domain, ufl_element) ufl.Coefficient.__init__(self, ufl_function_space) if name is None: self.name = "c" + str(Constant.constCount) Constant.constCount += 1 else: self.name = name if isNumber(value): self._value = float(value) else: self._value = [float(v) for v in value] self.models = []
def hexahedral_element(): """Compile list of Lagrange elements""" cell = ufl.hexahedron elements = [ufl.FiniteElement("Lagrange", cell, p) for p in range(1, 5)] compiled_elements, module = ffc.codegeneration.jit.compile_elements(elements) return elements, compiled_elements, module
def test_assembly_solve_block(): """Solve a two-field nonlinear diffusion like problem with block matrix approaches and test that solution is the same. """ mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 12, 11) p = 1 P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p) V0 = dolfinx.function.FunctionSpace(mesh, P) V1 = V0.clone() def bc_val_0(x): return x[0]**2 + x[1]**2 def bc_val_1(x): return numpy.sin(x[0]) * numpy.cos(x[1]) def initial_guess_u(x): return numpy.sin(x[0]) * numpy.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary(mesh, facetdim, boundary) u_bc0 = dolfinx.function.Function(V0) u_bc0.interpolate(bc_val_0) u_bc1 = dolfinx.function.Function(V1) u_bc1.interpolate(bc_val_1) bdofs0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofs1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofs0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofs1) ] # Block and Nest variational problem u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1) du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 F = [ inner((u**2 + 1) * ufl.grad(u), ufl.grad(v)) * dx - inner(f, v) * dx, inner((p**2 + 1) * ufl.grad(p), ufl.grad(q)) * dx - inner(g, q) * dx ] J = [[derivative(F[0], u, du), derivative(F[0], p, dp)], [derivative(F[1], u, du), derivative(F[1], p, dp)]] # -- Blocked version Jmat0 = dolfinx.fem.create_matrix_block(J) Fvec0 = dolfinx.fem.create_vector_block(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_block, Fvec0) snes.setJacobian(problem.J_block, J=Jmat0, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x0 = dolfinx.fem.create_vector_block(F) dolfinx.cpp.la.scatter_local_vectors( x0, [u.vector.array_r, p.vector.array_r], [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J0norm = Jmat0.norm() F0norm = Fvec0.norm() x0norm = x0.norm() # -- Nested (MatNest) Jmat1 = dolfinx.fem.create_matrix_nest(J) Fvec1 = dolfinx.fem.create_vector_nest(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat1.getNestISs() snes.getKSP().setType("fgmres") snes.getKSP().setTolerances(rtol=1e-12) snes.getKSP().getPC().setType("fieldsplit") snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('superlu_dist') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('superlu_dist') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_nest, Fvec1) snes.setJacobian(problem.J_nest, J=Jmat1, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x1 = dolfinx.fem.create_vector_nest(F) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x1) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 assert x1.getType() == "nest" assert Jmat1.getType() == "nest" assert Fvec1.getType() == "nest" J1norm = nest_matrix_norm(Jmat1) F1norm = Fvec1.norm() x1norm = x1.norm() assert J1norm == pytest.approx(J0norm, 1.0e-12) assert F1norm == pytest.approx(F0norm, 1.0e-12) assert x1norm == pytest.approx(x0norm, 1.0e-12) # -- Monolithic version E = P * P W = dolfinx.function.FunctionSpace(mesh, E) U = dolfinx.function.Function(W) dU = ufl.TrialFunction(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) F = inner((u0**2 + 1) * ufl.grad(u0), ufl.grad(v0)) * dx \ + inner((u1**2 + 1) * ufl.grad(u1), ufl.grad(v1)) * dx \ - inner(f, v0) * ufl.dx - inner(g, v1) * dx J = derivative(F, U, dU) u0_bc = dolfinx.function.Function(V0) u0_bc.interpolate(bc_val_0) u1_bc = dolfinx.function.Function(V1) u1_bc.interpolate(bc_val_1) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] Jmat2 = dolfinx.fem.create_matrix(J) Fvec2 = dolfinx.fem.create_vector(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, U, bcs) snes.setFunction(problem.F_mono, Fvec2) snes.setJacobian(problem.J_mono, J=Jmat2, P=None) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) x2 = dolfinx.fem.create_vector(F) x2.array = U.vector.array_r snes.solve(None, x2) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J2norm = Jmat2.norm() F2norm = Fvec2.norm() x2norm = x2.norm() assert J2norm == pytest.approx(J0norm, 1.0e-12) assert F2norm == pytest.approx(F0norm, 1.0e-12) assert x2norm == pytest.approx(x0norm, 1.0e-12)
# Build form compiler parameters form_compiler_parameters = {} for p in args.form_compiler_parameters: k, v = p.split("=") form_compiler_parameters[k] = v # Plane wave omega2 = 15**2 + 11**2 def u_exact(x): return math.cos(-15 * x[0] + 12 * x[1]) # UFL form element = ufl.FiniteElement("P", ufl.triangle, 3) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a = (ufl.inner(ufl.grad(u), ufl.grad(v)) - omega2 * ufl.dot(u, v)) * ufl.dx # Build mesh mesh = build_unit_square_mesh(args.n, args.n) tdim = mesh.reference_cell.get_dimension() print('Number cells: {}'.format(mesh.num_entities(tdim))) # Build dofmap dofmap = build_dofmap(element, mesh) print('Number dofs: {}'.format(dofmap.dim)) # Run and time assembly t = -timeit.default_timer() A = assemble(dofmap, a, dtype=numpy.float32)
def test_matrix_assembly_block(): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures in the nonlinear setting """ mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 4, 8) p0, p1 = 1, 2 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfinx.function.FunctionSpace(mesh, P0) V1 = dolfinx.function.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) def initial_guess_u(x): return numpy.sin(x[0]) * numpy.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def bc_value(x): return numpy.cos(x[0]) * numpy.cos(x[1]) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary(mesh, facetdim, boundary) u_bc = dolfinx.function.Function(V1) u_bc.interpolate(bc_value) bdofs = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofs) # Define variational problem du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) f = 1.0 g = -3.0 F0 = inner(u, v) * dx + inner(p, v) * dx - inner(f, v) * dx F1 = inner(u, q) * dx + inner(p, q) * dx - inner(g, q) * dx a_block = [[derivative(F0, u, du), derivative(F0, p, dp)], [derivative(F1, u, du), derivative(F1, p, dp)]] L_block = [F0, F1] # Monolithic blocked x0 = dolfinx.fem.create_vector_block(L_block) dolfinx.cpp.la.scatter_local_vectors( x0, [u.vector.array_r, p.vector.array_r], [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Ghosts are updated inside assemble_vector_block A0 = dolfinx.fem.assemble_matrix_block(a_block, [bc]) b0 = dolfinx.fem.assemble_vector_block(L_block, a_block, [bc], x0=x0, scale=-1.0) A0.assemble() assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) x1 = dolfinx.fem.create_vector_nest(L_block) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) A1 = dolfinx.fem.assemble_matrix_nest(a_block, [bc]) b1 = dolfinx.fem.assemble_vector_nest(L_block) dolfinx.fem.apply_lifting_nest(b1, a_block, [bc], x1, scale=-1.0) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form(L_block), [bc]) dolfinx.fem.set_bc_nest(b1, bcs0, x1, scale=-1.0) A1.assemble() assert A1.getType() == "nest" assert nest_matrix_norm(A1) == pytest.approx(Anorm0, 1.0e-12) assert b1.norm() == pytest.approx(bnorm0, 1.0e-12) # Monolithic version E = P0 * P1 W = dolfinx.function.FunctionSpace(mesh, E) dU = ufl.TrialFunction(W) U = dolfinx.function.Function(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) F = inner(u0, v0) * dx + inner(u1, v0) * dx + inner(u0, v1) * dx + inner(u1, v1) * dx \ - inner(f, v0) * ufl.dx - inner(g, v1) * dx J = derivative(F, U, dU) bdofsW_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsW_V1, W.sub(1)) A2 = dolfinx.fem.assemble_matrix(J, [bc]) A2.assemble() b2 = dolfinx.fem.assemble_vector(F) dolfinx.fem.apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc], x0=U.vector, scale=-1.0) assert A2.getType() != "nest" assert A2.norm() == pytest.approx(Anorm0, 1.0e-12) assert b2.norm() == pytest.approx(bnorm0, 1.0e-12)
def test_quadrilateral_variant_spectral_dq_l2(): element = create_element( ufl.FiniteElement('DQ L2', ufl.quadrilateral, 1, variant='spectral')) assert isinstance(element.element.A, FIAT.GaussLegendre) assert isinstance(element.element.B, FIAT.GaussLegendre)
def test_biharmonic(): """Manufactured biharmonic problem. Solved using rotated Regge mixed finite element method. This is equivalent to the Hellan-Herrmann-Johnson (HHJ) finite element method in two-dimensions.""" mesh = RectangleMesh(MPI.COMM_WORLD, [np.array([0.0, 0.0, 0.0]), np.array([1.0, 1.0, 0.0])], [32, 32], CellType.triangle) element = ufl.MixedElement([ufl.FiniteElement("Regge", ufl.triangle, 1), ufl.FiniteElement("Lagrange", ufl.triangle, 2)]) V = FunctionSpace(mesh, element) sigma, u = ufl.TrialFunctions(V) tau, v = ufl.TestFunctions(V) x = ufl.SpatialCoordinate(mesh) u_exact = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) * ufl.sin(ufl.pi * x[1]) f_exact = div(grad(div(grad(u_exact)))) sigma_exact = grad(grad(u_exact)) # sigma and tau are tangential-tangential continuous according to the # H(curl curl) continuity of the Regge space. However, for the biharmonic # problem we require normal-normal continuity H (div div). Theorem 4.2 of # Lizao Li's PhD thesis shows that the latter space can be constructed by # the former through the action of the operator S: def S(tau): return tau - ufl.Identity(2) * ufl.tr(tau) sigma_S = S(sigma) tau_S = S(tau) # Discrete duality inner product eq. 4.5 Lizao Li's PhD thesis def b(tau_S, v): n = FacetNormal(mesh) return inner(tau_S, grad(grad(v))) * dx \ - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \ - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds # Non-symmetric formulation a = inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v) L = inner(f_exact, v) * dx V_1 = V.sub(1).collapse() zero_u = Function(V_1) with zero_u.vector.localForm() as zero_u_local: zero_u_local.set(0.0) # Strong (Dirichlet) boundary condition boundary_facets = locate_entities_boundary( mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool)) boundary_dofs = locate_dofs_topological((V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets) bcs = [DirichletBC(zero_u, boundary_dofs, V.sub(1))] A = assemble_matrix(a, bcs=bcs) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) # Solve solver = PETSc.KSP().create(MPI.COMM_WORLD) PETSc.Options()["ksp_type"] = "preonly" PETSc.Options()["pc_type"] = "lu" # PETSc.Options()["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) x_h = Function(V) solver.solve(b, x_h.vector) x_h.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Recall that x_h has flattened indices. u_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact - x_h[4], u_exact - x_h[4]) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) u_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact, u_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(u_error_numerator / u_error_denominator) < 0.05) # Reconstruct tensor from flattened indices. # Apply inverse transform. In 2D we have S^{-1} = S. sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]])) sigma_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact - sigma_h, sigma_exact - sigma_h) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) sigma_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact, sigma_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(sigma_error_numerator / sigma_error_denominator) < 0.005)