Example #1
0
def balance_subroutine(tree, depth):
    """
    Perform balancing to enforce the 2:1 constraint between neighbouring
        nodes in linear octree.

        Strategy: Traverse the octree level by level, bottom-up, and check if
        a given node's parent lies in the tree, add it and their respective
        siblings. This enforces the 2:1 constraint.
    """
    balanced = set(tree)

    for level in range(depth, 0, -1):
        work_items = [x for x in balanced if morton.find_level(x) == level]

        for work_item in work_items:
            neighbours = morton.find_neighbours(work_item)

            for neighbour in neighbours:
                parent = morton.find_parent(neighbour)
                parent_level = level - 1

                if ~(neighbour in balanced) and ~(parent in balanced):

                    balanced.add(parent)

                    if parent_level > 0:
                        siblings = morton.find_siblings(parent)
                        balanced.update(siblings)

    return numba.typed.List(balanced)
Example #2
0
def find_dense_v_list(key, depth):
    """
    Find the V list of a key if it were in a non-adaptive tree.
    """

    parent = morton.find_parent(key)
    parent_neighbours = morton.find_neighbours(parent)
    parent_neigbhours_children = morton.find_children_vec(
        parent_neighbours).ravel()
    are_adj = morton.are_adjacent_vec(key, parent_neigbhours_children, depth)

    return parent_neigbhours_children[are_adj == 0]
Example #3
0
def test_find_interaction_lists(balanced):
    """
    Currently only tests interaction lists for nodes at leaf level, mainly
        checking that the constraints on their level, and adjacency are
        satisfied.
    """
    depth = tree.find_depth(balanced)
    complete = tree.complete_tree(balanced)
    u, x, v, w = tree.find_interaction_lists(balanced, complete, depth)

    for i in range(len(complete)):
        key = complete[i]

        if key in balanced:

            # Check all u list members are adjacent
            u_i = u[i][u[i] != -1]
            u_adj_idxs = morton.are_adjacent_vec(key, u_i, depth)
            assert np.all(u_adj_idxs == 1)

            # Check all x list members are at the right level, and not adjacent
            x_i = x[i][x[i] != -1]
            x_nadj_idxs = morton.are_adjacent_vec(key, x_i, depth)
            assert np.all(x_nadj_idxs == 0)

            x_levels = morton.find_level(x_i)
            assert np.all(
                x_levels == morton.find_level(morton.find_parent(key)))

            # Check all w list members are at right level, and not adjacent
            w_i = w[i][w[i] != -1]
            w_nadj_idxs = morton.are_adjacent_vec(key, w_i, depth)
            assert np.all(w_nadj_idxs == 0)

            w_levels = morton.find_level(w_i)
            assert np.all(w_levels == (morton.find_level(key) - 1))

            # Check all v list members are at right level, and not adjacent
            v_i = v[i][v[i] != -1]
            v_nadj_idxs = morton.are_adjacent_vec(key, v_i, depth)
            assert np.all(v_nadj_idxs == 0)

            v_levels = morton.find_level(v_i)
            assert np.all(v_levels == morton.find_level(key))
