Example #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)
Example #2
0
def block_mat_to_petsc(bmat):
    '''Block mat to PETScMatrix via assembly'''
    # This is beautiful but slow as hell :)
    def iter_rows(matrix):
        for i in range(matrix.size(0)):
            yield matrix.getrow(i)

    row_sizes, col_sizes = get_sizes(bmat)
    row_offsets = np.cumsum([0] + list(row_sizes))
    col_offsets = np.cumsum([0] + list(col_sizes))

    with petsc_serial_matrix(row_offsets[-1], col_offsets[-1]) as mat:
        row = 0
        for row_blocks in bmat.blocks:
            # Zip the row iterators of the matrices together
            for indices_values in itertools.izip(*map(iter_rows, row_blocks)):
                indices, values = zip(*indices_values)

                indices = [list(index+offset) for index, offset in zip(indices, col_offsets)]
                indices = sum(indices, [])
            
                row_values = np.hstack(values)

                mat.setValues([row], indices, row_values, PETSc.InsertMode.INSERT_VALUES)

                row += 1
    return PETScMatrix(mat)
Example #3
0
def block_mat_to_petsc(bmat):
    '''Block mat to PETScMatrix via assembly'''

    # This is beautiful but slow as hell :)
    def iter_rows(matrix):
        for i in range(matrix.size(0)):
            yield matrix.getrow(i)

    row_sizes, col_sizes = get_sizes(bmat)
    row_offsets = np.cumsum([0] + list(row_sizes))
    col_offsets = np.cumsum([0] + list(col_sizes))

    with petsc_serial_matrix(row_offsets[-1], col_offsets[-1]) as mat:
        row = 0
        for row_blocks in bmat.blocks:
            # Zip the row iterators of the matrices together
            for indices_values in itertools.izip(*map(iter_rows, row_blocks)):
                indices, values = zip(*indices_values)

                indices = [
                    list(index + offset)
                    for index, offset in zip(indices, col_offsets)
                ]
                indices = sum(indices, [])

                row_values = np.hstack(values)

                mat.setValues([row], indices, row_values,
                              PETSc.InsertMode.INSERT_VALUES)

                row += 1
    return PETScMatrix(mat)
Example #4
0
def DLT_trace_mat(V, TV, trace_mesh=None, tag_data=None):
    '''Inject dofs from facets to DLT'''
    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
    # We can get it
    mapping = trace_mesh.parent_entity_map[mesh.id()][
        fdim]  # Map cell of TV to cells of V

    if TV.num_sub_spaces() == 0:
        Tdmaps = [TV.dofmap()]
    else:
        Tdmaps = [TV.sub(i).dofmap() for i in range(TV.num_sub_spaces())]

    if V.num_sub_spaces() == 0:
        dmap = V.dofmap()
        facet2dofs = [dmap.entity_dofs(mesh, fdim)]
    else:
        facet2dofs = [
            V.sub(i).dofmap().entity_dofs(mesh, fdim)
            for i in range(V.num_sub_spaces())
        ]

    assert len(Tdmaps) == len(facet2dofs)

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

    # Rows
    with petsc_serial_matrix(TV, V) as mat:

        for Tdmap, facet2dof in zip(Tdmaps, facet2dofs):
            for trace_cell in trace_cells:
                trace_dof, = Tdmap.cell_dofs(trace_cell)
                DLT_dof = facet2dof[mapping[trace_cell]]
                mat.setValues([trace_dof], [DLT_dof], [1.],
                              PETSc.InsertMode.INSERT_VALUES)
    return mat
