Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
 def _pack(form):
     if form is None:
         return {}
     elif isinstance(form, collections.abc.Iterable):
         return list(map(lambda sub_form: _pack(sub_form), form))
     else:
         return _pack_coefficients(form)
Ejemplo n.º 3
0
def apply_lifting(b: np.ndarray,
                  a: typing.List[FormMetaClass],
                  bcs: typing.List[typing.List[DirichletBCMetaClass]],
                  x0: typing.Optional[typing.List[np.ndarray]] = None,
                  scale: float = 1.0,
                  constants=None,
                  coeffs=None) -> None:
    """Modify RHS vector b for lifting of Dirichlet boundary conditions.

    It modifies b such that:

    .. math::

        b \\leftarrow  b - \\text{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.

    Note:
        Ghost contributions are not accumulated (not sent to owner).
        Caller is responsible for calling VecGhostUpdateBegin/End.

    """
    x0 = [] if x0 is None else x0
    constants = [form and _pack_constants(form)
                 for form in a] if constants is None else constants
    coeffs = [{} if form is None else _pack_coefficients(form)
              for form in a] if coeffs is None else coeffs
    _cpp.fem.apply_lifting(b, a, constants, coeffs, bcs, x0, scale)
Ejemplo n.º 4
0
def _(A: la.MatrixCSRMetaClass,
      a: FormMetaClass,
      bcs: typing.List[DirichletBCMetaClass] = None,
      diagonal: float = 1.0,
      constants=None,
      coeffs=None) -> la.MatrixCSRMetaClass:
    """Assemble bilinear form into a matrix.

        Args:
        a: The bilinear form assemble.
        bcs: Boundary conditions that affect the assembled matrix.
            Degrees-of-freedom constrained by a boundary condition will
            have their rows/columns zeroed and the value ``diagonal`` set
            on on the matrix diagonal.
        constants: Constants that appear in the form. If not provided,
            any required constants will be computed.
        coeffs: Coefficients that appear in the form. If not provided,
            any required coefficients will be computed.

    Note:
        The returned matrix is not finalised, i.e. ghost values are not
        accumulated.

    """
    bcs = [] if bcs is None else bcs
    constants = _pack_constants(a) if constants is None else constants
    coeffs = _pack_coefficients(a) if coeffs is None else coeffs
    _cpp.fem.assemble_matrix(A, a, constants, coeffs, bcs)

    # If matrix is a 'diagonal'block, set diagonal entry for constrained
    # dofs
    if a.function_spaces[0] is a.function_spaces[1]:
        _cpp.fem.insert_diagonal(A, a.function_spaces[0], bcs, diagonal)
    return A
Ejemplo n.º 5
0
def _(b: np.ndarray, L: FormMetaClass, constants=None, coeffs=None):
    """Assemble linear form into a new Vector.

    Args:
        b: The array to assemble the contribution from the calling MPI
            rank into. It must have the required size.
        L: The linear form assemble.
        constants: Constants that appear in the form. If not provided,
            any required constants will be computed.
        coeffs: Coefficients that appear in the form. If not provided,
            any required coefficients will be computed.

    Note:
        Passing `constants` and `coefficients` is a performance
        optimisation for when a form is assembled multiple times and
        when (some) constants and coefficients are unchanged.

    Note:
        The returned vector is not finalised, i.e. ghost values are not
        accumulated on the owning processes. Calling
        :func:`dolfinx.la.VectorMetaClass.scatter_reverse` on the
        return vector can accumulate ghost contributions.

    """

    constants = _pack_constants(L) if constants is None else constants
    coeffs = _pack_coefficients(L) if coeffs is None else coeffs
    _cpp.fem.assemble_vector(b, L, constants, coeffs)
    return b
Ejemplo n.º 6
0
def assemble_vector(L: FormMetaClass,
                    constants=None,
                    coeffs=None) -> la.VectorMetaClass:
    """Assemble linear form into a new Vector.

    Args:
        L: The linear form assemble.
        constants: Constants that appear in the form. If not provided,
            any required constants will be computed.
        coeffs: Coefficients that appear in the form. If not provided,
            any required coefficients will be computed.

    Return:
        The assembled vector for the calling rank.

    Note:
        Passing `constants` and `coefficients` is a performance
        optimisation for when a form is assembled multiple times and
        when (some) constants and coefficients are unchanged.

    Note:
        The returned vector is not finalised, i.e. ghost values are not
        accumulated on the owning processes. Calling
        :func:`dolfinx.la.VectorMetaClass.scatter_reverse` on the
        return vector can accumulate ghost contributions.

    """
    b = create_vector(L)
    b.array[:] = 0
    constants = constants or _pack_constants(L)
    coeffs = coeffs or _pack_coefficients(L)
    _cpp.fem.assemble_vector(b.array, L, constants, coeffs)
    return b
