def __init__(self, function_space, model_parameters): super(AllenCahnHeatModel, self).__init__() self._solution_function = fd.Function(function_space) self._solutiondot_function = fd.Function(function_space) test_function = fd.TestFunction(function_space) # Split mixed FE function into separate functions and put them into namedtuple FiniteElementFunction = namedtuple("FiniteElementFunction", ["phi", "T"]) split_solution_function = FiniteElementFunction( *ufl.split(self._solution_function)) split_solutiondot_function = FiniteElementFunction( *ufl.split(self._solutiondot_function)) split_test_function = FiniteElementFunction(*ufl.split(test_function)) finite_element_functions = ( split_solution_function, split_solutiondot_function, split_test_function, ) F_AC = get_allen_cahn_weak_form(*finite_element_functions, model_parameters) F_heat = get_heat_weak_form(*finite_element_functions, model_parameters) F = F_AC + F_heat self._residual = F
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number from ufl.algorithms import extract_arguments form_arguments = extract_arguments(form) number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument using parts, please supply one" ) part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du, coefficient_derivatives)
def Arguments(V, number): """UFL value: Create an Argument in a mixed space, and return a tuple with the function components corresponding to the subelements. This is the overloaded PyDOLFIN variant. """ return ufl.split(Argument(V, number))
def TrialFunctions(V: functionspace.FunctionSpace): """Create a TrialFunction in a mixed space, and return a tuple with the function components corresponding to the subelements. """ return ufl.split(TrialFunction(V))
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number from ufl.algorithms import extract_arguments form_arguments = extract_arguments(form) number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument using parts, please supply one") part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one") return ufl.derivative(form, u, du, coefficient_derivatives)
def TrialFunctions(V): """UFL value: Create a TrialFunction in a mixed space, and return a tuple with the function components corresponding to the subelements. This is the overloaded PyDOLFIN variant. """ return ufl.split(TrialFunction(V))
def test_physically_mapped_facet(): mesh = Mesh(VectorElement("P", triangle, 1)) # set up variational problem U = FiniteElement("Morley", mesh.ufl_cell(), 2) V = FiniteElement("P", mesh.ufl_cell(), 1) R = FiniteElement("P", mesh.ufl_cell(), 1) Vv = VectorElement(BrokenElement(V)) Qhat = VectorElement(BrokenElement(V[facet])) Vhat = VectorElement(V[facet]) Z = FunctionSpace(mesh, MixedElement(U, Vv, Qhat, Vhat, R)) z = Coefficient(Z) u, d, qhat, dhat, lam = split(z) s = FacetNormal(mesh) trans = as_matrix([[1, 0], [0, 1]]) mat = trans*grad(grad(u))*trans + outer(d, d) * u J = (u**2*dx + u**3*dx + u**4*dx + inner(mat, mat)*dx + inner(grad(d), grad(d))*dx + dot(s, d)**2*ds) L_match = inner(qhat, dhat - d) L = J + inner(lam, inner(d, d)-1)*dx + (L_match('+') + L_match('-'))*dS + L_match*ds compile_form(L)
def computeVelocityField(mesh): Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2) Wh = dl.FunctionSpace(mesh, 'Lagrange', 1) mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(mesh, mixed_element) Re = 1e2 g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v,q) = ufl.split(vq) (v_test, q_test) = dl.TestFunctions (XW) def strain(v): return ufl.sym(ufl.grad(v)) F = ( (2./Re)*ufl.inner(strain(v),strain(v_test))+ ufl.inner (ufl.nabla_grad(v)*v, v_test) - (q * ufl.div(v_test)) + ( ufl.div(v) * q_test) ) * ufl.dx dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver": {"relative_tolerance":1e-4, "maximum_iterations":100, "linear_solver":"default"}}) return v
def monolithic_solve(): """Monolithic version""" E = P * P W = FunctionSpace(mesh, E) U = 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) F, J = form(F), form(J) u0_bc = Function(V0) u0_bc.interpolate(bc_val_0) u1_bc = Function(V1) u1_bc.interpolate(bc_val_1) bdofsW0_V0 = locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dirichletbc(u0_bc, bdofsW0_V0, W.sub(0)), dirichletbc(u1_bc, bdofsW1_V1, W.sub(1)) ] Jmat = create_matrix(J) Fvec = 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") problem = NonlinearPDE_SNESProblem(F, J, U, bcs) snes.setFunction(problem.F_mono, Fvec) snes.setJacobian(problem.J_mono, J=Jmat, P=None) U.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) x = create_vector(F) x.array = U.vector.array_r snes.solve(None, x) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 return x.norm()
def test_monolithic(V1, V2, squaremesh_5): mesh = squaremesh_5 Wel = ufl.MixedElement([V1.ufl_element(), V2.ufl_element()]) W = dolfinx.FunctionSpace(mesh, Wel) u = dolfinx.Function(W) u0, u1 = ufl.split(u) v = ufl.TestFunction(W) v0, v1 = ufl.split(v) Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 - u1)**2 * ufl.dx(mesh) F = ufl.derivative(Phi, u, v) opts = PETSc.Options("monolithic") opts.setValue('snes_type', 'newtonls') opts.setValue('snes_linesearch_type', 'basic') opts.setValue('snes_rtol', 1.0e-10) opts.setValue('snes_max_it', 20) opts.setValue('ksp_type', 'preonly') opts.setValue('pc_type', 'lu') opts.setValue('pc_factor_mat_solver_type', 'mumps') problem = dolfiny.snesblockproblem.SNESBlockProblem([F], [u], prefix="monolithic") sol, = problem.solve() u0, u1 = sol.split() u0 = u0.collapse() u1 = u1.collapse() assert np.isclose((u0.vector - np.arcsin(0.5)).norm(), 0.0) assert np.isclose((u1.vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
def computeVelocityField(self): """ The steady-state Navier-Stokes equation for velocity v: -1/Re laplace v + nabla q + v dot nabla v = 0 in Omega nabla dot v = 0 in Omega v = g on partial Omega """ Xh = dl.VectorFunctionSpace(self.mesh, 'Lagrange', self.eldeg) Wh = dl.FunctionSpace(self.mesh, 'Lagrange', 1) mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(self.mesh, mixed_element) Re = dl.Constant(self.Re) def v_boundary(x, on_boundary): return on_boundary def q_boundary(x, on_boundary): return x[0] < dl.DOLFIN_EPS and x[1] < dl.DOLFIN_EPS g = dl.Expression(('0.0', '(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v, q) = ufl.split(vq) (v_test, q_test) = dl.TestFunctions(XW) def strain(v): return ufl.sym(ufl.grad(v)) F = ((2. / Re) * ufl.inner(strain(v), strain(v_test)) + ufl.inner(ufl.nabla_grad(v) * v, v_test) - (q * ufl.div(v_test)) + (ufl.div(v) * q_test)) * ufl.dx dl.solve(F == 0, vq, bcs, solver_parameters={ "newton_solver": { "relative_tolerance": 1e-4, "maximum_iterations": 100, "linear_solver": "default" } }) return v
def Arguments(V, number): """UFL value: Create an Argument in a mixed space, and return a tuple with the function components corresponding to the subelements. This is the overloaded PyDOLFIN variant. """ if isinstance(V, MixedFunctionSpace): return [ Argument(V.sub_space(i), number, i) for i in range(V.num_sub_spaces()) ] else: return ufl.split(Argument(V, number))
def derivative(form, u, du=None): if du is None: if isinstance(u, Function): V = u.function_space() du = Argument(V) elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one") return ufl.derivative(form, u, du)
def derivative(form, u, du=None): if du is None: if isinstance(u, Function): V = u.function_space() du = Argument(V) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du)
def monolithic_assembly(clock, reps, mesh, use_cpp_forms): 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) num_dofs = W.dim U = dolfinx.Function(W) u, p = ufl.split(U) v, q = ufl.TestFunctions(W) g = ufl.as_vector([0.0, 0.0, -1.0]) F = ( ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx + ufl.inner(p, ufl.div(v)) * ufl.dx + ufl.inner(ufl.div(u), q) * ufl.dx - ufl.inner(g, v) * ufl.dx ) J = ufl.derivative(F, U, ufl.TrialFunction(W)) bcs = [] # Get jitted forms for better performance if use_cpp_forms: F = dolfinx.fem.assemble._create_cpp_form(F) J = dolfinx.fem.assemble._create_cpp_form(J) b = dolfinx.fem.create_vector(F) A = dolfinx.fem.create_matrix(J) for i in range(reps): A.zeroEntries() with b.localForm() as b_local: b_local.set(0.0) with dolfinx.common.Timer("ZZZ Mat Monolithic") as tmr: dolfinx.fem.assemble_matrix(A, J, bcs) A.assemble() clock["mat"] += tmr.elapsed()[0] with dolfinx.common.Timer("ZZZ Vec Monolithic") as tmr: dolfinx.fem.assemble_vector(b, F) dolfinx.fem.apply_lifting(b, [J], bcs=[bcs], x0=[U.vector], scale=-1.0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, bcs, x0=U.vector, scale=-1.0) b.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) clock["vec"] += tmr.elapsed()[0] return num_dofs, A, b
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number form_arguments = form.arguments() number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create new Argument using " "parts, please supply one") part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): cpp.deprecation( "derivative of form w.r.t. a tuple of Coefficients", "1.7.0", "2.0.0", "Take derivative w.r.t. a single Coefficient on " "a mixed space instead.") # Get mesh mesh = u[0].function_space().mesh() if not all(mesh.id() == v.function_space().mesh().id() for v in u): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Don't know how to compute derivative with " "respect to Coefficients on different meshes yet") # Build mixed element, space and argument element = ufl.MixedElement( [v.function_space().ufl_element() for v in u]) V = FunctionSpace(mesh, element) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form w.r.t. '%s'" % u, "Supply Function as a Coefficient") return ufl.derivative(form, u, du, coefficient_derivatives)
def argument(self, o): from ufl import split from firedrake import MixedFunctionSpace, FunctionSpace V = o.function_space() if len(V) == 1: # Not on a mixed space, just return ourselves. return o if o in self._arg_cache: return self._arg_cache[o] V_is = V.split() indices = self.blocks[o.number()] try: indices = tuple(indices) nidx = len(indices) except TypeError: # Only one index provided. indices = (indices, ) nidx = 1 if nidx == 1: W = V_is[indices[0]] W = FunctionSpace(W.mesh(), W.ufl_element()) a = (Argument(W, o.number(), part=o.part()), ) else: W = MixedFunctionSpace([V_is[i] for i in indices]) a = split(Argument(W, o.number(), part=o.part())) args = [] for i in range(len(V_is)): if i in indices: c = indices.index(i) a_ = a[c] if len(a_.ufl_shape) == 0: args += [a_] else: args += [a_[j] for j in numpy.ndindex(a_.ufl_shape)] else: args += [ Zero() for j in numpy.ndindex(V_is[i].ufl_element().value_shape()) ] return self._arg_cache.setdefault(o, as_vector(args))
def argument(self, o): from ufl import split from firedrake import MixedFunctionSpace, FunctionSpace V = o.function_space() if len(V) == 1: # Not on a mixed space, just return ourselves. return o if o in self._arg_cache: return self._arg_cache[o] V_is = V.split() indices = self.blocks[o.number()] try: indices = tuple(indices) nidx = len(indices) except TypeError: # Only one index provided. indices = (indices, ) nidx = 1 if nidx == 1: W = V_is[indices[0]] W = FunctionSpace(W.mesh(), W.ufl_element()) a = (Argument(W, o.number(), part=o.part()), ) else: W = MixedFunctionSpace([V_is[i] for i in indices]) a = split(Argument(W, o.number(), part=o.part())) args = [] for i in range(len(V_is)): if i in indices: c = indices.index(i) a_ = a[c] if len(a_.ufl_shape) == 0: args += [a_] else: args += [a_[j] for j in numpy.ndindex(a_.ufl_shape)] else: args += [Zero() for j in numpy.ndindex( V_is[i].ufl_element().value_shape())] return self._arg_cache.setdefault(o, as_vector(args))
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number form_arguments = form.arguments() number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create new Argument using " "parts, please supply one") part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u): cpp.deprecation("derivative of form w.r.t. a tuple of Coefficients", "1.7.0", "2.0.0", "Take derivative w.r.t. a single Coefficient on " "a mixed space instead.") # Get mesh mesh = u[0].function_space().mesh() if not all(mesh.id() == v.function_space().mesh().id() for v in u): cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Don't know how to compute derivative with " "respect to Coefficients on different meshes yet") # Build mixed element, space and argument element = ufl.MixedElement([v.function_space().ufl_element() for v in u]) V = FunctionSpace(mesh, element) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form w.r.t. '%s'" % u, "Supply Function as a Coefficient") return ufl.derivative(form, u, du, coefficient_derivatives)
# # Harmonic map demo using one mixed function u to represent x and y. # Author: Martin Alnes # Date: 2009-04-09 # from ufl import (Coefficient, FiniteElement, VectorElement, derivative, dot, dx, grad, inner, split, triangle) cell = triangle X = VectorElement("Lagrange", cell, 1) Y = FiniteElement("Lagrange", cell, 1) M = X * Y u = Coefficient(M) x, y = split(u) L = inner(grad(x), grad(x)) * dx + dot(x, x) * y * dx F = derivative(L, u) J = derivative(F, u) forms = [L, F, J]
def test_assembly_solve_taylor_hood_nl(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" gdim = mesh.geometry.dim P2 = VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return np.isclose(x[0], 0.0) def boundary1(x): """Define boundary x = 1""" return np.isclose(x[0], 1.0) def initial_guess_u(x): u_init = np.row_stack( (np.sin(x[0]) * np.sin(x[1]), np.cos(x[0]) * np.cos(x[1]))) if gdim == 3: u_init = np.row_stack((u_init, np.cos(x[2]))) return u_init def initial_guess_p(x): return -x[0]**2 - x[1]**3 u_bc_0 = Function(P2) u_bc_0.interpolate( lambda x: np.row_stack(tuple(x[j] + float(j) for j in range(gdim)))) u_bc_1 = Function(P2) u_bc_1.interpolate( lambda x: np.row_stack(tuple(np.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 = locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = locate_dofs_topological(P2, facetdim, bndry_facets1) bcs = [dirichletbc(u_bc_0, bdofs0), dirichletbc(u_bc_1, bdofs1)] u, p = Function(P2), 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]] F, J, P = form(F), form(J), form(P) # -- Blocked and monolithic Jmat0 = create_matrix_block(J) Pmat0 = create_matrix_block(P) Fvec0 = 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") 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 = create_vector_block(F) with u.vector.localForm() as _u, p.vector.localForm() as _p: scatter_local_vectors(x0, [_u.array_r, _p.array_r], [(u.function_space.dofmap.index_map, u.function_space.dofmap.index_map_bs), (p.function_space.dofmap.index_map, p.function_space.dofmap.index_map_bs)]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getConvergedReason() > 0 # -- Blocked and nested Jmat1 = create_matrix_nest(J) Pmat1 = create_matrix_nest(P) Fvec1 = 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_p.setType("preonly") ksp_p.getPC().setType('lu') 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 = 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 = FunctionSpace(mesh, TH) U = 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 F, J, P = form(F), form(J), form(P) bdofsW0_P2_0 = locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bcs = [ dirichletbc(u_bc_0, bdofsW0_P2_0, W.sub(0)), dirichletbc(u_bc_1, bdofsW0_P2_1, W.sub(0)) ] Jmat2 = create_matrix(J) Pmat2 = create_matrix(P) Fvec2 = 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") 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.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) x2 = 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 solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace( mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{ 'type': 'v', 'time': 0.0 }, { 'type': 'p', 'time': 0.0 }]) if doSave: problem.save_vel(False, u0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(False, self.W.sub(0), self.W.sub(1)) # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner( grad(u) * u, v) * dx # Define variational forms F_ns = (inner( (u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F( u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' # prm['newton_solver']['lu_solver']['same_nonzero_pattern'] = True info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt / 2.0): self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t, step) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
# ``` # # For the test functions, {py:func}`TestFunctions<function # ufl.argument.TestFunctions>` (note the 's' at the end) is used to # define the scalar test functions `q` and `v`. Some mixed objects # of the {py:class}`Function<dolfinx.fem.function.Function>` class on # `ME` are defined to represent $u = (c_{n+1}, \mu_{n+1})$ and # $u0 = (c_{n}, \mu_{n})$, and these are then split into # sub-functions: # + u = Function(ME) # current solution u0 = Function(ME) # solution from previous converged step # Split mixed functions c, mu = ufl.split(u) c0, mu0 = ufl.split(u0) # - # The line `c, mu = ufl.split(u)` permits direct access to the # components of a mixed function. Note that `c` and `mu` are references # for components of `u`, and not copies. # # ```{index} single: interpolating functions; (in Cahn-Hilliard demo) # ``` # # The initial conditions are interpolated into a finite element space: # + # Zero u u.x.array[:] = 0.0
def test_matrix_assembly_block_nl(): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures in the nonlinear setting """ mesh = create_unit_square(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 = FunctionSpace(mesh, P0) V1 = FunctionSpace(mesh, P1) def initial_guess_u(x): return np.sin(x[0]) * np.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def bc_value(x): return np.cos(x[0]) * np.cos(x[1]) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary( mesh, facetdim, lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0))) u_bc = Function(V1) u_bc.interpolate(bc_value) bdofs = locate_dofs_topological(V1, facetdim, bndry_facets) bc = dirichletbc(u_bc, bdofs) # Define variational problem du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) u, p = Function(V0), 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 = form([[derivative(F0, u, du), derivative(F0, p, dp)], [derivative(F1, u, du), derivative(F1, p, dp)]]) L_block = form([F0, F1]) # Monolithic blocked x0 = create_vector_block(L_block) scatter_local_vectors(x0, [u.vector.array_r, p.vector.array_r], [(u.function_space.dofmap.index_map, u.function_space.dofmap.index_map_bs), (p.function_space.dofmap.index_map, p.function_space.dofmap.index_map_bs)]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Ghosts are updated inside assemble_vector_block A0 = assemble_matrix_block(a_block, bcs=[bc]) b0 = assemble_vector_block(L_block, a_block, bcs=[bc], x0=x0, scale=-1.0) A0.assemble() assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) x1 = 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 = assemble_matrix_nest(a_block, bcs=[bc]) b1 = assemble_vector_nest(L_block) apply_lifting_nest(b1, a_block, bcs=[bc], x0=x1, scale=-1.0) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = bcs_by_block([L.function_spaces[0] for L in L_block], [bc]) 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 = FunctionSpace(mesh, E) dU = ufl.TrialFunction(W) U = Function(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) U.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) 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) F, J = form(F), form(J) bdofsW_V1 = locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bc = dirichletbc(u_bc, bdofsW_V1, W.sub(1)) A2 = assemble_matrix(J, bcs=[bc]) A2.assemble() b2 = assemble_vector(F) apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) 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 __init__(self, Vh, gamma, delta, mean=None, rel_tol=1e-12, max_iter=100): """ Construct the prior model. Input: - :code:`Vh`: the finite element space for the parameter - :code:`gamma` and :code:`delta`: the coefficient in the PDE - :code:`Theta`: the SPD tensor for anisotropic diffusion of the PDE - :code:`mean`: the prior mean """ assert delta != 0., "Intrinsic Gaussian Prior are not supported" self.Vh = Vh trial = dl.TrialFunction(Vh) test = dl.TestFunction(Vh) varfL = ufl.inner(ufl.grad(trial), ufl.grad(test)) * ufl.dx varfM = ufl.inner(trial, test) * ufl.dx self.M = dl.assemble(varfM) self.R = dl.assemble(gamma * varfL + delta * varfM) self.Rsolver = PETScKrylovSolver(self.Vh.mesh().mpi_comm(), "cg", amg_method()) self.Rsolver.set_operator(self.R) self.Rsolver.parameters["maximum_iterations"] = max_iter self.Rsolver.parameters["relative_tolerance"] = rel_tol self.Rsolver.parameters["error_on_nonconvergence"] = True self.Rsolver.parameters["nonzero_initial_guess"] = False self.Msolver = PETScKrylovSolver(self.Vh.mesh().mpi_comm(), "cg", "jacobi") self.Msolver.set_operator(self.M) self.Msolver.parameters["maximum_iterations"] = max_iter self.Msolver.parameters["relative_tolerance"] = rel_tol self.Msolver.parameters["error_on_nonconvergence"] = True self.Msolver.parameters["nonzero_initial_guess"] = False ndim = Vh.mesh().geometry().dim() old_qr = dl.parameters["form_compiler"]["quadrature_degree"] dl.parameters["form_compiler"]["quadrature_degree"] = -1 qdegree = 2 * Vh._ufl_element.degree() metadata = {"quadrature_degree": qdegree} representation_old = dl.parameters["form_compiler"]["representation"] dl.parameters["form_compiler"]["representation"] = "quadrature" element = ufl.VectorElement("Quadrature", Vh.mesh().ufl_cell(), qdegree, dim=(ndim + 1), quad_scheme="default") Qh = dl.FunctionSpace(Vh.mesh(), element) ph = dl.TrialFunction(Qh) qh = dl.TestFunction(Qh) pph = ufl.split(ph) Mqh = dl.assemble(ufl.inner(ph, qh) * ufl.dx(metadata=metadata)) ones = dl.Vector(self.R.mpi_comm()) Mqh.init_vector(ones, 0) ones.set_local( np.ones(ones.get_local().shape, dtype=ones.get_local().dtype)) dMqh = Mqh * ones dMqh.set_local(ones.get_local() / np.sqrt(dMqh.get_local())) Mqh.zero() Mqh.set_diagonal(dMqh) sqrtdelta = math.sqrt(delta) sqrtgamma = math.sqrt(gamma) varfGG = sqrtdelta * pph[0] * test * ufl.dx(metadata=metadata) for i in range(ndim): varfGG = varfGG + sqrtgamma * pph[i + 1] * test.dx(i) * ufl.dx( metadata=metadata) GG = dl.assemble(varfGG) self.sqrtR = MatMatMult(GG, Mqh) dl.parameters["form_compiler"]["quadrature_degree"] = old_qr dl.parameters["form_compiler"]["representation"] = representation_old self.mean = mean if self.mean is None: self.mean = dl.Vector(self.R.mpi_comm()) self.init_vector(self.mean, 0)
def galerkin_method(mesh): # Mesh and function spaces h = mesh.hmin() V = VectorElement("Lagrange", triangle, 1) P = FiniteElement("Lagrange", triangle, 1) VP = MixedElement([V,P]) W = FunctionSpace(mesh, VP) # Define Boundaries and Boundary Condictions inflow = 'near(x[0],0)' outflow = 'near(x[0], 2.2)' walls = 'near(x[1], 0) || near(x[1], 0.41)' cylinder = 'on_boundary && x[0]>0.1 && x[0]<0.3 && x[1]>0.1 && x[1]<0.3' #inflow_profile = Expression(('4.0*1.5*x[1]*(0.41 - x[1])*sin(3.1415*t/8) / pow(0.41, 4)', '0'), t=0.0, degree=4) inflow_profile2 = Expression(('4.0*x[1]*(0.41 - x[1])*1.5*sin(3.14*t/8) / pow(0.41, 2)', '0'), t=0.0, degree=2) bcu_inflow = DirichletBC(W.sub(0), inflow_profile2, inflow) bcu_walls = DirichletBC(W.sub(0), Constant((0, 0)), walls) bcu_cylinder = DirichletBC(W.sub(0), Constant((0, 0)), cylinder) bcp_outflow = DirichletBC(W.sub(1), Constant(0), outflow) bcs = [bcu_inflow, bcu_walls, bcu_cylinder, bcp_outflow] #Trial and test functions vp = TrialFunction(W) u, p = ufl.split(vp) #u, p = TrialFunctions(W) w, q = TestFunctions(W) #Functions v0 = Constant((0.,0.)) vp1 = Function(W) u1, p1 = vp1.split() un = interpolate(v0, W.sub(0).collapse()) #Stress tensor def epsilon(v): return sym(nabla_grad(v)) def sigma(v,p,nu): return 2*nu*epsilon(v)-p*Identity(len(v)) #Parameters dt = 0.2*h/10. idt = 1./dt t_end = 0.8 nu = 1/1000 f = Constant((0.,0.)) n = FacetNormal(mesh) rho = 1. print('dt: ', dt) print('\n\nNum iteracoes: ', int(t_end/dt)) #Standard Galerkin F = (1.0/dt)*inner(u-un,w)*dx + inner(dot(u1,nabla_grad(u)),w)*dx + inner(sigma(u,p,nu),epsilon(w))*dx + q*div(u)*dx - inner(f,w)*dx + inner(p*n,w)*ds - nu*inner(w,grad(u).T*n)*ds ##########STABILIZATION############# h = 2.0*Circumradius(mesh) unorm = sqrt(dot(u1, u1)) #Residuo momento R = (1.0/dt)*(u-un)+dot(u1,nabla_grad(u))-div(sigma(u,p,nu)) + nabla_grad(p) #PSPG tau_pspg = (h*h)/2. F_pspg = tau_pspg*inner(R,nabla_grad(q))*dx #SUPG tau_supg = ((2.0*idt)**2 + (2.0*u/h)**2 + 9.0*(4.0*nu/h**2)**2 )**(-0.5) F_supg = tau_supg*inner(R,dot(u1,nabla_grad(w)))*dx #LSIC tau_lsic = 0.5*unorm*h F_lsic = inner(div(u),div(w))*tau_lsic*dx F_est = F + F_pspg + F_supg + F_lsic #F_est = F + F_pspg + F_supg # define Jacobian F1 = action(F_est,vp1) J = derivative(F1, vp1,vp) #solution parameters tolr = 'relative_tolerance' tola = 'absolute_tolerance' ln = 'linear_solver' ns = 'newton_solver' prec = 'preconditioner' ks = 'krylov_solver' mi = 'maximum_iterations' enon = 'error_on_nonconvergence' linear = {tolr: 1.0E-8, tola: 1.0E-6, mi: 10000, enon: False} nonlinear = {tolr: 1.0E-4, tola: 1.0E-4, ln:'gmres', mi:20, ln:'gmres', prec:'ilu', enon: False, ks: linear} par = {ns: nonlinear} # Time-stepping t = 0 inicio = time.time() while t < t_end: inflow_profile2.t = t*10 print ("t = ", t) # Compute #begin("Solving ....") solve(F1 == 0, vp1, bcs=bcs, J=J, solver_parameters = par) #end() # Extract solutions: (u1, p1) = vp1.split(True) # Move to next time step un.assign(u1) t += dt fim = time.time() tempo = fim-inicio return u1, p1, tempo
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(dolfinx.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 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] 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)
I = Identity(3) # the identity matrix F = I + grad(u) # the deformation gradient F = variable(F) J = variable(det(F)) # dF mat = GuccioneMaterial(e1=fibers[0], e2=fibers[1], e3=fibers[2], kappa=1e3, Tactive=0.0) psi = mat.strain_energy(F) #guccione hyperelastic material energy function # Postprocecing velocity v = Function(W) #(v0, v1, v2) = ufl.split(v) #(v0, v1, v2, v3) = ufl.split(v) (v0, v1, v2, v3, v4, v5) = ufl.split(v) # Reaction (not working yet) epsilon = 0.1 c = Function(P.sub(1).collapse()) c_n = Function(P.sub(1).collapse()) s = TestFunction(P.sub(1).collapse()) #BCs for reaction bc_react_epi = DirichletBC(P.sub(1), Constant(1), boundary_markers, 40) bc_react_endo = DirichletBC(P.sub(1), Constant(0), boundary_markers, 30) bcs_react = [bc_react_epi, bc_react_endo] #Define storage file u_file = XDMFFile("contraction/u.xdmf") p0_file = XDMFFile("results_" + str(N) + "/p0.xdmf")
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(dolfinx.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 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] 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(dolfinx.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("mumps") 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(dolfinx.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('mumps') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('mumps') 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(dolfinx.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("mumps") 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)
# # For the test functions, # :py:func:`TestFunctions<function ufl.argument.TestFunctions>` (note # the 's' at the end) is used to define the scalar test functions ``q`` # and ``v``. # Some mixed objects of the # :py:class:`Function<dolfinx.fem.function.Function>` class on ``ME`` # are defined to represent :math:`u = (c_{n+1}, \mu_{n+1})` and :math:`u0 # = (c_{n}, \mu_{n})`, and these are then split into sub-functions:: # Define functions u = Function(ME) # current solution u0 = Function(ME) # solution from previous converged step # Split mixed functions c, mu = split(u) c0, mu0 = split(u0) # The line ``c, mu = split(u)`` permits direct access to the components of # a mixed function. Note that ``c`` and ``mu`` are references for # components of ``u``, and not copies. # # .. index:: # single: interpolating functions; (in Cahn-Hilliard demo) # # The initial conditions are interpolated into a finite element space:: # Zero u with u.vector.localForm() as x_local: x_local.set(0.0)
# Contraction parameters I = Identity(3) # the identity matrix F = I + grad(u) # the deformation gradient F = variable(F) J = variable(det(F)) # dF mat = GuccioneMaterial(e1=fibers[0], e2=fibers[1], e3=fibers[2], kappa=1e3, Tactive=0.0) psi = mat.strain_energy(F) #guccione hyperelastic material energy function # Postprocecing velocity v = Function(W) (v0, v1, v2) = ufl.split(v) #Define storage file u_file = XDMFFile("contraction/u.xdmf") p0_file = XDMFFile("results_for_K[2]/p0_K" + str(j) + ".xdmf") p1_file = XDMFFile("results_for_K[2]/p1_K" + str(j) + ".xdmf") p2_file = XDMFFile("results_for_K[2]/p2_K" + str(j) + ".xdmf") v0_file = XDMFFile("results_for_K[2]/v0_K" + str(j) + ".xdmf") v1_file = XDMFFile("results_for_K[2]/v1_K" + str(j) + ".xdmf") v2_file = XDMFFile("results_for_K[2]/v2_K" + str(j) + ".xdmf") append = False # Solve steps = 20 dt = 1 / steps t = 0.0
# For the test functions, # :py:func:`TestFunctions<dolfin.functions.function.TestFunctions>` (note # the 's' at the end) is used to define the scalar test functions ``q`` # and ``v``. The # :py:class:`TrialFunction<dolfin.functions.function.TrialFunction>` # ``du`` has dimension two. Some mixed objects of the # :py:class:`Function<dolfin.functions.function.Function>` class on ``ME`` # are defined to represent :math:`u = (c_{n+1}, \mu_{n+1})` and :math:`u0 # = (c_{n}, \mu_{n})`, and these are then split into sub-functions:: # Define functions u = Function(ME) # current solution u0 = Function(ME) # solution from previous converged step # Split mixed functions dc, dmu = split(du) c, mu = split(u) c0, mu0 = split(u0) # The line ``c, mu = split(u)`` permits direct access to the components of # a mixed function. Note that ``c`` and ``mu`` are references for # components of ``u``, and not copies. # # .. index:: # single: interpolating functions; (in Cahn-Hilliard demo) # # Initial conditions are created by using the evaluate method # then interpolated into a finite element space:: def u_init(values, x):
t_end = 0.4 print('dt: ', dt) print('\n\nNum iteracoes: ', int(t_end / dt)) ###############FLUID PROBLEM################ #Fluid parameters mu_f = 0.04 #Fluid dynamic viscosity rho_f = 1.06 #Fluid density nu_f = Constant(mu_f / rho_f) #Fluid kinematic viscosity f = Constant((0., 0., 0.)) #Fluid body forces #Trial and test functions vp = TrialFunction(W) v, p = ufl.split(vp) #v = fluid velocity, p = pressure : Trial Functions! w, q = TestFunctions( W ) #w = velocity test function (momentum) , q = pressure test function (continuity) #Functions v0 = Constant((0., 0., 0.)) #Initial velocity vp1 = Function(W) #solution function for rigid problem v1, p1 = vp1.split( ) #solution for velocity (v1) e pressure(p1) separeted rigid problem vn = interpolate(v0, W.sub(0).collapse() ) #Defining initial velocity for previously time step (i=0).
def solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace(mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': 0.0}, {'type': 'p', 'time': 0.0}]) if doSave: problem.save_vel(False, u0, 0.0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.W.sub(0), self.W.sub(1)) # NT bcp is not used # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner(grad(u) * u, v) * dx # Define variational forms F_ns = (inner((u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F(u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt/2.0): info("t = %f" % t) self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp, t) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
def galerkin_method(mesh): # Mesh and function spaces h = mesh.hmin() V = VectorElement("Lagrange", triangle, 1) P = FiniteElement("Lagrange", triangle, 1) VP = MixedElement([V, P]) W = FunctionSpace(mesh, VP) # Define Boundaries and Boundary Condictions upperedge = 'near(x[1], 1)' noslip = 'near(x[1], 0) || near(x[0], 1) || near(x[0], 0)' bcu_noslip = DirichletBC(W.sub(0), Constant((0.0, 0.0)), noslip) bcu_top = DirichletBC(W.sub(0), Constant((1.0, 0.0)), upperedge) bcs = [bcu_noslip, bcu_top] #Trial and test functions vp = TrialFunction(W) u, p = ufl.split(vp) w, q = TestFunctions(W) #Functions v0 = Constant((0., 0.)) vp1 = Function(W) u1, p1 = vp1.split() un = interpolate(v0, W.sub(0).collapse()) #Stress tensor def epsilon(v): return sym(nabla_grad(v)) def sigma(v, p, nu): return 2 * nu * epsilon(v) - p * Identity(len(v)) #Parameters dt = 0.2 * h / 1. idt = 1. / dt t_end = 2.5 nu = 1 / 1000 f = Constant((0., 0.)) n = FacetNormal(mesh) rho = 1. #Standard Galerkin F = (1.0 / dt) * inner(u - un, w) * dx + inner(dot( u1, nabla_grad(u)), w) * dx + inner(sigma(u, p, nu), epsilon( w)) * dx + q * div(u) * dx - inner(f, w) * dx + inner( p * n, w) * ds - nu * inner(w, grad(u).T * n) * ds ##########STABILIZATION############# h = 2.0 * Circumradius(mesh) unorm = sqrt(dot(u1, u1)) #Residuo momento R = (1.0 / dt) * (u - un) + dot(u1, nabla_grad(u)) - div(sigma( u, p, nu)) + nabla_grad(p) #PSPG tau_pspg = (h * h) / 2. F_pspg = tau_pspg * inner(R, nabla_grad(q)) * dx #SUPG tau_supg = ((2.0 * idt)**2 + (2.0 * u / h)**2 + 9.0 * (4.0 * nu / h**2)**2)**(-0.5) F_supg = tau_supg * inner(R, dot(u1, nabla_grad(w))) * dx #LSIC tau_lsic = 0.5 * unorm * h F_lsic = inner(div(u), div(w)) * tau_lsic * dx F_est = F + F_pspg + F_supg + F_lsic #F_est = F + F_pspg + F_supg # define Jacobian F1 = action(F_est, vp1) J = derivative(F1, vp1, vp) #solution parameters tolr = 'relative_tolerance' tola = 'absolute_tolerance' ln = 'linear_solver' ns = 'newton_solver' prec = 'preconditioner' ks = 'krylov_solver' mi = 'maximum_iterations' enon = 'error_on_nonconvergence' linear = {tolr: 1.0E-6, tola: 1.0E-6, mi: 1000, enon: False} nonlinear = { tolr: 1.0E-5, tola: 1.0E-5, ln: 'gmres', mi: 3, ln: 'gmres', prec: 'ilu', enon: False, ks: linear } par = {ns: nonlinear} # Time-stepping t = 0 # Create files for storing solution #ufile = File("Driven_cavity/velocity"+str(n_cells)+".pvd") #pfile = File("Driven_cavity/pressure"+str(n_cells)+".pvd") inicio = time.time() while t < t_end: print("t = ", t) # Compute #begin("Solving ....") solve(F1 == 0, vp1, bcs=bcs, J=J, solver_parameters=par) #end() # Extract solutions: (u1, p1) = vp1.split(True) # Plot #plot(v) # Save to file #ufile << u1 #pfile << p1 # Move to next time step un.assign(u1) t += dt #print('velocity no final: ', np.array(v.vector[0]).mean()) fim = time.time() tempo = fim - inicio return u1, p1, tempo