Example #5
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
Example #6
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
Example #7
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
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
Example #9
0
def point_trace_matrix(V, TV, x0):
    '''
    Let u in V; u = ck phi_k then u(x0) \in TV = ck phi_k(x0). So this 
    is a 1 by dim(V) matrix where the column values are phi_k(x0).
    '''
    mesh = V.mesh()
    tree = mesh.bounding_box_tree()
    cell = tree.compute_first_entity_collision(Point(*x0))
    assert cell < mesh.num_cells()

    # Cell for restriction
    Vcell = Cell(mesh, cell)
    vertex_coordinates = Vcell.get_vertex_coordinates()
    cell_orientation = Vcell.orientation()
    x0 = np.fromiter(x0, dtype=float)

    # Columns - get all components at once
    all_dofs = V.dofmap().cell_dofs(cell).tolist()
    Vel = V.element()
    value_size = V.ufl_element().value_size()
    basis_values = np.zeros(V.element().space_dimension() * value_size)

    Vel.evaluate_basis_all(basis_values, x0, vertex_coordinates,
                           cell_orientation)

    with petsc_serial_matrix(TV, V) as mat:

        # Scalar gets all
        if value_size == 1:
            component_dofs = lambda component: V.dofmap().cell_dofs(cell)
        # Slices
        else:
            component_dofs = lambda component: V.sub(component).dofmap(
            ).cell_dofs(cell)

        for row in map(int, TV.dofmap().cell_dofs(cell)):  # R^n components
            sub_dofs = component_dofs(row)
            sub_dofs_local = [all_dofs.index(dof) for dof in sub_dofs]
            print row, sub_dofs, sub_dofs_local, basis_values[sub_dofs_local]

            mat.setValues([row], sub_dofs, basis_values[sub_dofs_local],
                          PETSc.InsertMode.INSERT_VALUES)
    return mat
Example #10
0
def point_trace_matrix(V, TV, x0):
    '''
    Let u in V; u = ck phi_k then u(x0) \in TV = ck phi_k(x0). So this 
    is a 1 by dim(V) matrix where the column values are phi_k(x0).
    '''
    mesh = V.mesh()
    tree = mesh.bounding_box_tree()
    cell = tree.compute_first_entity_collision(Point(*x0))
    assert cell < mesh.num_cells()

    # Cell for restriction
    Vcell = Cell(mesh, cell)
    vertex_coordinates = Vcell.get_vertex_coordinates()
    cell_orientation = Vcell.orientation()
    x0 = np.fromiter(x0, dtype=float)

    # Columns - get all components at once
    all_dofs = V.dofmap().cell_dofs(cell).tolist()
    Vel = V.element()
    value_size = V.ufl_element().value_size()
    basis_values = np.zeros(V.element().space_dimension()*value_size)

    Vel.evaluate_basis_all(basis_values, x0, vertex_coordinates, cell_orientation)

    with petsc_serial_matrix(TV, V) as mat:

        # Scalar gets all
        if value_size == 1:
            component_dofs = lambda component: V.dofmap().cell_dofs(cell)
        # Slices
        else:
            component_dofs = lambda component: V.sub(component).dofmap().cell_dofs(cell)
        
        for row in map(int, TV.dofmap().cell_dofs(cell)):  # R^n components
            sub_dofs = component_dofs(row)
            sub_dofs_local = [all_dofs.index(dof) for dof in sub_dofs]
            print row, sub_dofs, sub_dofs_local, basis_values[sub_dofs_local]
            
            mat.setValues([row], sub_dofs, basis_values[sub_dofs_local],
                          PETSc.InsertMode.INSERT_VALUES)
    return mat