Ejemplo n.º 7
0
def assemble_scalar(M: FormMetaClass, constants=None, coeffs=None):
    """Assemble functional. The returned value is local and not
    accumulated across processes.

    Args:
        M: The functional to compute.
        constants: Constants that appear in the form. If not provided,
            any required constants will be computed.
        coeffs: Coefficients that appear in the form. If not provided,
            any required coefficients will be computed.

    Return:
        The computed scalar on the calling rank.

    Note:
        Passing `constants` and `coefficients` is a performance
        optimisation for when a form is assembled multiple times and
        when (some) constants and coefficients are unchanged.

        To compute the functional value on the whole domain, the output
        of this function is typically summed across all MPI ranks.

    """
    constants = constants or _pack_constants(M)
    coeffs = coeffs or _pack_coefficients(M)
    return _cpp.fem.assemble_scalar(M, constants, coeffs)
Ejemplo n.º 8
0
def _(A: PETSc.Mat,
      a: typing.List[typing.List[FormMetaClass]],
      bcs: typing.List[DirichletBCMetaClass] = [],
      diagonal: float = 1.0,
      constants=None,
      coeffs=None) -> PETSc.Mat:
    """Assemble bilinear forms into matrix"""

    constants = [[form and _pack_constants(form) for form in forms]
                 for forms in a] if constants is None else constants
    coeffs = [[{} if form is None else _pack_coefficients(form)
               for form in forms] for forms in a] if coeffs is None else coeffs

    V = _extract_function_spaces(a)
    is_rows = _cpp.la.petsc.create_index_sets([
        (Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[0]
    ])
    is_cols = _cpp.la.petsc.create_index_sets([
        (Vsub.dofmap.index_map, Vsub.dofmap.index_map_bs) for Vsub in V[1]
    ])

    # Assemble form
    for i, a_row in enumerate(a):
        for j, a_sub in enumerate(a_row):
            if a_sub is not None:
                Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j])
                _cpp.fem.petsc.assemble_matrix(Asub, a_sub, constants[i][j],
                                               coeffs[i][j], bcs, True)
                A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub)

    # Flush to enable switch from add to set in the matrix
    A.assemble(PETSc.Mat.AssemblyType.FLUSH)

    # Set diagonal
    for i, a_row in enumerate(a):
        for j, a_sub in enumerate(a_row):
            if a_sub is not None:
                Asub = A.getLocalSubMatrix(is_rows[i], is_cols[j])
                if a_sub.function_spaces[0] is a_sub.function_spaces[1]:
                    _cpp.fem.petsc.insert_diagonal(Asub,
                                                   a_sub.function_spaces[0],
                                                   bcs, diagonal)
                A.restoreLocalSubMatrix(is_rows[i], is_cols[j], Asub)

    return A
Ejemplo n.º 9
0
def _(A: PETSc.Mat,
      a: FormMetaClass,
      bcs: typing.List[DirichletBCMetaClass] = [],
      diagonal: float = 1.0,
      constants=None,
      coeffs=None) -> PETSc.Mat:
    """Assemble bilinear form into a matrix. The returned matrix is not
    finalised, i.e. ghost values are not accumulated.

    """
    constants = _pack_constants(a) if constants is None else constants
    coeffs = _pack_coefficients(a) if coeffs is None else coeffs
    _cpp.fem.petsc.assemble_matrix(A, a, constants, coeffs, bcs)
    if a.function_spaces[0] is a.function_spaces[1]:
        A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH)
        A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH)
        _cpp.fem.petsc.insert_diagonal(A, a.function_spaces[0], bcs, diagonal)
    return A
Ejemplo n.º 10
0
def _(A: PETSc.Mat,
      a: typing.List[typing.List[FormMetaClass]],
      bcs: typing.List[DirichletBCMetaClass] = [],
      diagonal: float = 1.0,
      constants=None,
      coeffs=None) -> PETSc.Mat:
    """Assemble bilinear forms into matrix"""
    constants = [[form and _pack_constants(form) for form in forms]
                 for forms in a] if constants is None else constants
    coeffs = [[{} if form is None else _pack_coefficients(form)
               for form in forms] for forms in a] if coeffs is None else coeffs
    for i, (a_row, const_row,
            coeff_row) in enumerate(zip(a, constants, coeffs)):
        for j, (a_block, const,
                coeff) in enumerate(zip(a_row, const_row, coeff_row)):
            if a_block is not None:
                Asub = A.getNestSubMatrix(i, j)
                assemble_matrix(Asub, a_block, bcs, diagonal, const, coeff)
    return A
Ejemplo n.º 11
0
def apply_lifting_nest(b: PETSc.Vec,
                       a: typing.List[typing.List[FormMetaClass]],
                       bcs: typing.List[DirichletBCMetaClass],
                       x0: typing.Optional[PETSc.Vec] = None,
                       scale: float = 1.0,
                       constants=None,
                       coeffs=None) -> PETSc.Vec:
    """Apply the function :func:`dolfinx.fem.apply_lifting` to each sub-vector in a nested PETSc Vector."""

    x0 = [] if x0 is None else x0.getNestSubVecs()
    bcs1 = _bcs_by_block(_extract_spaces(a, 1), bcs)

    constants = [[form and _pack_constants(form) for form in forms]
                 for forms in a] if constants is None else constants
    coeffs = [[{} if form is None else _pack_coefficients(form)
               for form in forms] for forms in a] if coeffs is None else coeffs
    for b_sub, a_sub, const, coeff in zip(b.getNestSubVecs(), a, constants,
                                          coeffs):
        apply_lifting(b_sub, a_sub, bcs1, x0, scale, const, coeff)
    return b