class BlockNonlinearProblem(NonlinearProblem): def __init__(self, residual_block_form, block_solution, bcs, jacobian_block_form): NonlinearProblem.__init__(self) # Store the input arguments self.residual_block_form = residual_block_form self.jacobian_block_form = jacobian_block_form self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap() def F(self, fenics_residual, _): # Update block solution subfunctions based on the third argument, which has already been # stored in self.block_solution.block_vector() self.block_solution.apply("to subfunctions") # Wrap FEniCS residual into a block residual block_residual = self.block_backend.wrap_vector(fenics_residual) # Assemble the block residual block_assemble(self.residual_block_form, block_tensor=block_residual) # Apply boundary conditions if self.bcs is not None: self.bcs.apply(block_residual, self.block_solution.block_vector()) def J(self, fenics_jacobian, _): # No need to update block solution subfunctions, this has already been done in the residual # Wrap FEniCS jacobian into a block jacobian block_jacobian = self.block_backend.wrap_matrix(fenics_jacobian) # Assemble the block jacobian block_assemble(self.jacobian_block_form, block_tensor=block_jacobian) # Apply boundary conditions if self.bcs is not None: self.bcs.apply(block_jacobian)
def __init__(self, residual_block_form, block_solution, bcs, jacobian_block_form): NonlinearProblem.__init__(self) # Store the input arguments self.residual_block_form = residual_block_form self.jacobian_block_form = jacobian_block_form self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap()
def __init__(self, block_solution): NonlinearProblem.__init__(self) rhs = [F_F_n(v), 0, F_P_n(w), G_n(qP), 0] F = np.array(lhs).sum(axis=1) - np.array(rhs) J = block_derivative(F, trial, dtrial) self.residual_block_form = F self.jacobian_block_form = J self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap()
def __init__(self, residual_form_or_eval, block_solution, bcs, jacobian_form_or_eval): NonlinearProblem.__init__(self) # Store the input arguments self.residual_form_or_eval = residual_form_or_eval self.jacobian_form_or_eval = jacobian_form_or_eval self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap() # =========== PETScSNESSolver::init() workaround for assembled matrices =========== # self._J_assemble_failed_in_init = False
def _create_block_tensor(comm, block_form, rank, block_tensor): backend = BlockDefaultFactory() block_tensor = _dolfin_create_tensor(comm, block_form, rank, backend, block_tensor) block_tensor = as_backend_type(block_tensor) # Attach block dofmap to tensor assert rank in (1, 2) if rank == 2: block_dofmap_0 = block_form.block_function_spaces()[0].block_dofmap() block_dofmap_1 = block_form.block_function_spaces()[1].block_dofmap() assert block_tensor.has_block_dof_map(0) == block_tensor.has_block_dof_map(1) if not block_tensor.has_block_dof_map(0): block_tensor.attach_block_dof_map(block_dofmap_0, block_dofmap_1) else: assert block_dofmap_0 == block_tensor.get_block_dof_map(0) assert block_dofmap_1 == block_tensor.get_block_dof_map(1) elif rank == 1: block_dofmap = block_form.block_function_spaces()[0].block_dofmap() if not block_tensor.has_block_dof_map(): block_tensor.attach_block_dof_map(block_dofmap) else: assert block_dofmap == block_tensor.get_block_dof_map() # Store private attribute for BlockDirichletBC application to off diagonal blocks if rank == 2: bcs_zero_off_block_diagonal = empty(block_form.shape, dtype=bool) for I in range(block_form.shape[0]): for J in range(block_form.shape[1]): bcs_zero_off_block_diagonal[I, J] = not _is_zero(block_form[I, J]) block_tensor._bcs_zero_off_block_diagonal = bcs_zero_off_block_diagonal.tolist() return block_tensor
def _create_block_tensor(comm, block_form, rank, block_tensor): backend = BlockDefaultFactory() block_tensor = _dolfin_create_tensor(comm, block_form, rank, backend, block_tensor) block_tensor = as_backend_type(block_tensor) # Attach block dofmap to tensor assert rank in (1, 2) if rank is 2: block_dofmap_0 = block_form.block_function_spaces()[0].block_dofmap() block_dofmap_1 = block_form.block_function_spaces()[1].block_dofmap() assert block_tensor.has_block_dof_map( 0) == block_tensor.has_block_dof_map(1) if not block_tensor.has_block_dof_map(0): block_tensor.attach_block_dof_map(block_dofmap_0, block_dofmap_1) else: assert block_dofmap_0 == block_tensor.get_block_dof_map(0) assert block_dofmap_1 == block_tensor.get_block_dof_map(1) elif rank is 1: block_dofmap = block_form.block_function_spaces()[0].block_dofmap() if not block_tensor.has_block_dof_map(): block_tensor.attach_block_dof_map(block_dofmap) else: assert block_dofmap == block_tensor.get_block_dof_map() return block_tensor
class BiotNSBlockNonLinearProblem(BlockNonlinearProblem): def __init__(self, block_solution): NonlinearProblem.__init__(self) rhs = [F_F_n(v), 0, F_P_n(w), G_n(qP), 0] F = np.array(lhs).sum(axis=1) - np.array(rhs) J = block_derivative(F, trial, dtrial) self.residual_block_form = F self.jacobian_block_form = J self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap() # precompute linear part of jacobian # self.precomp_jacobian = block_assemble(J, keep_diagonal=self.bcs is not None) def J(self, fenics_jacobian, _): # No need to update block solution subfunctions, this has already been done in the residual # Wrap FEniCS jacobian into a block jacobian block_jacobian = self.block_backend.wrap_matrix(fenics_jacobian) # Assemble the block jacobian block_assemble(self.jacobian_block_form, block_tensor=block_jacobian, keep_diagonal=self.bcs is not None) # Apply boundary conditions if self.bcs is not None: self.bcs.apply(block_jacobian)
class BlockNonlinearProblem(NonlinearProblem): def __init__(self, residual_form_or_eval, block_solution, bcs, jacobian_form_or_eval): NonlinearProblem.__init__(self) # Store the input arguments self.residual_form_or_eval = residual_form_or_eval self.jacobian_form_or_eval = jacobian_form_or_eval self.block_solution = block_solution self.bcs = bcs # Create block backend for wrapping self.block_backend = BlockDefaultFactory() self.block_dof_map = self.block_solution.block_function_space( ).block_dofmap() # =========== PETScSNESSolver::init() workaround for assembled matrices =========== # self._J_assemble_failed_in_init = False # === end === PETScSNESSolver::init() workaround for assembled matrices === end === # def F(self, fenics_residual, _): # Update block solution subfunctions based on the third argument, which has already been # updated in self.block_solution.block_vector() self.block_solution.apply("to subfunctions") # Wrap FEniCS residual into a block residual block_residual = self.block_backend.wrap_vector(fenics_residual) # Assemble the block residual self._block_residual_vector_assemble(block_residual, self.block_solution) # Apply boundary conditions if self.bcs is not None: self.bcs.apply(block_residual, self.block_solution.block_vector()) def _block_residual_vector_assemble(self, block_residual, block_solution): assert isinstance( self.residual_form_or_eval, (list, array, BlockForm1, types.FunctionType, types.MethodType)) if isinstance(self.residual_form_or_eval, (list, array, BlockForm1)): residual_form_or_vector = self.residual_form_or_eval elif isinstance(self.residual_form_or_eval, (types.FunctionType, types.MethodType)): residual_form_or_vector = self.residual_form_or_eval( block_solution) else: raise AssertionError( "Invalid case in BlockNonlinearProblem._block_residual_vector_assemble." ) assert isinstance(residual_form_or_vector, (list, array, BlockForm1, GenericBlockVector)) if isinstance(residual_form_or_vector, (list, array, BlockForm1)): block_assemble(residual_form_or_vector, block_tensor=block_residual) elif isinstance(residual_form_or_vector, GenericBlockVector): residual_form_or_vector = as_backend_type(residual_form_or_vector) block_residual = as_backend_type(block_residual) residual_form_or_vector.vec().swap(block_residual.vec()) assert residual_form_or_vector.has_block_dof_map() block_dofmap = residual_form_or_vector.get_block_dof_map() if not block_residual.has_block_dof_map(): block_residual.attach_block_dof_map(block_dofmap) else: assert block_dofmap == block_residual.get_block_dof_map() else: raise AssertionError( "Invalid case in BlockNonlinearProblem._block_residual_vector_assemble." ) def J(self, fenics_jacobian, _): # No need to update block solution subfunctions, this has already been done in the residual # Wrap FEniCS jacobian into a block jacobian block_jacobian = self.block_backend.wrap_matrix(fenics_jacobian) # Assemble the block jacobian assembled = self._block_jacobian_matrix_assemble( block_jacobian, self.block_solution) # =========== PETScSNESSolver::init() workaround for assembled matrices =========== # if not assembled: assert not self._J_assemble_failed_in_init # This should happen only once self._J_assemble_failed_in_init = True return # === end === PETScSNESSolver::init() workaround for assembled matrices === end === # # Apply boundary conditions if self.bcs is not None: self.bcs.apply(block_jacobian) def _block_jacobian_matrix_assemble(self, block_jacobian, block_solution): assert isinstance( self.jacobian_form_or_eval, (list, array, BlockForm2, types.FunctionType, types.MethodType)) if isinstance(self.jacobian_form_or_eval, (list, array, BlockForm2)): jacobian_form_or_matrix = self.jacobian_form_or_eval elif isinstance(self.jacobian_form_or_eval, (types.FunctionType, types.MethodType)): jacobian_form_or_matrix = self.jacobian_form_or_eval( block_solution) else: raise AssertionError( "Invalid case in BlockNonlinearProblem._block_jacobian_matrix_assemble." ) assert isinstance(jacobian_form_or_matrix, (list, array, BlockForm2, GenericBlockMatrix)) if isinstance(jacobian_form_or_matrix, (list, array, BlockForm2)): block_assemble(jacobian_form_or_matrix, block_tensor=block_jacobian) return True elif isinstance(jacobian_form_or_matrix, GenericBlockMatrix): # =========== PETScSNESSolver::init() workaround for assembled matrices =========== # if block_jacobian.empty(): return False # === end === PETScSNESSolver::init() workaround for assembled matrices === end === # else: jacobian_form_or_matrix = as_backend_type( jacobian_form_or_matrix) block_jacobian = as_backend_type(block_jacobian) block_jacobian.zero() block_jacobian += jacobian_form_or_matrix assert jacobian_form_or_matrix.has_block_dof_map(0) assert jacobian_form_or_matrix.has_block_dof_map(1) block_dofmap_0 = jacobian_form_or_matrix.get_block_dof_map(0) block_dofmap_1 = jacobian_form_or_matrix.get_block_dof_map(0) assert block_jacobian.has_block_dof_map( 0) == block_jacobian.has_block_dof_map(1) if not block_jacobian.has_block_dof_map(0): block_jacobian.attach_block_dof_map( block_dofmap_0, block_dofmap_1) else: assert block_dofmap_0 == block_jacobian.get_block_dof_map( 0) assert block_dofmap_1 == block_jacobian.get_block_dof_map( 1) return True else: raise AssertionError( "Invalid case in BlockNonlinearProblem._block_jacobian_matrix_assemble." )