Example #11
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
Example #12
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
Example #13
0
def cylinder_average_matrix(V, TV, radius, quad_degree):
    '''Averaging matrix'''
    mesh = V.mesh()
    line_mesh = TV.mesh()
    # We are going to perform the integration with Gauss quadrature at
    # the end (PI u)(x):
    # A cell of mesh (an edge) defines a normal vector. Let P be the plane
    # that is defined by the normal vector n and some point x on Gamma. Let L
    # be the circle that is the intersect of P and S. The value of q (in Q) at x
    # is defined as
    #
    #                    q(x) = (1/|L|)*\int_{L}g(x)*dL
    #
    # which simplifies to g(x) = (1/(2*pi*R))*\int_{-pi}^{pi}u(L)*R*d(theta) and
    # or                       = (1/2) * \int_{-1}^{1} u (L(pi*s)) * ds
    # This can be integrated no problemo once we figure out L. To this end, let
    # t_1 and t_2 be two unit mutually orthogonal vectors that are orthogonal to
    # n. Then L(pi*s) = p + R*t_1*cos(pi*s) + R*t_2*sin(pi*s) can be seen to be
    # such that i) |x-p| = R and ii) x.n = 0 [i.e. this the suitable
    # parametrization]
    
    # Clearly we can scale the weights as well as precompute
    # cos and sin terms.
    xq, wq = leggauss(quad_degree)
    wq *= 0.5
    cos_xq = np.cos(np.pi*xq).reshape((-1, 1))
    sin_xq = np.sin(np.pi*xq).reshape((-1, 1))

    if is_number(radius):
         radius = lambda x, radius=radius: radius 

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()               
    basis_values = np.zeros(V.element().space_dimension()*value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent => orthogonal tangent vectors

            v0, v1 = mesh_x[line_cell.entities(0)]
            n = v0 - v1

            t1 = np.array([n[1]-n[2], n[2]-n[0], n[0]-n[1]])
    
            t2 = np.cross(n, t1)
            t1 /= np.linalg.norm(t1)
            t2 = t2/np.linalg.norm(t2)

            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Get radius and integration points
                rad = radius(avg_point)
         
                integration_points = avg_point + rad*t1*sin_xq + rad*t2*cos_xq

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    Vcell = Cell(mesh, c)
                    vertex_coordinates = Vcell.get_vertex_coordinates()
                    cell_orientation = Vcell.orientation()
                    Vel.evaluate_basis_all(basis_values, ip, vertex_coordinates, cell_orientation)

                    cols_ip = V_dm.cell_dofs(c)
                    values_ip = basis_values*wq[index]
                    # Add
                    for col, value in zip(cols_ip, values_ip.reshape((-1, value_size))):
                        if col in data:
                            data[col] += value
                        else:
                            data[col] = value
                            
                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(data.keys(), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array([data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values, PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #14
0
def sphere_average_matrix(V, TV, radius, quad_degree):
    '''Averaging matrix over the sphere'''
    mesh = V.mesh()
    line_mesh = TV.mesh()
    # Lebedev below need off degrees
    if quad_degree % 2 == 0: quad_degree += 1
    # NOTE: this is a dependency
    from quadpy.sphere import Lebedev

    integrator = Lebedev(quad_degree)
    xq = integrator.points
    wq = integrator.weights
    
    if is_number(radius):
         radius = lambda x, radius=radius: radius 

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()               
    basis_values = np.zeros(V.element().space_dimension()*value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Get radius and integration points
                rad = radius(avg_point)
                # Scale and shift the unit sphere to the point
                integration_points = xq*rad + avg_point

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    Vcell = Cell(mesh, c)
                    vertex_coordinates = Vcell.get_vertex_coordinates()
                    cell_orientation = Vcell.orientation()
                    Vel.evaluate_basis_all(basis_values, ip, vertex_coordinates, cell_orientation)

                    cols_ip = V_dm.cell_dofs(c)
                    values_ip = basis_values*wq[index]
                    # Add
                    for col, value in zip(cols_ip, values_ip.reshape((-1, value_size))):
                        if col in data:
                            data[col] += value
                        else:
                            data[col] = value
                            
                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(data.keys(), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array([data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values, PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #15
0
def trace_3d1d_matrix(V, TV, reduced_mesh):
    '''Trace from 3d to 1d. Makes sense only for CG space'''
    assert reduced_mesh.id() == TV.mesh().id()
    assert V.ufl_element().family() == 'Lagrange'
    
    mesh = V.mesh()
    line_mesh = TV.mesh()
    
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # We use the map to get (1d cell -> [3d edge) -> 3d cell]
    if hasattr(reduced_mesh, 'parent_entity_map'):
        # ( )
        mapping = reduced_mesh.parent_entity_map[mesh.id()][1]
        # [ ]
        mesh.init(1)
        mesh.init(1, 3)
        e2c = mesh.topology()(1, 3)
        # From 1d cell (by index)
        get_cell3d = lambda c, d1d3=mapping, d3d3=e2c: d3d3(d1d3[c.index()])[0]
    # Tree collision by midpoint
    else:
        tree = mesh.bounding_box_tree()
        limit = mesh.num_cells()

        get_cell3d = lambda c, tree=tree, bound=limit: (
            lambda index: index if index<bound else None
        )(tree.compute_first_entity_collision(c.midpoint()))
  
    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()               
    basis_values = np.zeros(V.element().space_dimension()*value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent => orthogonal tangent vectors
            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]

            # Let's get a 3d cell to use for getting the V values
            # CG assumption allows taking any
            tet_cell = get_cell3d(line_cell)
            if tet_cell is None: continue
            
            Vcell = Cell(mesh, tet_cell)
            vertex_coordinates = Vcell.get_vertex_coordinates()
            cell_orientation = 0
            # Columns are determined by V cell! I guess the sparsity
            # could be improved if for x_dofs of TV only x_dofs of V
            # were considered
            column_indices = np.array(V_dm.cell_dofs(tet_cell), dtype='int32')

            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # 3d at point
                Vel.evaluate_basis_all(basis_values, avg_point, vertex_coordinates, cell_orientation)
                # The thing now is that with data we can assign to several
                # rows of the matrix. Shift determines the (x, y, ... ) or
                # (xx, xy, yx, ...) component of Q
                data = basis_values.reshape((-1, value_size)).T
                for shift, column_values in enumerate(data):
                    row = scalar_row + shift
                    mat.setValues([row], column_indices, column_values, PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #16
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
Example #17
0
def cylinder_average_matrix(V, TV, radius, quad_degree):
    '''Averaging matrix'''
    mesh = V.mesh()
    line_mesh = TV.mesh()
    # We are going to perform the integration with Gauss quadrature at
    # the end (PI u)(x):
    # A cell of mesh (an edge) defines a normal vector. Let P be the plane
    # that is defined by the normal vector n and some point x on Gamma. Let L
    # be the circle that is the intersect of P and S. The value of q (in Q) at x
    # is defined as
    #
    #                    q(x) = (1/|L|)*\int_{L}g(x)*dL
    #
    # which simplifies to g(x) = (1/(2*pi*R))*\int_{-pi}^{pi}u(L)*R*d(theta) and
    # or                       = (1/2) * \int_{-1}^{1} u (L(pi*s)) * ds
    # This can be integrated no problemo once we figure out L. To this end, let
    # t_1 and t_2 be two unit mutually orthogonal vectors that are orthogonal to
    # n. Then L(pi*s) = p + R*t_1*cos(pi*s) + R*t_2*sin(pi*s) can be seen to be
    # such that i) |x-p| = R and ii) x.n = 0 [i.e. this the suitable
    # parametrization]

    # Clearly we can scale the weights as well as precompute
    # cos and sin terms.
    xq, wq = leggauss(quad_degree)
    wq *= 0.5
    cos_xq = np.cos(np.pi * xq).reshape((-1, 1))
    sin_xq = np.sin(np.pi * xq).reshape((-1, 1))

    if is_number(radius):
        radius = lambda x, radius=radius: radius

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()
    basis_values = np.zeros(V.element().space_dimension() * value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent => orthogonal tangent vectors

            v0, v1 = mesh_x[line_cell.entities(0)]
            n = v0 - v1

            t1 = np.array([n[1] - n[2], n[2] - n[0], n[0] - n[1]])

            t2 = np.cross(n, t1)
            t1 /= np.linalg.norm(t1)
            t2 = t2 / np.linalg.norm(t2)

            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Get radius and integration points
                rad = radius(avg_point)

                integration_points = avg_point + rad * t1 * sin_xq + rad * t2 * cos_xq

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    Vcell = Cell(mesh, c)
                    vertex_coordinates = Vcell.get_vertex_coordinates()
                    cell_orientation = Vcell.orientation()
                    Vel.evaluate_basis_all(basis_values, ip,
                                           vertex_coordinates,
                                           cell_orientation)

                    cols_ip = V_dm.cell_dofs(c)
                    values_ip = basis_values * wq[index]
                    # Add
                    for col, value in zip(cols_ip,
                                          values_ip.reshape((-1, value_size))):
                        if col in data:
                            data[col] += value
                        else:
                            data[col] = value

                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(data.keys(), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array(
                        [data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values,
                                  PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #18
0
def sphere_average_matrix(V, TV, radius, quad_degree):
    '''Averaging matrix over the sphere'''
    mesh = V.mesh()
    line_mesh = TV.mesh()
    # Lebedev below need off degrees
    if quad_degree % 2 == 0: quad_degree += 1
    # NOTE: this is a dependency
    from quadpy.sphere import Lebedev

    integrator = Lebedev(quad_degree)
    xq = integrator.points
    wq = integrator.weights

    if is_number(radius):
        radius = lambda x, radius=radius: radius

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()
    basis_values = np.zeros(V.element().space_dimension() * value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Get radius and integration points
                rad = radius(avg_point)
                # Scale and shift the unit sphere to the point
                integration_points = xq * rad + avg_point

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    Vcell = Cell(mesh, c)
                    vertex_coordinates = Vcell.get_vertex_coordinates()
                    cell_orientation = Vcell.orientation()
                    Vel.evaluate_basis_all(basis_values, ip,
                                           vertex_coordinates,
                                           cell_orientation)

                    cols_ip = V_dm.cell_dofs(c)
                    values_ip = basis_values * wq[index]
                    # Add
                    for col, value in zip(cols_ip,
                                          values_ip.reshape((-1, value_size))):
                        if col in data:
                            data[col] += value
                        else:
                            data[col] = value

                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(data.keys(), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array(
                        [data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values,
                                  PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #19
0
def trace_3d1d_matrix(V, TV, reduced_mesh):
    '''Trace from 3d to 1d. Makes sense only for CG space'''
    assert reduced_mesh.id() == TV.mesh().id()
    assert V.ufl_element().family() == 'Lagrange'

    mesh = V.mesh()
    line_mesh = TV.mesh()

    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # We use the map to get (1d cell -> [3d edge) -> 3d cell]
    if hasattr(reduced_mesh, 'parent_entity_map'):
        # ( )
        mapping = reduced_mesh.parent_entity_map[mesh.id()][1]
        # [ ]
        mesh.init(1)
        mesh.init(1, 3)
        e2c = mesh.topology()(1, 3)
        # From 1d cell (by index)
        get_cell3d = lambda c, d1d3=mapping, d3d3=e2c: d3d3(d1d3[c.index()])[0]
    # Tree collision by midpoint
    else:
        tree = mesh.bounding_box_tree()
        limit = mesh.num_cells()

        get_cell3d = lambda c, tree=tree, bound=limit: (
            lambda index: index if index < bound else None)(
                tree.compute_first_entity_collision(c.midpoint()))

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()
    basis_values = np.zeros(V.element().space_dimension() * value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent => orthogonal tangent vectors
            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]

            # Let's get a 3d cell to use for getting the V values
            # CG assumption allows taking any
            tet_cell = get_cell3d(line_cell)
            if tet_cell is None: continue

            Vcell = Cell(mesh, tet_cell)
            vertex_coordinates = Vcell.get_vertex_coordinates()
            cell_orientation = 0
            # Columns are determined by V cell! I guess the sparsity
            # could be improved if for x_dofs of TV only x_dofs of V
            # were considered
            column_indices = np.array(V_dm.cell_dofs(tet_cell), dtype='int32')

            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # 3d at point
                Vel.evaluate_basis_all(basis_values, avg_point,
                                       vertex_coordinates, cell_orientation)
                # The thing now is that with data we can assign to several
                # rows of the matrix. Shift determines the (x, y, ... ) or
                # (xx, xy, yx, ...) component of Q
                data = basis_values.reshape((-1, value_size)).T
                for shift, column_values in enumerate(data):
                    row = scalar_row + shift
                    mat.setValues([row], column_indices, column_values,
                                  PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)
Example #20
0
def average_matrix(V, TV, shape):
    '''
    Averaging matrix for reduction of g in V to TV by integration over shape.
    '''
    # We build a matrix representation of u in V -> Pi(u) in TV where
    #
    # Pi(u)(s) = |L(s)|^-1*\int_{L(s)}u(t) dx(s)
    #
    # Here L is the shape over which u is integrated for reduction.
    # Its measure is |L(s)|.

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    mesh = V.mesh()
    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    line_mesh = TV.mesh()

    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()
    basis_values = np.zeros(V.element().space_dimension() * value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent (normal of the plane which cuts the virtual
            # surface to yield the bdry curve
            v0, v1 = mesh_x[line_cell.entities(0)]
            n = v0 - v1

            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Avg point here has the role of 'height' coordinate
                quadrature = shape.quadrature(avg_point, n)
                integration_points = quadrature.points
                wq = quadrature.weights

                curve_measure = sum(wq)

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    cs = tree.compute_entity_collisions(Point(*ip))
                    # assert False
                    for c in cs[:1]:
                        Vcell = Cell(mesh, c)
                        vertex_coordinates = Vcell.get_vertex_coordinates()
                        cell_orientation = Vcell.orientation()
                        basis_values[:] = Vel.evaluate_basis_all(
                            ip, vertex_coordinates, cell_orientation)

                        cols_ip = V_dm.cell_dofs(c)
                        values_ip = basis_values * wq[index]
                        # Add
                        for col, value in zip(
                                cols_ip, values_ip.reshape((-1, value_size))):
                            if col in data:
                                data[col] += value / curve_measure
                            else:
                                data[col] = value / curve_measure

                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(list(data.keys()), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array(
                        [data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values,
                                  PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return mat
Example #21
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
Example #22
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
Example #23
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
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
Example #25
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
Example #26
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
Example #27
0
def surface_average_matrix(V, TV, bdry_curve):
    '''Averaging matrix'''
    mesh = V.mesh()
    line_mesh = TV.mesh()
    # We build a matrix representation of u in V -> Pi(u) in TV where
    #
    # Pi(u)(s) = |L(s)|^-1*\int_{L(s)}u(t) dL(s)
    #
    # Here L represents a curve bounding the surface at 'height' s.
    #
    # We do this numerically as |L(s)|^-1*\sum_q u(x_q)*w_q

    # Weights remaing fixed
    wq = bdry_curve.weights

    mesh_x = TV.mesh().coordinates()
    # The idea for point evaluation/computing dofs of TV is to minimize
    # the number of evaluation. I mean a vector dof if done naively would
    # have to evaluate at same x number of component times.
    value_size = TV.ufl_element().value_size()

    # Eval at points will require serch
    tree = mesh.bounding_box_tree()
    limit = mesh.num_cells()

    TV_coordinates = TV.tabulate_dof_coordinates().reshape((TV.dim(), -1))
    TV_dm = TV.dofmap()
    V_dm = V.dofmap()
    # For non scalar we plan to make compoenents by shift
    if value_size > 1:
        TV_dm = TV.sub(0).dofmap()

    Vel = V.element()
    basis_values = np.zeros(V.element().space_dimension() * value_size)
    with petsc_serial_matrix(TV, V) as mat:

        for line_cell in cells(line_mesh):
            # Get the tangent (normal of the plane which cuts the virtual
            # surface to yield the bdry curve
            v0, v1 = mesh_x[line_cell.entities(0)]
            n = v0 - v1
            # We can specialize quadrature points; we can have several
            # height points with same normal
            pts_at_n = bdry_curve.points(n)
            len_at_n = bdry_curve.length(n)

            # The idea is now to minimize the point evaluation
            scalar_dofs = TV_dm.cell_dofs(line_cell.index())
            scalar_dofs_x = TV_coordinates[scalar_dofs]
            for scalar_row, avg_point in zip(scalar_dofs, scalar_dofs_x):
                # Avg point here has the role of 'height' coordinate
                integration_points = pts_at_n(avg_point)
                len_bdry_curve = len_at_n(avg_point)

                data = {}
                for index, ip in enumerate(integration_points):
                    c = tree.compute_first_entity_collision(Point(*ip))
                    if c >= limit: continue

                    Vcell = Cell(mesh, c)
                    vertex_coordinates = Vcell.get_vertex_coordinates()
                    cell_orientation = Vcell.orientation()
                    Vel.evaluate_basis_all(basis_values, ip,
                                           vertex_coordinates,
                                           cell_orientation)

                    cols_ip = V_dm.cell_dofs(c)
                    values_ip = basis_values * wq[index]
                    # Add
                    for col, value in zip(cols_ip,
                                          values_ip.reshape((-1, value_size))):
                        if col in data:
                            data[col] += value / len_bdry_curve
                        else:
                            data[col] = value / len_bdry_curve

                # The thing now that with data we can assign to several
                # rows of the matrix
                column_indices = np.array(data.keys(), dtype='int32')
                for shift in range(value_size):
                    row = scalar_row + shift
                    column_values = np.array(
                        [data[col][shift] for col in column_indices])
                    mat.setValues([row], column_indices, column_values,
                                  PETSc.InsertMode.INSERT_VALUES)
            # On to next avg point
        # On to next cell
    return PETScMatrix(mat)