예제 #1
0
def injection_matrix(Vc, Vf, fine_mesh, data):
    '''Injection mapping from Vc to Vf'''
    mesh_c = Vc.mesh()
    assert fine_mesh.id() == Vf.mesh().id()
    mesh_f = Vf.mesh()

    if data['not_nested_method'] == 'interpolate':
        return df.PETScDMCollection.create_transfer_matrix(Vc, Vf)
    elif data['not_nested_method'] == 'project':
        raise ValueError('Missing projection')

    # Fallback to our interpolate with lookup, which, however is slower
    # to `create_transfer_matrix`

    tdim = mesh_f.topology().dim()
    # Refine was used to create it
    keys, fine_to_coarse = list(
        zip(*list(fine_mesh.parent_entity_map[mesh_c.id()][tdim].items())))
    fine_to_coarse = np.array(fine_to_coarse, dtype='uintp')
    fine_to_coarse[np.argsort(keys)] = fine_to_coarse

    # The idea is to evaluate Vf's degrees of freedom at basis functions of Vc
    fdmap = Vf.dofmap()
    Vf_dof = DegreeOfFreedom(Vf)

    cdmap = Vc.dofmap()
    Vc_basis_f = FEBasisFunction(Vc)

    # Column values
    visited_rows = [False] * Vf.dim()
    row_values = np.zeros(Vc_basis_f.elm.space_dimension(), dtype='double')

    with petsc_serial_matrix(Vf, Vc) as mat:

        for f_cell, c_cell in enumerate(fine_to_coarse):

            Vc_basis_f.cell = c_cell
            # These are the colums
            coarse_dofs = cdmap.cell_dofs(c_cell)

            Vf_dof.cell = f_cell

            fine_dofs = fdmap.cell_dofs(f_cell)

            for local, dof in enumerate(fine_dofs):
                if visited_rows[dof]:
                    continue
                else:
                    visited_rows[dof] = True

                Vf_dof.dof = local
                # Evaluete coarse basis foos here
                for local_c, dof_c in enumerate(coarse_dofs):
                    Vc_basis_f.dof = local_c
                    row_values[local_c] = Vf_dof.eval(Vc_basis_f)
                # Insert
                mat.setValues([dof], coarse_dofs, row_values,
                              PETSc.InsertMode.INSERT_VALUES)

    return PETScMatrix(mat)
예제 #2
0
def restriction_matrix(V, TV, rmesh):
    '''The first cell connected to the facet gets to set the values of TV'''
    assert TV.mesh().id() == rmesh.id()

    mesh = V.mesh()
    tdim = mesh.topology().dim()

    # Let's get the mapping or cell of TV mesh to V mesh cells
    mapping = rmesh.parent_entity_map[mesh.id()][tdim]
    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Rows
    visited_dofs = [False] * TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(TV.mesh().num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)
            # The corresponding cell in V mesh
            cell = mapping[trace_cell]
            V_basis_f.cell = cell

            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T

                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local

                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #3
0
def restriction_matrix(V, TV, rmesh):
    '''The first cell connected to the facet gets to set the values of TV'''
    assert TV.mesh().id() == rmesh.id()
    
    mesh = V.mesh()
    tdim = mesh.topology().dim()
    
    # Let's get the mapping or cell of TV mesh to V mesh cells
    mapping = rmesh.parent_entity_map[mesh.id()][tdim]  
    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Rows
    visited_dofs = [False]*TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(TV.mesh().num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)
            # The corresponding cell in V mesh
            cell = mapping[trace_cell]
            V_basis_f.cell = cell
            
            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T
                
                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local
                    
                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #4
