Beispiel #1
0
    def timed_fun(*args, **kwargs):
        """Time an operation."""
        from bempp.api import log

        start_time = _time.time()
        res = fun(*args, **kwargs)
        end_time = _time.time()
        log(fun.__qualname__ + " : {0:.3e}s".format(end_time - start_time), "timing")
        return res
    def finalize(self):
        """Finalize the grid creation and return a grid object."""
        from bempp.api.grid.grid import Grid
        from bempp.api import log
        grid = Grid(self._impl.finalize())

        log("Created grid with %i elements, %i nodes and %i edges." % (
            grid.leaf_view.entity_count(0),
            grid.leaf_view.entity_count(2),
            grid.leaf_view.entity_count(1)))
        return grid
Beispiel #3
0
        def timed_fun(*args, **kwargs):
            """The actual timer function."""
            from bempp.api import GLOBAL_PARAMETERS
            from bempp.api import log

            if not GLOBAL_PARAMETERS.verbosity.extended_verbosity:
                return fun(*args, **kwargs)

            start_time = _time.time()
            res = fun(*args, **kwargs)
            end_time = _time.time()
            log(message + " : {0:.3e}s".format(end_time - start_time))
            return res
Beispiel #4
0
 def __call__(self, x):
     from bempp.api import log
     self._count += 1
     if self._store_residuals:
         if self._iteration_is_cg:
             res = self._rhs - self._operator * x
         else:
             res = x
         self._residuals.append(_np.linalg.norm(res))
         log(f"GMRES Iteration {self._count} with residual {self._residuals[-1]}"
             )
     else:
         log(f"GMRES Iteration {self._count}")
Beispiel #5
0
def p0_discontinuous_function_space(
    grid,
    support_elements=None,
    segments=None,
    swapped_normals=None,
    include_boundary_dofs=None,
    truncate_at_segment_edge=None,
):
    """Define a space of piecewise constant functions."""
    from .space import SpaceBuilder, _process_segments

    if include_boundary_dofs is not None:
        log("Setting include_boundary_dofs has no effect on this space type.",
            "warning")
    if truncate_at_segment_edge is not None:
        log(
            "Setting truncate_at_segment_edge has no effect on this space type.",
            "warning",
        )

    support, normal_multipliers = _process_segments(grid, support_elements,
                                                    segments, swapped_normals)

    elements_in_support = _np.flatnonzero(support)
    support_size = len(elements_in_support)

    local2global = _np.zeros((grid.number_of_elements, 1), dtype="uint32")
    local2global[support] = _np.expand_dims(
        _np.arange(support_size, dtype="uint32"), 1)

    local_multipliers = _np.zeros((grid.number_of_elements, 1),
                                  dtype="float64")
    local_multipliers[support] = 1

    collocation_points = _np.array([[1.0 / 3], [1.0 / 3]])

    return (SpaceBuilder(grid).set_codomain_dimension(1).set_support(
        support).set_normal_multipliers(normal_multipliers).set_order(
            0).set_is_localised(True).set_shapeset("p0_discontinuous").
            set_identifier("p0_discontinuous").set_local2global(local2global).
            set_local_multipliers(local_multipliers).set_collocation_points(
                collocation_points).set_barycentric_representation(
                    p0_barycentric_discontinuous_function_space).
            set_numba_surface_gradient(_numba_p0_surface_gradient).build())
Beispiel #6
0
def get_operator_with_space_preprocessing(op_fun,
                                          domain,
                                          range_,
                                          dual_to_range,
                                          label,
                                          symmetry,
                                          parameters,
                                          use_projection_spaces=True,
                                          assemble_only_singular_part=False):
    """Assemble operator after preprocessing of spaces."""
    import bempp.api
    from bempp.api.space import rewrite_operator_spaces
    from bempp.api.space import project_operator

    if parameters is None:
        parameters = bempp.api.global_parameters

    if parameters.assembly.boundary_operator_assembly_type == 'dense':
        from bempp.api import log
        use_projection_spaces = False
        log("Projection space mode disabled for dense assembly.")

    if check_for_non_barycentric_spaces(domain, dual_to_range):
        return rewrite_operator_spaces(
            get_operator_with_space_preprocessing(
                op_fun, domain.non_barycentric_space, range_,
                dual_to_range.non_barycentric_space, label, symmetry,
                parameters, use_projection_spaces,
                assemble_only_singular_part), domain, range_, dual_to_range)

    if not use_projection_spaces:
        return op_fun(domain, range_, dual_to_range, label, symmetry,
                      parameters, assemble_only_singular_part)
    else:

        operator = op_fun(domain.super_space, range_,
                          dual_to_range.super_space, label, symmetry,
                          parameters, assemble_only_singular_part)

        return project_operator(operator,
                                domain=domain,
                                range_=range_,
                                dual_to_range=dual_to_range)
