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 form(self, x: PETSc.Vec): """This function is called before the residual or Jacobian is computed. This is usually used to update ghost values. Parameters ---------- x The vector containing the latest solution """ x.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
def _(b: PETSc.Vec, L: typing.List[FormMetaClass], a, bcs: typing.List[DirichletBCMetaClass] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, constants_L=None, coeffs_L=None, constants_a=None, coeffs_a=None) -> PETSc.Vec: """Assemble linear forms into a monolithic vector. The vector is not zeroed and it is not finalised, i.e. ghost values are not accumulated. """ maps = [(form.function_spaces[0].dofmap.index_map, form.function_spaces[0].dofmap.index_map_bs) for form in L] if x0 is not None: x0_local = _cpp.la.petsc.get_local_vectors(x0, maps) x0_sub = x0_local else: x0_local = [] x0_sub = [None] * len(maps) constants_L = [form and _pack_constants(form) for form in L] if constants_L is None else constants_L coeffs_L = [{} if form is None else _pack_coefficients(form) for form in L] if coeffs_L is None else coeffs_L constants_a = [[form and _pack_constants(form) for form in forms] for forms in a] if constants_a is None else constants_a coeffs_a = [[{} if form is None else _pack_coefficients(form) for form in forms] for forms in a] if coeffs_a is None else coeffs_a bcs1 = _bcs_by_block(_extract_spaces(a, 1), bcs) b_local = _cpp.la.petsc.get_local_vectors(b, maps) for b_sub, L_sub, a_sub, const_L, coeff_L, const_a, coeff_a in zip( b_local, L, a, constants_L, coeffs_L, constants_a, coeffs_a): _cpp.fem.assemble_vector(b_sub, L_sub, const_L, coeff_L) _cpp.fem.apply_lifting(b_sub, a_sub, const_a, coeff_a, bcs1, x0_local, scale) _cpp.la.petsc.scatter_local_vectors(b, b_local, maps) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = _bcs_by_block(_extract_spaces(L), bcs) offset = 0 b_array = b.getArray(readonly=False) for submap, bc, _x0 in zip(maps, bcs0, x0_sub): size = submap[0].size_local * submap[1] _cpp.fem.set_bc(b_array[offset:offset + size], bc, _x0, scale) offset += size return b
def update(self, solver: dolfinx.nls.petsc.NewtonSolver, dx: PETSc.Vec, x: PETSc.Vec): # We need to use a vector created on the MPC's space to update ghosts self.u_mpc.vector.array = x.array_r self.u_mpc.vector.axpy(-1.0, dx) self.u_mpc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) self.mpc.homogenize(self.u_mpc.vector) self.mpc.backsubstitution(self.u_mpc.vector) x.array = self.u_mpc.vector.array_r x.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
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 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 _(b: PETSc.Vec, L: typing.List[typing.Union[Form, cpp.fem.Form]], a, bcs: typing.List[DirichletBC] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0) -> PETSc.Vec: """Assemble linear forms into a monolithic vector. The vector is not zeroed and it is not finalised, i.e. ghost values are not accumulated. """ maps = [ form.function_spaces[0].dofmap.index_map for form in _create_cpp_form(L) ] if x0 is not None: x0_local = cpp.la.get_local_vectors(x0, maps) x0_sub = x0_local else: x0_local = [] x0_sub = [None] * len(maps) bcs1 = cpp.fem.bcs_cols(_create_cpp_form(a), bcs) b_local = cpp.la.get_local_vectors(b, maps) for b_sub, L_sub, a_sub, bc in zip(b_local, L, a, bcs1): cpp.fem.assemble_vector(b_sub, _create_cpp_form(L_sub)) cpp.fem.apply_lifting(b_sub, _create_cpp_form(a_sub), bc, x0_local, scale) cpp.la.scatter_local_vectors(b, b_local, maps) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = cpp.fem.bcs_rows(_create_cpp_form(L), bcs) offset = 0 b_array = b.getArray(readonly=False) for submap, bc, _x0 in zip(maps, bcs0, x0_sub): size = submap.size_local * submap.block_size cpp.fem.set_bc(b_array[offset:offset + size], bc, _x0, scale) offset += size return b