0
def injection_matrix(Vc, Vf):
    '''Injection mapping from Vc to Vf'''
    mesh_c = Vc.mesh()
    mesh_f = Vf.mesh()

    assert mesh_f.has_parent() and mesh_c.has_child()
    assert mesh_f.parent().id() == mesh_c.id()

    fine_to_coarse = mesh_f.data().array('parent_cell',
                                         mesh_f.topology().dim())

    # The idea is to evaluate Vf's degrees of freedom at basis functions of Vc
    fdmap = Vf.dofmap()
    Vf_dof = DegreeOfFreedom(Vf)

    cdmap = Vc.dofmap()
    Vc_basis_f = FEBasisFunction(Vc)

    # Column values
    visited_rows = [False] * Vf.dim()
    row_values = np.zeros(Vc_basis_f.elm.space_dimension(), dtype='double')

    with petsc_serial_matrix(Vf, Vc) as mat:

        for f_cell, c_cell in enumerate(fine_to_coarse):

            Vc_basis_f.cell = c_cell
            # These are the colums
            coarse_dofs = cdmap.cell_dofs(c_cell)

            Vf_dof.cell = f_cell

            fine_dofs = fdmap.cell_dofs(f_cell)

            for local, dof in enumerate(fine_dofs):
                if visited_rows[dof]:
                    continue
                else:
                    visited_rows[dof] = True

                Vf_dof.dof = local
                # Evaluete coarse basis foos here
                for local_c, dof_c in enumerate(coarse_dofs):
                    Vc_basis_f.dof = local_c
                    row_values[local_c] = Vf_dof.eval(Vc_basis_f)
                # Insert
                mat.setValues([dof], coarse_dofs, row_values,
                              PETSc.InsertMode.INSERT_VALUES)
    # Transpose
    return mat