Beispiel #7
0
def _grid_scatter_worker(grid_id, array_proxies):
    """Assign a new grid on the worker."""
    from bempp.api.utils import pool
    from bempp.api.grid.grid import Grid
    from bempp.api import log

    vertices, elements, domain_indices = pool.from_buffer(array_proxies)

    if not pool.has_key(grid_id):
        pool.insert_data(
            grid_id,
            Grid(vertices.copy(), elements.copy(), domain_indices.copy(),
                 grid_id),
        )
        log(f"Copied grid with id {grid_id} to worker {pool.get_id()}",
            "debug")
    else:
        log(f"Use cached grid with id {grid_id} on worker {pool.get_id()}",
            "debug")
Beispiel #8
0
def regular_sphere(n):
    """
    Return a regular sphere.

    Parameters
    ----------
    n : int
        Refinement level of the sphere.

    """
    from bempp.core.grid import grid_from_sphere
    from bempp.api.grid.grid import Grid
    from bempp.api import log

    grid = Grid(grid_from_sphere(n))
    log("Created grid with %i elements, %i nodes and %i edges." %
        (grid.leaf_view.entity_count(0), grid.leaf_view.entity_count(2),
         grid.leaf_view.entity_count(1)))

    return grid
Beispiel #9
0
def dual1_function_space(
    grid,
    support_elements=None,
    segments=None,
    swapped_normals=None,
    include_boundary_dofs=None,
    truncate_at_segment_edge=False,
):
    """Define a space of DP1 functions on the dual grid."""
    from .space import SpaceBuilder, invert_local2global
    from scipy.sparse import coo_matrix

    if include_boundary_dofs is not None:
        log("Setting include_boundary_dofs has no effect on this space type.",
            "warning")

    coarse_space = p0_discontinuous_function_space(grid, support_elements,
                                                   segments, swapped_normals)

    coarse_support = _np.zeros(grid.number_of_elements, dtype=_np.bool)
    coarse_support[coarse_space.support_elements] = True

    nentries = 0
    for global_dof_index in range(coarse_space.global_dof_count):
        local_dofs = coarse_space.global2local[global_dof_index]
        element_index = local_dofs[0][0]

        # 1 at barycentre of the triangle
        nentries += 6
        # 1/2 at the centre of each edge
        for e in range(3):
            edge = coarse_space.grid.element_edges[e][element_index]
            for neighbour in coarse_space.grid.edge_neighbors[edge]:
                if not truncate_at_segment_edge:
                    coarse_support[neighbour] = True
                if coarse_support[neighbour]:
                    nentries += 2
        # 1/num_coarse_triangles_at_vertex at each vertex
        for v in range(3):
            vertex = coarse_space.grid.elements[v][element_index]
            start = coarse_space.grid.vertex_neighbors.indexptr[vertex]
            end = coarse_space.grid.vertex_neighbors.indexptr[vertex + 1]
            neighbours = coarse_space.grid.vertex_neighbors.indices[start:end]
            for neighbour in neighbours:
                if not truncate_at_segment_edge:
                    coarse_support[neighbour] = True
                if coarse_support[neighbour]:
                    nentries += 2

    support_elements = [i for i, j in enumerate(coarse_support) if j]
    support_numbers = {j: i for i, j in enumerate(support_elements)}

    coarse_dofs = _np.zeros(nentries, dtype=_np.uint32)
    bary_dofs = _np.zeros(nentries, dtype=_np.uint32)
    values = _np.zeros(nentries, dtype=_np.float64)

    count = 0
    for global_dof_index in range(coarse_space.global_dof_count):
        local_dofs = coarse_space.global2local[global_dof_index]
        element_index = local_dofs[0][0]

        # 1 at barycentre of the triangle
        if coarse_support[element_index]:
            face_n = support_numbers[element_index]
            for n in [1, 5, 7, 11, 13, 17]:
                bary_dofs[count] = 6 * 3 * face_n + n
                coarse_dofs[count] = global_dof_index
                values[count] = 1
                count += 1
        # 1/2 at the centre of each edge
        for e in range(3):
            edge = coarse_space.grid.element_edges[e][element_index]
            for neighbour in coarse_space.grid.edge_neighbors[edge]:
                if coarse_support[neighbour]:
                    face_n = support_numbers[neighbour]
                    for i, dofs in enumerate([[1, 5], [13, 17], [7, 11]]):
                        if coarse_space.grid.element_edges[i][
                                neighbour] == edge:
                            for n in dofs:
                                bary_dofs[count] = 6 * 3 * face_n + n
                                coarse_dofs[count] = global_dof_index
                                values[count] = 0.5
                                count += 1
                            break
        # 1/num_coarse_triangles_at_vertex at each vertex
        for v in range(3):
            vertex = coarse_space.grid.elements[v][element_index]
            start = coarse_space.grid.vertex_neighbors.indexptr[vertex]
            end = coarse_space.grid.vertex_neighbors.indexptr[vertex + 1]
            neighbour_count = end - start
            neighbours = coarse_space.grid.vertex_neighbors.indices[start:end]
            for neighbour in neighbours:
                if coarse_support[neighbour]:
                    face_n = support_numbers[neighbour]
                    for i, dofs in enumerate([[0, 15], [3, 6], [9, 12]]):
                        if coarse_space.grid.elements[i][neighbour] == vertex:
                            for n in dofs:
                                bary_dofs[count] = 6 * 3 * face_n + n
                                coarse_dofs[count] = global_dof_index
                                values[count] = 1 / neighbour_count
                                count += 1
                            break

    bary_grid = grid.barycentric_refinement

    number_of_support_elements = len(support_elements)

    coarse_elements = _np.array(support_elements, dtype=_np.uint32)

    bary_support_elements = 6 * _np.repeat(coarse_elements, 6) + _np.tile(
        _np.arange(6), number_of_support_elements)

    bary_support_size = len(bary_support_elements)

    support = _np.zeros(bary_grid.number_of_elements, dtype=_np.bool)
    support[bary_support_elements] = True

    local2global = _np.zeros((bary_grid.number_of_elements, 3), dtype="uint32")
    local_multipliers = _np.zeros((bary_grid.number_of_elements, 3),
                                  dtype="uint32")

    local2global[support] = _np.arange(3 * bary_support_size).reshape(
        bary_support_size, 3)

    local_multipliers[support] = 1
    global2local = invert_local2global(local2global, local_multipliers)

    dof_transformation = coo_matrix(
        (values, (bary_dofs, coarse_dofs)),
        shape=(3 * bary_support_size, coarse_space.global_dof_count),
        dtype=_np.float64,
    ).tocsr()

    return (SpaceBuilder(bary_grid).set_codomain_dimension(1).set_support(
        support).set_order(1).set_is_localised(True).set_is_barycentric(
            True).set_shapeset("p1_discontinuous").set_identifier(
                "p1_discontinuous").set_local2global(local2global).
            set_global2local(global2local).set_local_multipliers(
                local_multipliers).set_dof_transformation(dof_transformation).
            set_numba_surface_gradient(_numba_p1_surface_gradient).build())
