def __init__(self, block_form, block_function_space, form_compiler_parameters=None): # Store UFL form self._block_form = block_form # Store block function space assert len(block_function_space) == 2 self._block_function_space = block_function_space # Replace UFL form by Dolfin form before passing it to the constructor # (note that we assume that block_form has been already preprocessed, # so we can assume that nested blocks have been unrolled and zero # placeholders have been replaced by zero forms) N = len(block_form) M = len(block_form[0]) assert all([len(block_form_I) == M for block_form_I in block_form]) replaced_block_form = empty((N, M), dtype=object) for I in range(N): for J in range(M): if isinstance(block_form[I, J], Form) and has_exact_type(block_form[I, J], CoefficientDerivative): block_form[I, J] = expand_derivatives(block_form[I, J]) replaced_block_form[I, J] = block_replace_zero(block_form, (I, J), block_function_space) assert isinstance(replaced_block_form[I, J], Form) or _is_zero(replaced_block_form[I, J]) if isinstance(replaced_block_form[I, J], Form): replaced_block_form[I, J] = _create_dolfin_form( form=replaced_block_form[I, J], form_compiler_parameters=form_compiler_parameters ) elif _is_zero(replaced_block_form[I, J]): assert isinstance(replaced_block_form[I, J], cpp_Form) else: raise TypeError("Invalid form") BlockForm2_Base.__init__(self, replaced_block_form.tolist(), [block_function_space_.cpp_object() for block_function_space_ in block_function_space]) # Store sizes for shape method self.N = N self.M = M
def __init__(self, block_form, block_function_space, form_compiler_parameters=None): # Store UFL form self._block_form = block_form # Store block function space assert len(block_function_space) == 1 self._block_function_space = block_function_space # Replace UFL form by Dolfin form before passing it to the constructor # (note that we assume that block_form has been already preprocessed, # so we can assume that nested blocks have been unrolled and zero # placeholders have been replaced by zero forms) N = len(block_form) replaced_block_form = empty((N, ), dtype=object) for I in range(N): replaced_block_form[I] = block_replace_zero(block_form, (I, ), block_function_space) assert isinstance(replaced_block_form[I], Form) or _is_zero(replaced_block_form[I]) if isinstance(replaced_block_form[I], Form): replaced_block_form[I] = _create_dolfin_form( form=replaced_block_form[I], form_compiler_parameters=form_compiler_parameters ) elif _is_zero(replaced_block_form[I]): assert isinstance(replaced_block_form[I], cpp_Form) else: raise TypeError("Invalid form") BlockForm1_Base.__init__(self, replaced_block_form.tolist(), [block_function_space_.cpp_object() for block_function_space_ in block_function_space]) # Store size for len and shape method self.N = N
def block_adjoint(block_form): assert isinstance(block_form, (array, list, BlockForm2)) if isinstance(block_form, (array, list)): input_type = array (block_form, block_function_space, block_form_rank) = _block_form_preprocessing(block_form) assert block_form_rank == 2 N = len(block_form) M = len(block_form[0]) block_adjoint_function_space = [block_function_space[1], block_function_space[0]] else: input_type = BlockForm2 N = block_form.block_size(0) M = block_form.block_size(1) block_adjoint_function_space = [block_form.block_function_spaces(1), block_form.block_function_spaces(0)] block_test_function_adjoint = BlockTestFunction(block_adjoint_function_space[0]) block_trial_function_adjoint = BlockTrialFunction(block_adjoint_function_space[1]) block_adjoint_form = empty((M, N), dtype=object) for I in range(N): for J in range(M): assert isinstance(block_form[I, J], Form) or _is_zero(block_form[I, J]) if isinstance(block_form[I, J], Form): block_adjoint_form[J, I] = adjoint(block_form[I, J], (block_test_function_adjoint[J], block_trial_function_adjoint[I])) elif _is_zero(block_form[I, J]): block_adjoint_form[J, I] = 0 else: raise TypeError("Invalid form") if input_type is array: return block_adjoint_form elif input_type is BlockForm2: return BlockForm2(block_adjoint_form, block_function_space=block_adjoint_function_space)
def _block_form_preprocessing(block_form, block_function_space=None, block_form_rank=None): assert isinstance(block_form, (array, list)) if block_form_rank is None: block_form_rank = _get_block_form_rank(block_form) assert block_form_rank is not None, \ "A block form rank should be provided when assemblying a zero block vector/matrix." assert block_form_rank in (1, 2) if block_form_rank == 2: # Extract BlockFunctionSpace from the current form, if required if not block_function_space: assert not all([_is_zero(block_form_I_J) for block_form_I in block_form for block_form_I_J in block_form_I]), \ "A BlockFunctionSpace should be provided when assemblying a zero block matrix." block_function_space = _extract_block_function_space_2(block_form) assert len(block_function_space) == 2 assert block_function_space[0] is not None assert block_function_space[1] is not None block_function_space = [ block_function_space[0], block_function_space[1] ] # convert from dict to list else: assert isinstance(block_function_space, list) assert len(block_function_space) == 2 assert isinstance(block_function_space[0], BlockFunctionSpace) assert isinstance(block_function_space[1], BlockFunctionSpace) # Flatten nested blocks, if any block_form = block_flatten_nested(block_form, block_function_space) # Return preprocessed data return (block_form, block_function_space, block_form_rank) elif block_form_rank == 1: # Extract BlockFunctionSpace from the current form, if required if not block_function_space: assert not all([_is_zero(block_form_I) for block_form_I in block_form]), \ "A BlockFunctionSpace should be provided when assemblying a zero block vector." block_function_space = _extract_block_function_space_1(block_form) assert len(block_function_space) == 1 assert block_function_space[0] is not None block_function_space = [block_function_space[0] ] # convert from dict to list else: assert isinstance(block_function_space, BlockFunctionSpace) block_function_space = [block_function_space] # Flatten nested blocks, if any block_form = block_flatten_nested(block_form, block_function_space) # Return preprocessed data return (block_form, block_function_space, block_form_rank)
def __rmul__(self, other): if isinstance(other, float): output_block_form = empty((self.N, ), dtype=object) for I in range(self.N): assert isinstance(self[I], Form) or _is_zero(self[I]) if isinstance(self[I], Form): output_block_form[I] = other*self[I] elif _is_zero(self[I]): output_block_form[I] = 0 else: raise TypeError("Invalid form") return BlockForm1(output_block_form, self._block_function_space) else: return NotImplemented
def _extract_block_function_space_1(block_form): block_function_space = dict() for block_form_I in block_form: if _is_zero(block_form_I): continue elif isinstance(block_form_I, (array, list)): if isinstance(block_form_I[0], list) or isinstance( block_form_I[0], array): block_function_space_recursive = _extract_block_function_space_2( block_form_I) else: block_function_space_recursive = _extract_block_function_space_1( block_form_I) for (number, block_function_space_number ) in block_function_space_recursive.items(): if number in block_function_space: assert block_function_space[ number] == block_function_space_number else: block_function_space[number] = block_function_space_number else: assert isinstance(block_form_I, Form) for (index, arg) in enumerate(block_form_I.arguments()): number = arg.number() block_function_space_arg = arg.block_function_space() if number in block_function_space: assert block_function_space[ number] == block_function_space_arg else: block_function_space[number] = block_function_space_arg return block_function_space
def block_derivative(F, u, du): assert isinstance(F, (array, list, BlockForm1)) if isinstance(F, (array, list)): input_type = array (F, block_V, block_form_rank) = _block_form_preprocessing(F) assert block_form_rank == 1 else: input_type = BlockForm1 block_V = F.block_function_spaces() assert len(block_V) == 1 block_V = block_V[0] # Compute the derivative assert len(F) == len(u) == len(du) J = empty((len(F), len(u)), dtype=object) for i in range(len(F)): if not _is_zero(F[i]): for j in range(len(u)): J[i, j] = derivative(F[i], u[j], du[j]) else: J[i, :] = 0 if input_type is array: return J elif input_type is BlockForm1: return BlockForm2(J, block_function_space=[du.block_function_space(), block_V])
def _flatten_nested_1(form_or_block_form, flattened_block_form, block_function_space): is_zero = _is_zero(form_or_block_form) assert is_zero or isinstance(form_or_block_form, (array, Form, list)) if is_zero: pass elif isinstance(form_or_block_form, Form): args = _extract_arguments(form_or_block_form) test_block_index = None test_block_function_space = None for arg in args: assert arg.number() == 0 if test_block_index is not None: assert test_block_index == arg.block_index(), "Test functions corresponding to different blocks appear in the same form." assert test_block_function_space == arg.block_function_space(), "Test functions defined in different block function spaces appear in the same form." else: test_block_index = arg.block_index() test_block_function_space = arg.block_function_space() assert test_block_index is not None assert test_block_function_space is not None if hasattr(block_function_space[0], "is_block_subspace"): assert test_block_index in block_function_space[0].components_to_sub_components, "Block function space and test block index are not consistent on the sub space." test_block_index = block_function_space[0].components_to_sub_components[test_block_index] assert test_block_function_space == block_function_space[0].parent_block_function_space else: assert test_block_function_space == block_function_space[0] flattened_block_form[test_block_index] += form_or_block_form elif isinstance(form_or_block_form, (array, list)): assert _get_block_form_rank(form_or_block_form) == 1 for block_form_I_nested in form_or_block_form: _flatten_nested_1(block_form_I_nested, flattened_block_form, block_function_space) else: raise AssertionError("Invalid case in _flatten_nested_1")
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 __add__(self, other): if isinstance(other, BlockForm2): assert self.N == other.N assert self.M == other.M assert self._block_function_space[ 0] is other._block_function_space[0] assert self._block_function_space[ 1] is other._block_function_space[1] output_block_form = empty((self.N, self.M), dtype=object) for I in range(self.N): for J in range(self.M): assert isinstance(self[I, J], Form) or _is_zero(self[I, J]) assert isinstance(other[I, J], Form) or _is_zero(other[I, J]) if (isinstance(self[I, J], Form) and isinstance(other[I, J], Form)): output_block_form[I, J] = self[I, J] + other[I, J] elif (isinstance(self[I, J], Form) and _is_zero(other[I, J])): output_block_form[I, J] = self[I, J] elif (isinstance(other[I, J], Form) and _is_zero(self[I, J])): output_block_form[I, J] = other[I, J] elif (_is_zero(self[I, J]) and _is_zero(other[I, J])): output_block_form[I, J] = 0 else: raise TypeError("Invalid form") return BlockForm2(output_block_form, self._block_function_space) else: return NotImplemented
def _block_form_preprocessing(block_form, block_function_space=None, block_form_rank=None): assert isinstance(block_form, (array, list)) if block_form_rank is None: block_form_rank = _get_block_form_rank(block_form) assert block_form_rank is not None, \ "A block form rank should be provided when assemblying a zero block vector/matrix." assert block_form_rank in (1, 2) if block_form_rank is 2: # Extract BlockFunctionSpace from the current form, if required if not block_function_space: assert not all([_is_zero(block_form_I_J) for block_form_I in block_form for block_form_I_J in block_form_I]), \ "A BlockFunctionSpace should be provided when assemblying a zero block matrix." block_function_space = _extract_block_function_space_2(block_form) assert len(block_function_space) == 2 assert block_function_space[0] is not None assert block_function_space[1] is not None block_function_space = [ block_function_space[0], block_function_space[1] ] # convert from dict to list else: assert isinstance(block_function_space, list) assert len(block_function_space) is 2 assert isinstance(block_function_space[0], BlockFunctionSpace) assert isinstance(block_function_space[1], BlockFunctionSpace) # Flatten nested blocks, if any block_form = block_flatten_nested(block_form, block_function_space) # ... and compute size accordingly if block_function_space[0] == block_function_space[1]: _assert_flattened_form_2_is_square(block_form) N = len(block_form) M = len(block_form[0]) # Replace zero blocks, if any replaced_block_form = empty((N, M), dtype=object) for I in range(N): for J in range(M): replaced_block_form[I, J] = block_replace_zero( block_form, (I, J), block_function_space) # Return preprocessed data return (replaced_block_form, block_function_space, block_form_rank) elif block_form_rank is 1: # Extract BlockFunctionSpace from the current form, if required if not block_function_space: assert not all([_is_zero(block_form_I) for block_form_I in block_form]), \ "A BlockFunctionSpace should be provided when assemblying a zero block vector." block_function_space = _extract_block_function_space_1(block_form) assert len(block_function_space) == 1 assert block_function_space[0] is not None block_function_space = [block_function_space[0] ] # convert from dict to list else: assert isinstance(block_function_space, BlockFunctionSpace) block_function_space = [block_function_space] # Flatten nested blocks, if any block_form = block_flatten_nested(block_form, block_function_space) # ... and compute size accordingly N = len(block_form) # Replace zero blocks, if any replaced_block_form = empty((N, ), dtype=object) for I in range(N): replaced_block_form[I] = block_replace_zero( block_form, (I, ), block_function_space) # Return preprocessed data return (replaced_block_form, block_function_space, block_form_rank)