예제 #5
0
def interpolation_mat(V, Q):
    '''
    Matrix representation of interpolation operator from V to Q
    '''
    # Compatibility of spaces
    assert V.dolfin_element().value_rank() == Q.dolfin_element().value_rank()
    assert V.ufl_element().value_shape() == Q.ufl_element().value_shape()
    # We assume that the spaces are constructed on the same mesh
    assert V.mesh().id() == Q.mesh().id()

    # The idea is to evaluate Q's degrees of freedom at basis functions of V
    V_dm = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    Q_dm = Q.dofmap()
    Q_dof = DegreeOfFreedom(Q)

    visited_rows = np.zeros(Q.dim(), dtype=bool)
    # Column values for row
    column_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(Q, V) as mat:

        for cell in xrange(V.mesh().num_cells()):
            Q_dof.cell = cell
            V_basis_f.cell = cell

            cell_rows = Q_dm.cell_dofs(cell)
            column_indices = np.array(V_dm.cell_dofs(cell), dtype='int32')
            for local_row, row in enumerate(cell_rows):
                if visited_rows[row]: continue

                visited_rows[row] = True
                # Define dof
                Q_dof.dof = local_row

                # Eval at V basis functions
                for local_col, col in enumerate(column_indices):
                    # Set which basis foo
                    V_basis_f.dof = local_col
                    column_values[local_col] = Q_dof.eval(V_basis_f)
                # Can fill the matrix now
                mat.setValues([row], column_indices, column_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #6
0
def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None):
    '''The first cell connected to the facet gets to set the values of TV'''
    mesh = V.mesh()

    if trace_mesh is None: trace_mesh = TV.mesh()

    fdim = trace_mesh.topology().dim()

    # None means all
    if tag_data is None:
        tag_data = (MeshFunction('size_t', trace_mesh,
                                 trace_mesh.topology().dim(), 0), set((0, )))

    trace_mesh_subdomains, tags = tag_data
    # Init/extract the mapping
    try:
        assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags)
    except (AssertionError, IndexError):
        warning('Using non-conforming trace')
        # So non-conforming matrix returns PETSc.Mat
        return nonconforming_trace_mat(V, TV)

    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim + 1)
    f2c = mesh.topology()(fdim, fdim + 1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Only look at tagged cells
    trace_cells = itertools.chain(*[
        itertools.imap(operator.methodcaller('index'),
                       SubsetIterator(trace_mesh_subdomains, tag))
        for tag in tags
    ])

    # Rows
    visited_dofs = [False] * TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in trace_cells:
            # We might
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here. Does not matter which
            # cell of the connected ones we pick
            cell = f2c(mapping[trace_cell])[0]
            V_basis_f.cell = cell

            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T

                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local

                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #7
0
def trace_mat_two_restrict(V, TV, restriction, normal, trace_mesh=None):
    '''
    Compute the trace values using avg/jump restriction. A + plus is the one 
    for which the vector cell.midpoint - facet.midpoint agrees in orientation
    with the normal on the facet.
    '''
    mesh = V.mesh()
    fdim = mesh.topology().dim() - 1

    if trace_mesh is None: trace_mesh = TV.mesh()

    # Init/extract entity map
    assert get_entity_map(mesh, trace_mesh)
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim + 1)
    f2c = mesh.topology()(fdim, fdim + 1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # We define avg as sum(+, -)/2 and jump as sum(+, neg(-))
    operator_pieces = {
        'avg': (lambda x: x / 2, lambda x: x / 2),
        'jump': (lambda x: x, lambda x: -x)
    }[restriction]

    gdim = mesh.geometry().dim()
    # Rows
    visited_dofs = [False] * TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(trace_mesh.num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here
            facet_cells = f2c(mapping[trace_cell])

            assert 0 < len(facet_cells) < 3
            # Ignore boundary facets
            if len(facet_cells) == 1:
                facet_cells = [facet_cells[0]]
                modifiers = (lambda x: x, )  # Do nothing
            # Search which cell has the right sign
            else:
                signs = [None, None]
                # Order such that '+' is first
                t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim]
                mp = Cell(mesh, facet_cells[0]).midpoint().array()[:gdim]

                sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-'
                # Need to flip
                if sign == '-':
                    facet_cells = facet_cells[::-1]
                # As requested
                modifiers = operator_pieces

            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T

                # Two sweeps to set the values in the row
                ADD_VALUES = False
                for modify, cell in zip(modifiers, facet_cells):
                    V_basis_f.cell = cell
                    dofs = dmap.cell_dofs(cell)

                    # Eval at V basis functions
                    for local, dof in enumerate(dofs):
                        # Set which basis foo
                        V_basis_f.dof = local
                        dof_values[local] = modify(TV_dof.eval(V_basis_f))
                    # Can fill the matrix now
                    col_indices = np.array(dofs, dtype='int32')

                    if not ADD_VALUES:
                        mat.setValues([dof_T], col_indices, dof_values,
                                      PETSc.InsertMode.INSERT_VALUES)
                        ADD_VALUES = True
                        #print 'setting', dof_T, col_indices, dof_values
                    else:
                        mat.setValues([dof_T], col_indices, dof_values,
                                      PETSc.InsertMode.ADD_VALUES)
                        #print 'adding', dof_T, col_indices, dof_values
    return mat
예제 #8
0
def trace_mat_one_restrict(V,
                           TV,
                           restriction,
                           normal,
                           trace_mesh=None,
                           tag_data=None):
    '''
    Compute the trace values using +/- restriction. A + plus is the one 
    for which the vector cell.midpoint - facet.midpoint agrees in orientation
    with the normal on the facet.
    '''
    mesh = V.mesh()
    fdim = mesh.topology().dim() - 1

    if trace_mesh is None: trace_mesh = TV.mesh()

    # None means all
    if tag_data is None:
        tag_data = (MeshFunction('size_t', trace_mesh,
                                 trace_mesh.topology().dim(), 0), set((0, )))
    trace_mesh_subdomains, tags = tag_data

    # Only look at tagged cells
    trace_cells = itertools.chain(*[
        itertools.imap(operator.methodcaller('index'),
                       SubsetIterator(trace_mesh_subdomains, tag))
        for tag in tags
    ])

    # Init/extract entity map
    assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags)
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim + 1)
    f2c = mesh.topology()(fdim, fdim + 1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    gdim = mesh.geometry().dim()
    # Rows
    visited_dofs = [False] * TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in trace_cells:
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here
            facet_cells = f2c(mapping[trace_cell])

            assert 0 < len(facet_cells) < 3
            # Ignore boundary facets
            if len(facet_cells) == 1:
                cell = facet_cells[0]
            # Search which cell has the right sign
            else:
                signs = []
                for fcell in facet_cells:
                    t_mp = Cell(trace_mesh,
                                trace_cell).midpoint().array()[:gdim]
                    mp = Cell(mesh, fcell).midpoint().array()[:gdim]

                    sign = '+' if np.inner(mp -
                                           t_mp, normal(t_mp)) > 0 else '-'
                    signs.append(sign)
                cell = facet_cells[signs.index(restriction)]
            V_basis_f.cell = cell

            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T

                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local

                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #9
0
def trace_mat_no_restrict(V, TV, trace_mesh=None):
    '''The first cell connected to the facet gets to set the values of TV'''
    mesh = V.mesh()

    if trace_mesh is None: trace_mesh = TV.mesh()

    fdim = trace_mesh.topology().dim()

    # Init/extract the mapping
    assert get_entity_map(mesh, trace_mesh)
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim + 1)
    f2c = mesh.topology()(fdim, fdim + 1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Rows
    visited_dofs = [False] * TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(TV.mesh().num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here. Does not matter which
            # cell of the connected ones we pick
            cell = f2c(mapping[trace_cell])[0]
            V_basis_f.cell = cell

            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T

                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local

                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #10
0
def nonconforming_trace_mat(V, T):
    '''
    Matrix taking function f from d dim space V to g in (d-1) space T. 
    T(f) ~ g should hold.
    '''
    # For this to work I only make sure that function values are the same
    assert V.ufl_element().value_shape() == T.ufl_element().value_shape()

    # I want to evaluate T degrees of freedom at V basis functions, i.e.
    # L^T_k{phi^V_l}. The picture is
    #
    #   ------
    #   \    /\
    # ===\==/==\====T
    #     \/----\
    #
    # and thus is assume that each dof of T space (row) will involve
    # collisions with several cells/basis function of V space. However
    # here we only snap to the first one

    mesh = V.mesh()  # The (d-1)trace mesh
    tree = mesh.bounding_box_tree()
    limit = mesh.num_entities_global(mesh.topology().dim())

    Tdm = T.dofmap()
    elm_T = T.element()
    # Colliding cells with trace dofs
    collisions = []
    for Tdof_x in T.tabulate_dof_coordinates().reshape((T.dim(), -1)):
        c = tree.compute_first_entity_collision(df.Point(*Tdof_x))
        # Contained?
        c >= limit and df.warning('Some colliding cells not found')

        collisions.append(c)

    # So we fill rows by checking basis functions of on the isected cells
    Vdm = V.dofmap()
    elm_V = V.element()

    V_basis_function = FEBasisFunction(V)
    T_degree_of_freedom = DegreeOfFreedom(T)

    X_T = T.tabulate_dof_coordinates().reshape((T.dim(), -1))
    X_V = V.tabulate_dof_coordinates().reshape((V.dim(), -1))

    visited_dofs = np.zeros(T.dim(), dtype=bool)
    col_values = np.zeros(V_basis_function.elm.space_dimension(),
                          dtype='double')
    with petsc_serial_matrix(T, V) as mat:

        for Tcell in range(T.mesh().num_cells()):
            # Set for this cell
            T_degree_of_freedom.cell = Tcell

            Tdofs = Tdm.cell_dofs(Tcell)
            for local_T, Tdof in enumerate(Tdofs):
                # Seen the row?
                if visited_dofs[Tdof]: continue

                visited_dofs[Tdof] = True

                # Set to current dof
                T_degree_of_freedom.dof = local_T

                # Now all the V cells and their basis functions
                c = collisions[Tdof]
                # If we have no reasonable cell leave the row empty
                if c >= limit: continue

                # Set the dof cell
                V_basis_function.cell = c

                Vdofs = np.array(Vdm.cell_dofs(c),
                                 dtype='int32')  # These are columns

                # Fill column
                for local_V, Vdof in enumerate(Vdofs):
                    # Set as basis_function
                    V_basis_function.dof = local_V

                    # Evaluate trace dof at basis function
                    dof_value = T_degree_of_freedom.eval(V_basis_function)

                    col_values[local_V] = dof_value

                mat.setValues([Tdof], Vdofs, col_values,
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #11
0
def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None):
    '''The first cell connected to the facet gets to set the values of TV'''
    mesh = V.mesh()

    if trace_mesh is None: trace_mesh = TV.mesh()

    fdim = trace_mesh.topology().dim()

    # None means all
    if tag_data is None:
        try:
            marking_function = trace_mesh.marking_function
            tag_data = (marking_function, set(marking_function.array()))
        except AttributeError:
            tag_data = (MeshFunction('size_t', trace_mesh,
                                     trace_mesh.topology().dim(), 0), set(
                                         (0, )))

    trace_mesh_subdomains, tags = tag_data
    # Init/extract the mapping
    try:
        assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags)
    except (AssertionError, IndexError):
        warning('Using non-conforming trace')
        # So non-conforming matrix returns PETSc.Mat
        return nonconforming_trace_mat(V, TV)

    if V.ufl_element().family() == 'HDiv Trace':
        assert V.ufl_element().degree() == 0
        # In this case
        return DLT_trace_mat(V, TV, trace_mesh=trace_mesh, tag_data=tag_data)

    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim + 1)
    f2c = mesh.topology()(fdim, fdim + 1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Only look at tagged cells
    trace_cells = list(
        itertools.chain(*[
            map(operator.methodcaller('index'),
                SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags
        ]))

    ndofs_elm, nbasis_elm = TV_dof.elm.space_dimension(
    ), V_basis_f.elm.space_dimension()
    local_values = np.zeros((nbasis_elm, ndofs_elm))

    if len(trace_cells) > 10_000:
        print(f'Trace mat {TV.ufl_element()} -> {V.ufl_element()}')
        trace_cells = tqdm.tqdm(trace_cells, total=len(trace_cells))

    rows, cols, values = [], [], []
    # DG spaces don't share rows between cells so we take advantage of
    # this in special branch
    if TV.ufl_element().family() == 'Discontinuous Lagrange':
        for trace_cell in trace_cells:
            TV_dof.cell = trace_cell
            # Many rows at once
            trace_dofs = Tdmap.cell_dofs(trace_cell)
            # Figure out the dofs of V to use here. Does not matter which
            # cell of the connected ones we pick
            cell = f2c(mapping[trace_cell])[0]
            V_basis_f.cell = cell

            # Columns for the rows
            dofs = dmap.cell_dofs(cell)
            for local, dof in enumerate(dofs):
                # Set which basis foo
                V_basis_f.dof = local
                # Get all rows at once
                local_values[local][:] = TV_dof.eval_dofs(V_basis_f)
            # Indices for the filled piece
            rows_ = np.tile(trace_dofs, nbasis_elm)
            cols_ = np.repeat(dofs, ndofs_elm)

            rows.extend(rows_)
            cols.extend(cols_)
            values.extend(local_values.flat)
    # FIXME: Othewise we need to take care of duplicate entrieselse:
    else:
        needs_fill = np.ones(TV.dim(), dtype=bool)

        for trace_cell in trace_cells:
            TV_dof.cell = trace_cell
            # Many rows at once
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Don't add duplicates
            unseen = needs_fill[trace_dofs]  # Some will be true and
            # For the future
            needs_fill[trace_dofs[unseen]] = False

            # Figure out the dofs of V to use here. Does not matter which
            # cell of the connected ones we pick
            cell = f2c(mapping[trace_cell])[0]
            V_basis_f.cell = cell

            # Columns for the rows
            dofs = dmap.cell_dofs(cell)
            for local, dof in enumerate(dofs):
                # Set which basis foo
                V_basis_f.dof = local
                # Get all rows at once
                local_values[local][:] = TV_dof.eval_dofs(V_basis_f)
            # Indices for the filled piece
            rows_ = np.tile(trace_dofs[unseen], nbasis_elm)
            cols_ = np.repeat(dofs, sum(unseen))

            rows.extend(rows_)
            cols.extend(cols_)
            values.extend(local_values[:, unseen].flat)

    mat = csr_matrix((values, (rows, cols)), shape=(TV.dim(), V.dim()))

    return PETSc.Mat().createAIJ(comm=PETSc.COMM_WORLD,
                                 size=mat.shape,
                                 csr=(mat.indptr, mat.indices, mat.data))
def nonconforming_trace_mat(V, T):
    '''
    Matrix taking function f from d dim space V to g in (d-1) space T. 
    T(f) ~ g should hold.
    '''
    # For this to work I only make sure that function values are the same
    assert V.dolfin_element().value_rank() == T.dolfin_element().value_rank()
    assert V.ufl_element().value_shape() == T.ufl_element().value_shape()

    # I want to evaluate T degrees of freedom at V basis functions, i.e.
    # L^T_k{phi^V_l}. The picture is
    #
    #   ------
    #   \    /\
    # ===\==/==\====T
    #     \/----\
    #
    # and thus is assume that each dof of T space (row) will involve
    # collisions with several cells/basis function of V space
    
    mesh = V.mesh()  # The (d-1)trace mesh
    tree = mesh.bounding_box_tree()
    limit = mesh.topology().size_global(mesh.topology().dim())

    Tdm = T.dofmap()
    elm_T = T.element()
    # Colliding cells with trace dofs
    collisions = []
    for Tdof_x in T.tabulate_dof_coordinates().reshape((T.dim(), -1)):
        cs = tree.compute_entity_collisions(Point(*Tdof_x))
        if any(c >= limit for c in cs):
            warning('Some colliding cells not found')
            cs = filter(lambda c: c < limit, cs)
        collisions.append(cs)

    # So we fill rows by checking basis functions of on the isected cells
    Vdm = V.dofmap()
    elm_V = V.element()
    
    V_basis_function = FEBasisFunction(V)
    T_degree_of_freedom = DegreeOfFreedom(T)

    visited_dofs = [False]*T.dim()
    with petsc_serial_matrix(T, V) as mat:

        for Tcell in range(T.mesh().num_cells()):
            # Set for this cell
            T_degree_of_freedom.cell = Tcell
            
            Tdofs = Tdm.cell_dofs(Tcell)
            for local_T, Tdof in enumerate(Tdofs):
                # Seen the row?
                if visited_dofs[Tdof]: continue
                
                visited_dofs[Tdof] = True

                # Set to current dof
                T_degree_of_freedom.dof = local_T

                col_indices, col_values = [], []
                # Now all the V cells and their basis functions
                for c in collisions[Tdof]:
                    # Set the dof cell
                    V_basis_function.cell = c
                    
                    Vdofs = Vdm.cell_dofs(c)
                    # Columns
                    for local_V, Vdof in enumerate(Vdofs):
                        if Vdof in col_indices:
                            continue
                        
                        # Set as basis_function
                        V_basis_function.dof = local_V

                        # Evaluate trace dof at basis function
                        dof_value = T_degree_of_freedom.eval(V_basis_function)
                        col_indices.append(Vdof)
                        col_values.append(dof_value)
                # Can fill the matrix row
                col_indices = np.array(col_indices, dtype='int32')
                col_values = np.array(col_values)

                mat.setValues([Tdof], col_indices, col_values, PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #13
0
def trace_mat_no_restrict(V, TV, trace_mesh=None):
    '''The first cell connected to the facet gets to set the values of TV'''
    mesh = V.mesh()

    if trace_mesh is None: trace_mesh = TV.mesh()

    fdim = trace_mesh.topology().dim()

    # Init/extract the mapping
    try:
        assert get_entity_map(mesh, trace_mesh)
    except AssertionError:
        warning('Using non-conforming trace')

        return nonconforming_trace_mat(V, TV)
        
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim+1)
    f2c = mesh.topology()(fdim, fdim+1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # Rows
    visited_dofs = [False]*TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(TV.mesh().num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here. Does not matter which
            # cell of the connected ones we pick
            cell = f2c(mapping[trace_cell])[0]
            V_basis_f.cell = cell
            
            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T
                
                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local
                    
                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES)
    return mat
예제 #14
0
def trace_mat_two_restrict(V, TV, restriction, normal, trace_mesh=None):
    '''
    Compute the trace values using avg/jump restriction. A + plus is the one 
    for which the vector cell.midpoint - facet.midpoint agrees in orientation
    with the normal on the facet.
    '''
    mesh = V.mesh()
    fdim = mesh.topology().dim() - 1
    
    if trace_mesh is None: trace_mesh = TV.mesh()

    # Init/extract entity map
    assert get_entity_map(mesh, trace_mesh)
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][fdim]  # Map cell of TV to cells of V

    mesh.init(fdim, fdim+1)
    f2c = mesh.topology()(fdim, fdim+1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    # We define avg as sum(+, -)/2 and jump as sum(+, neg(-))
    operator_pieces = {'avg': (lambda x: x/2, lambda x: x/2),
                       'jump': (lambda x: x, lambda x: -x)}[restriction]

    gdim = mesh.geometry().dim()
    # Rows
    visited_dofs = [False]*TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(trace_mesh.num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here
            facet_cells = f2c(mapping[trace_cell])

            assert 0 < len(facet_cells) < 3
            # Ignore boundary facets
            if len(facet_cells) == 1:
                facet_cells = [facet_cells[0]]
                modifiers = (lambda x: x, )  # Do nothing
            # Search which cell has the right sign
            else:
                signs = [None, None]
                # Order such that '+' is first
                t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim]
                mp = Cell(mesh, facet_cells[0]).midpoint().array()[:gdim]

                sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-'
                # Need to flip
                if sign == '-':
                    facet_cells = facet_cells[::-1]
                # As requested
                modifiers = operator_pieces

            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True
                    
                # Define trace dof
                TV_dof.dof = local_T
                
                # Two sweeps to set the values in the row
                ADD_VALUES = False
                for modify, cell in zip(modifiers, facet_cells):
                    V_basis_f.cell = cell
                    dofs = dmap.cell_dofs(cell)

                    # Eval at V basis functions
                    for local, dof in enumerate(dofs):
                        # Set which basis foo
                        V_basis_f.dof = local
                        dof_values[local] = modify(TV_dof.eval(V_basis_f))
                    # Can fill the matrix now
                    col_indices = np.array(dofs, dtype='int32')

                    if not ADD_VALUES:
                        mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES)
                        ADD_VALUES = True
                        #print 'setting', dof_T, col_indices, dof_values
                    else:
                        mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.ADD_VALUES)
                        #print 'adding', dof_T, col_indices, dof_values
    return mat
예제 #15
0
def trace_mat_one_restrict(V, TV, restriction, normal, trace_mesh=None):
    '''
    Compute the trace values using +/- restriction. A + plus is the one 
    for which the vector cell.midpoint - facet.midpoint agrees in orientation
    with the normal on the facet.
    '''
    mesh = V.mesh()
    fdim = mesh.topology().dim() - 1
    
    if trace_mesh is None: trace_mesh = TV.mesh()

    # Init/extract entity map
    assert get_entity_map(mesh, trace_mesh)
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][fdim]  # Map cell of TV to cells of V
        
    mesh.init(fdim, fdim+1)
    f2c = mesh.topology()(fdim, fdim+1)  # Facets of V to cell of V

    # The idea is to evaluate TV's degrees of freedom at basis functions
    # of V
    Tdmap = TV.dofmap()
    TV_dof = DegreeOfFreedom(TV)

    dmap = V.dofmap()
    V_basis_f = FEBasisFunction(V)

    gdim = mesh.geometry().dim()
    # Rows
    visited_dofs = [False]*TV.dim()
    # Column values
    dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double')
    with petsc_serial_matrix(TV, V) as mat:

        for trace_cell in range(trace_mesh.num_cells()):
            TV_dof.cell = trace_cell
            trace_dofs = Tdmap.cell_dofs(trace_cell)

            # Figure out the dofs of V to use here
            facet_cells = f2c(mapping[trace_cell])

            assert 0 < len(facet_cells) < 3
            # Ignore boundary facets
            if len(facet_cells) == 1:
                cell = facet_cells[0]
            # Search which cell has the right sign
            else:
                signs = []
                for fcell in facet_cells:
                    t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim]
                    mp = Cell(mesh, fcell).midpoint().array()[:gdim]

                    sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-'
                    signs.append(sign)
                cell = facet_cells[signs.index(restriction)]
            V_basis_f.cell = cell
            
            dofs = dmap.cell_dofs(cell)
            for local_T, dof_T in enumerate(trace_dofs):

                if visited_dofs[dof_T]:
                    continue
                else:
                    visited_dofs[dof_T] = True

                # Define trace dof
                TV_dof.dof = local_T
                
                # Eval at V basis functions
                for local, dof in enumerate(dofs):
                    # Set which basis foo
                    V_basis_f.dof = local
                    
                    dof_values[local] = TV_dof.eval(V_basis_f)

                # Can fill the matrix now
                col_indices = np.array(dofs, dtype='int32')
                # Insert
                mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES)
    return mat