def test_linear_pde(): """Test Newton solver for a linear PDE""" # Create mesh and function space mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 12) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(10.0, v) * dx - inner(grad(u), grad(v)) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) u_bc.vector.set(1.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDEProblem(F, u, bc) # Create Newton solver and solve solver = dolfin.cpp.nls.NewtonSolver(dolfin.MPI.comm_world) n, converged = solver.solve(problem, u.vector) assert converged assert n == 1 # Increment boundary condition and solve again u_bc.vector.set(2.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) n, converged = solver.solve(problem, u.vector) assert converged assert n == 1
def test_nonlinear_pde_snes(): """Test Newton solver for a simple nonlinear PDE""" # Create mesh and function space mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 15) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner( grad(u), grad(v)) * dx - inner(u, v) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) u_bc.vector.set(1.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDE_SNESProblem(F, u, bc) u.vector.set(0.9) u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) b = dolfin.cpp.la.create_vector(V.dofmap.index_map) J = dolfin.cpp.fem.create_matrix(problem.a_comp._cpp_object) # Create Newton solver and solve snes = PETSc.SNES().create() snes.setFunction(problem.F, b) snes.setJacobian(problem.J, J) snes.setTolerances(rtol=1.0e-9, max_it=10) snes.setFromOptions() snes.getKSP().setTolerances(rtol=1.0e-9) snes.solve(None, u.vector) assert snes.getConvergedReason() > 0 assert snes.getIterationNumber() < 6 # Modify boundary condition and solve again u_bc.vector.set(0.5) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, u.vector) assert snes.getConvergedReason() > 0 assert snes.getIterationNumber() < 6
def read_checkpoint(self, V, name: str, counter: int = -1) -> function.Function: """Read finite element Function from checkpointing format Parameters ---------- V Function space of saved function. name Name of function as saved into XDMF file. counter : optional Position of function in the file within functions of the same name. Counter is used to read function saved as time series. To get last saved function use counter=-1, or counter=-2 for one before last, etc. Note ---- Parameter `V: Function space` must be the same as saved function space except for ordering of mesh entities. Returns ------- dolfin.function.function.Function The finite element Function read from checkpoint file """ V_cpp = getattr(V, "_cpp_object", V) u_cpp = self._cpp_object.read_checkpoint(V_cpp, name, counter) return function.Function(V, u_cpp.vector())
def copy(self): """Return a copy of the Function. The FunctionSpace is shared and the degree-of-freedom vector is copied. """ return function.Function(self.function_space(), self._cpp_object.vector().copy())
def interpolate(v, V): """Return interpolation of a given function into a given finite element space. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` V a :py:class:`FunctionSpace (standard, mixed, etc.) <dolfin.functions.functionspace.FunctionSpace>` *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Iv = interpolate(v, V) """ # Check arguments # if not isinstance(V, cpp.functionFunctionSpace): # cpp.dolfin_error("interpolation.py", # "compute interpolation", # "Illegal function space for interpolation, not a FunctionSpace (%s)" % str(v)) # Compute interpolation Pv = function.Function(V) Pv.interpolate(v) return Pv
def test_linear_pde(): """Test Newton solver for a linear PDE""" # Create mesh and function space mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 12) V = dolfin.function.FunctionSpace(mesh, ("Lagrange", 1)) u = dolfin.function.Function(V) v = function.TestFunction(V) F = inner(10.0, v) * dx - inner(grad(u), grad(v)) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) u_bc.vector().set(1.0) u_bc.vector().update_ghosts() bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDEProblem(F, u, bc) # Create Newton solver and solve solver = dolfin.cpp.nls.NewtonSolver(dolfin.MPI.comm_world) n, converged = solver.solve(problem, u.vector()) assert converged assert n == 1
def test_newton_solver_iheritance_override_methods(): import functools called_methods = {} def check_is_called(method): @functools.wraps(method) def wrapper(*args, **kwargs): called_methods[method.__name__] = True return method(*args, **kwargs) return wrapper class CustomNewtonSolver(dolfin.cpp.nls.NewtonSolver): def __init__(self, comm): super().__init__(comm) @check_is_called def update_solution(self, x, dx, relaxation, problem, it): return super().update_solution(x, dx, relaxation, problem, it) @check_is_called def converged(self, r, problem, it): return super().converged(r, problem, it) mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 12) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(10.0, v) * dx - inner(grad(u), grad(v)) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDEProblem(F, u, bc) # Create Newton solver and solve solver = CustomNewtonSolver(dolfin.MPI.comm_world) n, converged = solver.solve(problem, u.vector) assert called_methods[CustomNewtonSolver.converged.__name__] assert called_methods[CustomNewtonSolver.update_solution.__name__]
def read_function(self, V, name: str): """Read finite element Function from file Parameters ---------- V Function space of saved function. name Name of function as saved into HDF file. Returns ------- dolfin.function.function.Function Function read from file Note ---- Parameter `V: Function space` must be the same as saved function space except for ordering of mesh entities. """ V_cpp = getattr(V, "_cpp_object", V) u_cpp = self._cpp_object.read(V_cpp, name) return function.Function(V, u_cpp.vector())
def project(v, V=None, bcs=[], mesh=None, funct=None): """Return projection of given expression *v* onto the finite element space *V*. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` bcs Optional argument :py:class:`list of DirichletBC <dolfin.fem.bcs.DirichletBC>` V Optional argument :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` mesh Optional argument :py:class:`mesh <dolfin.cpp.Mesh>`. funct Target function where result is stored. *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Pv = project(v, V) This is useful for post-processing functions or expressions which are not readily handled by visualization tools (such as for example discontinuous functions). """ # Try figuring out a function space if not specified if V is None: # Create function space based on Expression element if trying # to project an Expression if isinstance(v, function.Expression): if mesh is not None and isinstance(mesh, cpp.mesh.Mesh): V = function.FunctionSpace(mesh, v.ufl_element()) # else: # cpp.dolfin_error("projection.py", # "perform projection", # "Expected a mesh when projecting an Expression") else: # Otherwise try extracting function space from expression V = _extract_function_space(v, mesh) # Check arguments # Ensure we have a mesh and attach to measure if mesh is None: mesh = V.mesh dx = ufl.dx(mesh) # Define variational problem for projection w = function.TestFunction(V) Pv = function.TrialFunction(V) a = ufl.inner(Pv, w) * dx L = ufl.inner(v, w) * dx # Assemble linear system A = fem.assemble_matrix(a, bcs) A.assemble() b = fem.assemble_vector(L) fem.apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) fem.set_bc(b, bcs) # Solve linear system for projection if funct is None: funct = function.Function(V) la.solve(A, funct.vector, b) return funct
def project(v, V=None, bcs=None, mesh=None, function=None, solver_type="lu", preconditioner_type="default", form_compiler_parameters=None): """Return projection of given expression *v* onto the finite element space *V*. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` bcs Optional argument :py:class:`list of DirichletBC <dolfin.fem.bcs.DirichletBC>` V Optional argument :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` mesh Optional argument :py:class:`mesh <dolfin.cpp.Mesh>`. solver_type see :py:func:`solve <dolfin.fem.solving.solve>` for options. preconditioner_type see :py:func:`solve <dolfin.fem.solving.solve>` for options. form_compiler_parameters see :py:class:`Parameters <dolfin.cpp.Parameters>` for more information. *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Pv = project(v, V) This is useful for post-processing functions or expressions which are not readily handled by visualization tools (such as for example discontinuous functions). """ # Try figuring out a function space if not specified if V is None: # Create function space based on Expression element if trying # to project an Expression if isinstance(v, function.Expression): if mesh is not None and isinstance(mesh, cpp.mesh.Mesh): V = function.FunctionSpace(mesh, v.ufl_element()) # else: # cpp.dolfin_error("projection.py", # "perform projection", # "Expected a mesh when projecting an Expression") else: # Otherwise try extracting function space from expression V = _extract_function_space(v, mesh) # Check arguments # Ensure we have a mesh and attach to measure if mesh is None: mesh = V.mesh() dx = ufl.dx(mesh) # Define variational problem for projection w = function.TestFunction(V) Pv = function.TrialFunction(V) a = ufl.inner(w, Pv) * dx L = ufl.inner(w, v) * dx # Assemble linear system A, b = fem.assemble_system( a, L, bcs=bcs, form_compiler_parameters=form_compiler_parameters) # Solve linear system for projection if function is None: function = function.Function(V) la.solve(A, function.vector(), b, solver_type, preconditioner_type) return function