Source code for oasisx.function
# Copyright (C) 2022 Jørgen Schartum Dokken
#
# This file is part of Oasisx
# SPDX-License-Identifier: MIT
from typing import List, Optional
from petsc4py import PETSc as _petsc
import dolfinx.fem
import ufl
[docs]class Projector:
"""
Projector for a given function.
Solves Ax=b, where
.. highlight:: python
.. code-block:: python
u, v = ufl.TrialFunction(Space), ufl.TestFunction(space)
dx = ufl.Measure("dx", metadata=metadata)
A = inner(u, v) * dx
b = inner(function, v) * dx
Args:
function: UFL expression of function to project
space: Space to project function into
bcs: List of BCS to apply to projection
petsc_options: Options to pass to PETSc
jit_options: Options to pass to just in time compiler
form_compiler_options: Options to pass to the form compiler
metadata: Data to pass to the integration measure
"""
# The mass matrix
_A: _petsc.Mat # type: ignore
# The rhs vector
_b: _petsc.Vec # type: ignore
_lhs: dolfinx.fem.forms.Form # The compiled form for the mass matrix
_rhs: dolfinx.fem.forms.Form # The compiled form form the rhs vector
# The PETSc solver
_ksp: _petsc.KSP # type: ignore
_x: dolfinx.fem.Function # The solution vector
_bcs: List[dolfinx.fem.DirichletBC]
__slots__ = tuple(__annotations__)
def __init__(
self,
function: ufl.core.expr.Expr,
space: dolfinx.fem.FunctionSpace,
bcs: Optional[List[dolfinx.fem.DirichletBC]] = None,
petsc_options: Optional[dict] = None,
jit_options: Optional[dict] = None,
form_compiler_options: Optional[dict] = None,
metadata: Optional[dict] = None,
):
petsc_options = {} if petsc_options is None else petsc_options
jit_options = {} if jit_options is None else jit_options
form_compiler_options = {} if form_compiler_options is None else form_compiler_options
# Assemble projection matrix once
u = ufl.TrialFunction(space)
v = ufl.TestFunction(space)
a = ufl.inner(u, v) * ufl.dx(metadata=metadata)
self._lhs = dolfinx.fem.form(
a, jit_options=jit_options, form_compiler_options=form_compiler_options
)
bcs = [] if bcs is None else bcs
self._A = dolfinx.fem.petsc.assemble_matrix(self._lhs, bcs=bcs)
self._A.assemble()
# Compile RHS form and create vector
L = ufl.inner(function, v) * ufl.dx(metadata=metadata)
self._rhs = dolfinx.fem.form(
L, jit_options=jit_options, form_compiler_options=form_compiler_options
)
self._x = dolfinx.fem.Function(space)
self._b = dolfinx.fem.Function(space)
self._bcs = [] if bcs is None else bcs
# Create Krylov Subspace solver
self._ksp = _petsc.KSP().create(space.mesh.comm) # type: ignore
self._ksp.setOperators(self._A)
# Set PETSc options
prefix = "oasis_projector"
opts = _petsc.Options() # type: ignore
opts.prefixPush(prefix)
self._ksp.setOptionsPrefix(prefix)
for k, v in petsc_options.items():
opts[k] = v
opts.prefixPop()
self._ksp.setFromOptions()
# Set matrix and vector PETSc options
self._A.setOptionsPrefix(prefix)
self._A.setFromOptions()
self._b.vector.setOptionsPrefix(prefix)
self._b.vector.setFromOptions()
for opt in opts.getAll().keys():
del opts[opt]
# Setup preconditioner
self._ksp.getPC().setUp()
[docs] def assemble_rhs(self):
"""
Update RHS by re-assembling
"""
self._b.x.array[:] = 0.0
dolfinx.fem.petsc.assemble_vector(self._b.vector, self._rhs)
if len(self._bcs) > 0:
dolfinx.fem.petsc.apply_lifting(self._b.vector, [self._lhs], bcs=[self._bcs])
self._b.x.scatter_reverse(dolfinx.cpp.la.InsertMode.add)
if len(self._bcs) > 0:
dolfinx.fem.petsc.set_bc(self._b.vector, self._bcs)
self._b.x.scatter_forward()
[docs] def solve(self, assemble_rhs: bool = True) -> int:
"""
Compute projection using PETSc a KSP solver
Args:
assemble_rhs: Re-assemble RHS and re-apply boundary conditions if true
"""
if assemble_rhs:
self.assemble_rhs()
self._ksp.solve(self._b.vector, self._x.vector)
self._x.x.scatter_forward()
return int(self._ksp.getConvergedReason())
@property
def x(self):
return self._x
def __del__(self):
self._ksp.destroy()
self._A.destroy()
self._b.vector.destroy()
self._x.vector.destroy()
class LumpedProject:
"""Projector using a lumped mass matrix"""
__slots__ = ["_form", "_petsc_options", "_bcs"]
def __init__(self):
""" """
raise NotImplementedError