Example #4
0
    def find_interaction_list(i, leaves, leaves_set, complete_set, depth, u, x,
                              v, w):
        """
        Internal method to find interaction list for a given key.

        Parameters:
        -----------
        i : np.int64
            Index of key in the complete tree.
        leaves : np.array(dtype=np.int64)
            Linear octree, represented by its leaves.
        leaves_set : set(np.int64)
            Set containing the linear octree.
        complete_set : set(np.int64)
            Set containing the completed octree.
        depth : np.int64
            Depth of the octree.
        u : np.array(shape=(n_complete, 90))
            U list container, nearest neighbours.
        x : np.array(shape=(n_complete, 20))
            X list container, colleagues of a node's parent which are
            non-adjacent to the node - conjugate to the W list.
        v : np.array(shape=(n_complete, 189))
            V list container, children of a node's parent's colleagues which
            are not adjacent to the node.
        w : np.array(shape=(n_complete, 208))
            W list container, children of colleagues, which are not adjacent to
            the node.
        """
        def build_parent_level_leaf(key, leaves_set, colleagues_parents,
                                    parent_colleagues, depth):
            """
            Build the portion of the interaction list that is expected at the
                parent level of a node. Contributes to the U and X lists for
                leaf keys.

            Parameters:
            ----------
            key : np.int64
                Key for the current node being considered.
            leaves_set : set(np.int64)
            colleagues_parents : np.array(np.int64)
                The (unique) parents of the node's colleagues.
            parent_colleagues : np.array(np.int64)
                The colleagues of the node's parents.
            depth : np.int64

            Returns:
            --------
            (np.int64, np.array(dtype=np.int64))
                Four-tuple (u_ptr, u, x_ptr, x), where 'u_ptr' is the length
                of the U list contributions at this level.

            """
            # U List (P2P)
            cp_in_tree = np.zeros_like(colleagues_parents)
            i = 0
            for cp in colleagues_parents:
                if cp in leaves_set:
                    cp_in_tree[i] = cp
                    i += 1

            cp_in_tree = cp_in_tree[:i]

            adj_idxs = morton.are_adjacent_vec(key, cp_in_tree, depth)
            adjacent = cp_in_tree[adj_idxs == 1]

            # X List (P2L)
            pc_in_tree = np.zeros_like(parent_colleagues)
            i = 0
            for pc in parent_colleagues:
                if pc in leaves_set:
                    pc_in_tree[i] = pc
                    i += 1

            pc_in_tree = pc_in_tree[:i]

            not_adj_idxs = morton.are_adjacent_vec(key, pc_in_tree, depth)
            not_adjacent = pc_in_tree[not_adj_idxs == 0]

            return len(adjacent), adjacent, len(not_adjacent), not_adjacent

        def build_current_level_leaf(key, leaves_set, complete_set, colleagues,
                                     parent_colleagues_children, depth):
            """
            Build the portion of the interaction list that is expected at the
                level of a node. Contributes to the U and V lists for leaf keys.

            Parameters:
            -----------
            key : np.int64
                Key for the current node being considered.
            leaves_set : set(np.int64)
            colleagues : np.array(np.int64)
                The node's colleagues.
            parent_colleagues_children : np.array(np.int64)
                The children of a node's parent's colleagues.
            depth : np.int64

            Returns:
            --------
            (np.int64, np.array(dtype=np.int64))
                Four-tuple (u_ptr, u, v_ptr, v), where 'u_ptr' is the length
                of the U list contributions at this level.
            """
            # U List (P2P)
            c_in_tree = np.zeros_like(colleagues)
            i = 0
            for c in colleagues:
                if c in leaves_set:
                    c_in_tree[i] = c
                    i += 1

            c_in_tree = c_in_tree[:i]
            adj_idxs = morton.are_adjacent_vec(key, c_in_tree, depth)
            adjacent = c_in_tree[adj_idxs == 1]

            # V List (M2L)
            pcc_in_tree = np.zeros_like(parent_colleagues_children)
            i = 0
            for pcc in parent_colleagues_children:
                if pcc in complete_set:
                    pcc_in_tree[i] = pcc
                    i += 1

            pcc_in_tree = pcc_in_tree[:i]
            adj_idxs = morton.are_adjacent_vec(key, pcc_in_tree, depth)
            not_adjacent = pcc_in_tree[adj_idxs == 0]

            return len(adjacent), adjacent, len(not_adjacent), not_adjacent

        def build_current_level_non_leaf(key, complete_set,
                                         parent_colleagues_children, depth):
            """
            Build the portion of the interaction list that is expected at the
                level of a node. Contributes to the V lists for non-leaf keys.

            Parameters:
            -----------
            key : np.int64
                Key for the current node being considered.
            complete_set : set(np.int64)
            parent_colleagues_children : np.array(np.int64)
                The children of a node's parent's colleagues.
            depth : np.int64

            Returns:
            --------
            (np.int64, np.array(dtype=np.int64))
                Tuple (v_ptr, v), where 'v_ptr' is the length of the V list
                contributions at this level.
            """
            # V List (M2L)
            pcc_in_tree = np.zeros_like(parent_colleagues_children)
            i = 0
            for pcc in parent_colleagues_children:
                if pcc in complete_set:
                    pcc_in_tree[i] = pcc
                    i += 1

            pcc_in_tree = pcc_in_tree[:i]
            adj_idxs = morton.are_adjacent_vec(key, pcc_in_tree, depth)
            not_adjacent = pcc_in_tree[adj_idxs == 0]

            return len(not_adjacent), not_adjacent

        def build_child_level_leaf(key, leaves_set, colleagues_children,
                                   depth):
            """
            Build the portion of the interaction list that is expected at the
                level of a node's children. Contributes to the U and W lists for
                leaf keys.

            Parameters:
            -----------
            key : np.int64
                Key for the current node being considered.
            leaves_set : set(np.int64)
            colleagues_children : np.array(np.int64)
                The children of a node's colleagues.
            depth : np.int64

            Returns:
            --------
            (np.int64, np.array(dtype=np.int64))
                Four-tuple (u_ptr, u, w_ptr, w), where 'u_ptr' is the length
                of the U list contributions at this level.
            """
            # U List (P2P)
            i = 0
            cc_in_tree = np.zeros_like(colleagues_children)
            for cc in colleagues_children:
                if cc in leaves_set:
                    cc_in_tree[i] = cc
                    i += 1

            cc_in_tree = cc_in_tree[:i]
            adj_idxs = morton.are_adjacent_vec(key, cc_in_tree, depth)
            adjacent = cc_in_tree[adj_idxs == 1]

            # W List (M2P)
            not_adjacent = cc_in_tree[adj_idxs == 0]
            return len(adjacent), adjacent, len(not_adjacent), not_adjacent

        u_ptr = 0
        x_ptr = 0
        v_ptr = 0
        w_ptr = 0

        key = complete[i]

        if key in leaves_set:
            parent = morton.find_parent(key)
            colleagues = morton.find_neighbours(key)
            colleagues_children = morton.find_children_vec(colleagues).ravel()
            colleagues_parents = np.unique(morton.find_parent(colleagues))
            parent_colleagues = morton.find_neighbours(parent)
            parent_colleagues_children = morton.find_children_vec(
                parent_colleagues).ravel()

            pu_ptr, padj, px_ptr, pnadj = build_parent_level_leaf(
                key, leaves_set, colleagues_parents, parent_colleagues, depth)

            u[i][u_ptr:pu_ptr] = padj
            u_ptr = pu_ptr
            x[i][x_ptr:px_ptr] = pnadj

            cu_ptr, cadj, pcc_ptr, pcc_nadj = build_current_level_leaf(
                key, leaves_set, complete_set, colleagues,
                parent_colleagues_children, depth)
            u[i][u_ptr:u_ptr + cu_ptr] = cadj
            u_ptr = pu_ptr + cu_ptr
            v[i][v_ptr:pcc_ptr] = pcc_nadj

            ccu_ptr, ccadj, ccw_ptr, ccnadj = build_child_level_leaf(
                key, leaves_set, colleagues_children, depth)
            u[i][u_ptr:u_ptr + ccu_ptr] = ccadj
            w[i][w_ptr:ccw_ptr] = ccnadj

        else:
            parent = morton.find_parent(key)
            parent_colleagues = morton.find_neighbours(parent)
            parent_colleagues_children = morton.find_children_vec(
                parent_colleagues).ravel()
            pcc_ptr, pcc_nadj = build_current_level_non_leaf(
                key, complete_set, parent_colleagues_children, depth)
            v[i][v_ptr:pcc_ptr] = pcc_nadj
Example #5
0
def test_find_parent(key, expected):
    result = morton.find_parent(key)
    assert result == expected