Beispiel #10
0
    def __init__(self,
                 vertices,
                 elements,
                 domain_indices=None,
                 grid_id=None,
                 scatter=True):
        """Create a grid from a vertices and an elements array."""
        from bempp.api import log
        from bempp.api.utils import pool
        from bempp.api.utils.helpers import create_unique_id

        self._vertices = None
        self._elements = None
        self._domain_indices = None
        self._edges = None
        self._element_edges = None
        self._edge_adjacency = None
        self._vertex_adjacency = None
        self._element_neighbors = None
        self._vertex_on_boundary = None
        self._edge_on_boundary = None
        self._edge_neighbors = None
        self._vertex_neighbors = None
        self._barycentric_grid = None
        if grid_id:
            self._id = grid_id
        else:
            self._id = create_unique_id()

        self._volumes = None
        self._normals = None
        self._jacobians = None
        self._jacobian_inverse_transposed = None
        self._diameters = None
        self._integration_elements = None
        self._centroids = None

        self._device_interfaces = {}

        self._element_to_vertex_matrix = None
        self._element_to_element_matrix = None

        self._normalize_and_assign_input(vertices, elements, domain_indices)
        self._enumerate_edges()

        self._get_element_adjacency_for_edges_and_vertices()
        self._compute_geometric_quantities()

        self._compute_boundary_information()

        self._compute_edge_neighbors()
        self._compute_vertex_neighbors()

        self._grid_data = GridData(self._vertices, self._elements, self._edges,
                                   self._element_edges, self._volumes,
                                   self._normals, self._jacobians,
                                   self._jacobian_inverse_transposed,
                                   self._diameters, self._integration_elements,
                                   self._centroids, self._domain_indices,
                                   self._vertex_on_boundary)
        self._is_scattered = False

        if scatter and pool.is_initialised() and not pool.is_worker():
            self._scatter()
        if not pool.is_worker():
            log((
                f"Created grid with id {self.id}. Elements: {self.number_of_elements}. "
                +
                f"Edges: {self.number_of_edges}. Vertices: {self.number_of_vertices}"
            ))