def apply_lifting(b: PETSc.Vec, a: typing.List[typing.Union[Form, cpp.fem.Form]], bcs: typing.List[typing.List[DirichletBC]], x0: typing.Optional[typing.List[PETSc.Vec]] = [], scale: float = 1.0) -> None: """Modify RHS vector b for lifting of Dirichlet boundary conditions. It modifies b such that: b <- b - scale * A_j (g_j - x0_j) where j is a block (nest) index. For a non-blocked problem j = 0. The boundary conditions bcs are on the trial spaces V_j. The forms in [a] must have the same test space as L (from which b was built), but the trial space may differ. If x0 is not supplied, then it is treated as zero. Ghost contributions are not accumulated (not sent to owner). Caller is responsible for calling VecGhostUpdateBegin/End. """ with contextlib.ExitStack() as stack: x0 = [stack.enter_context(x.localForm()) for x in x0] x0_r = [x.array_r for x in x0] b_local = stack.enter_context(b.localForm()) cpp.fem.apply_lifting(b_local.array_w, _create_cpp_form(a), bcs, x0_r, scale)
def F(self, snes: PETSc.SNES, x: PETSc.Vec, b: PETSc.Vec): """Assemble the residual F into the vector b. Parameters ========== snes: the snes object x: Vector containing the latest solution. b: Vector to assemble the residual into. """ # We need to assign the vector to the function x.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) x.copy(self.u.vector) self.u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Zero the residual vector # import pdb; pdb.set_trace() with b.localForm() as b_local: b_local.set(0.0) assemble_vector(b, self.F_form) # Apply boundary conditions apply_lifting(b, [self.J_form], [self.bcs], [x], -1.0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, self.bcs, x, -1.0)
def assemble_vector(form: ufl.form.Form, constraint: MultiPointConstraint, b: _PETSc.Vec = None) -> _PETSc.Vec: """ Assemble a linear form into vector b with corresponding multi point constraint Parameters ---------- form The linear form constraint The multi point constraint b PETSc vector to assemble into (optional) Returns ------- PETSc.Vec The assembled linear form """ if b is None: b = _cpp.la.petsc.create_vector( constraint.function_space.dofmap.index_map, constraint.function_space.dofmap.index_map_bs) t = Timer("~MPC: Assemble vector (C++)") with b.localForm() as b_local: b_local.set(0.0) dolfinx_mpc.cpp.mpc.assemble_vector(b_local, form, constraint._cpp_object) t.stop() return b
def _(b: PETSc.Vec, L: typing.Union[Form, cpp.fem.Form]) -> PETSc.Vec: """Assemble linear form into an existing PETSc vector. The vector is not zeroed before assembly and it is not finalised, qi.e. ghost values are not accumulated on the owning processes. """ with b.localForm() as b_local: cpp.fem.assemble_vector(b_local.array_w, _create_cpp_form(L)) return b
def _(b: PETSc.Vec, L: FormMetaClass, coeffs=Coefficients(None, None)) -> PETSc.Vec: """Assemble linear form into an existing PETSc vector. The vector is not zeroed before assembly and it is not finalised, i.e. ghost values are not accumulated on the owning processes. """ c = (coeffs[0] if coeffs[0] is not None else pack_constants(L), coeffs[1] if coeffs[1] is not None else pack_coefficients(L)) with b.localForm() as b_local: _cpp.fem.assemble_vector(b_local.array_w, L, c[0], c[1]) return b
def F(self, x: PETSc.Vec, F: PETSc.Vec): with F.localForm() as F_local: F_local.set(0.0) dolfinx_mpc.assemble_vector(self._L, self.mpc, b=F) # Apply boundary condition dolfinx_mpc.apply_lifting(F, [self._a], bcs=[self.bcs], constraint=self.mpc, x0=[x], scale=-1.0) F.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.petsc.set_bc(F, self.bcs, x, -1.0)
def _(b: PETSc.Vec, L: typing.Union[Form, cpp.fem.Form]) -> PETSc.Vec: """Assemble linear form into an existing vector. The vector must already have the correct size and parallel layout and wll be zeroed. The returned vector is finalised, i.e. ghost values accumulated across MPI processes. """ L_cpp = _create_cpp_form(L) with b.localForm() as b_local: b_local.set(0.0) cpp.fem.assemble_vector(b, L_cpp) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) return b
def apply_lifting(b: PETSc.Vec, a: typing.List[FormMetaClass], bcs: typing.List[typing.List[DirichletBCMetaClass]], x0: typing.Optional[typing.List[PETSc.Vec]] = [], scale: float = 1.0, constants=None, coeffs=None) -> None: """Apply the function :func:`dolfinx.fem.apply_lifting` to a PETSc Vector.""" with contextlib.ExitStack() as stack: x0 = [stack.enter_context(x.localForm()) for x in x0] x0_r = [x.array_r for x in x0] b_local = stack.enter_context(b.localForm()) assemble.apply_lifting(b_local.array_w, a, bcs, x0_r, scale, constants, coeffs)
def homogenize(self, vector: _PETSc.Vec) -> None: """ For a vector, homogenize (set to zero) the vector components at the multi-point constraint slave DoF indices. This is particularly useful for nonlinear problems. Parameters ---------- vector The input vector """ with vector.localForm() as vector_local: self._cpp_object.homogenize(vector_local.array_w) vector.ghostUpdate(addv=_PETSc.InsertMode.INSERT, mode=_PETSc.ScatterMode.FORWARD)
def backsubstitution(self, vector: _PETSc.Vec) -> None: """ For a vector, impose the multi-point constraint by backsubstiution. This function is used after solving the reduced problem to obtain the values at the slave degrees of freedom Parameters ---------- vector The input vector """ # Unravel data from constraint with vector.localForm() as vector_local: self._cpp_object.backsubstitution(vector_local.array_w) vector.ghostUpdate(addv=_PETSc.InsertMode.INSERT, mode=_PETSc.ScatterMode.FORWARD)
def F(self, x: PETSc.Vec, b: PETSc.Vec): """Assemble the residual F into the vector b. Parameters ---------- x The vector containing the latest solution b Vector to assemble the residual into """ # Reset the residual vector with b.localForm() as b_local: b_local.set(0.0) fem.assemble_vector(b, self._L) # Apply boundary condition fem.apply_lifting(b, [self._a], [self.bcs], [x], -1.0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) fem.set_bc(b, self.bcs, x, -1.0)
def apply_lifting(b: _PETSc.Vec, form: List[_fem.FormMetaClass], bcs: List[List[_fem.DirichletBCMetaClass]], constraint: MultiPointConstraint, x0: List[_PETSc.Vec] = [], scale: float = 1.0): """ Apply lifting to vector b, i.e. .. math:: b <- b - scale * K^T (A_j (g_j - x0_j)) Parameters ---------- b PETSc vector to assemble into form The linear form bcs List of Dirichlet boundary conditions constraint The multi point constraint x0 List of vectors scale Scaling for lifting Returns ------- PETSc.Vec The assembled linear form """ t = Timer("~MPC: Apply lifting (C++)") with contextlib.ExitStack() as stack: x0 = [stack.enter_context(x.localForm()) for x in x0] x0_r = [x.array_r for x in x0] b_local = stack.enter_context(b.localForm()) dolfinx_mpc.cpp.mpc.apply_lifting(b_local.array_w, form, bcs, x0_r, scale, constraint._cpp_object) t.stop()
def _(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear form into an existing PETSc vector. Note: The vector is not zeroed before assembly and it is not finalised, i.e. ghost values are not accumulated on the owning processes. Args: b: Vector to assemble the contribution of the linear form into. L: A linear form to assemble into `b`. Returns: An assembled vector. """ with b.localForm() as b_local: assemble.assemble_vector(b_local.array_w, L, constants, coeffs) return b