Example #1
0
class RegularGrid(Grid):
    def __init__(self,grid_desc):
        assert isinstance(grid_desc,(list,tuple))
        for gd in grid_desc:
            assert isinstance(gd,(list,tuple))
            assert 3 == len(gd)        
        self.dim = len(grid_desc)
        self.grid_desc = grid_desc # List of (low,high,num) triples

        (low,hi,num_cells) = zip(*self.grid_desc)
        self.lower_bound = np.array(low,dtype=np.double)
        self.upper_bound = np.array(hi,dtype=np.double)
        self.num_cells = np.array(num_cells,dtype=np.integer)
        assert not np.any(self.num_cells <= 0)
        self.num_nodes = self.num_cells + 1

        # Cell dimensions
        self.delta = (self.upper_bound - self.lower_bound)
        self.delta /= self.num_cells.astype(np.double)

        # Initialize the indexer
        self.cell_indexer = Indexer(self.num_cells)
        self.node_indexer = Indexer(self.num_nodes)

        # Fuzz to convert [low,high) to [low,high]
        self.fuzz = 1e-15

    def points_to_cell_coords(self,points):
        """
        Figure out where points are. Returns the cell coordinate.
        """
        assert is_mat(points) 
        (N,D) = points.shape
        assert D == self.dim
        
        # Get the OOB info
        oob = OutOfBounds()
        oob.build_from_points(self,points)
        assert oob.check()
        
        raw_coords = np.empty((N,D))
        for d in xrange(D):
            (low,high,num_cells) = self.grid_desc[d]
            # Transform: [low,high) |-> [0,n)
            transform = num_cells * (points[:,d] - low) / (high - low)
            transform += self.fuzz
            raw_coords[:,d] = np.floor(transform).astype(np.integer)
            # Add a little fuzz to make sure stuff on the boundary is
            # mapped correctly

            # Fuzz top boundary to get [low,high]
            fuzz_mask = np.logical_and(high <= points[:,d],
                                     points[:,d] < high + 2*self.fuzz)
            raw_coords[fuzz_mask,d] = num_cells - 1
            # Counts things just a littttle bit greater than last cell
            # boundary as part of the last cell
        
        raw_coords[oob.mask,:] = np.nan
        assert is_int(raw_coords)
        coords = Coordinates(raw_coords,oob)
        assert coords.check()

        return coords
    
    def points_to_cell_indices(self,points):
        assert is_mat(points)
        (N,D) = points.shape
        
        cell_coords = self.points_to_cell_coords(points)
        assert isinstance(cell_coords,Coordinates)
        assert (N,D) == cell_coords.shape
        
        cell_indices = self.cell_indexer.coords_to_indices(cell_coords)
        assert is_vect(cell_indices)
        assert (N,) == cell_indices.shape
        
        return cell_indices

    def cell_indices_to_cell_coords(self,cell_indices):
        cell_coords = self.cell_indexer.indices_to_coords(cell_indices)
        return cell_coords

    def cell_indices_to_mid_points(self,cell_indices):
        assert is_vect(cell_indices)

        low_points = cell_indices_to_low_points(self,cell_indices)
        mid_points = low_points + row_vect(0.5 * self.delta)
        assert is_mat(mid_points)
        assert mid_points.shape[0] == cell_indices.shape[0]
        
        return mid_points

    def cell_indices_to_low_points(self,cell_indices):
        assert is_vect(cell_indices)
        
        cell_coords = self.cell_indexer.indices_to_coords(cell_indices)
        assert isinstance(cell_coords,Coordinates)
        assert cell_coords.check()
        
        low_points = self.cell_coords_to_low_points(cell_coords)
        assert is_mat(low_points)
        assert cell_coords.shape == low_points.shape

        return low_points
        
        
    def cell_coords_to_low_points(self,cell_coords):
        assert isinstance(cell_coords,Coordinates)
        assert self.dim == cell_coords.dim
        assert cell_coords.check()
        
        C = cell_coords.coords
        oob = cell_coords.oob
        assert np.all(np.isnan(C[oob.mask,:])) 
        low_points = row_vect(self.lower_bound) + C * row_vect(self.delta)
        
        assert is_mat(low_points)
        
        assert np.all(np.isnan(low_points[oob.mask,:])) 
        assert cell_coords.shape == low_points.shape
        return low_points
    
    def node_indices_to_node_points(self,node_indices):
        assert is_vect(node_indices)
        (N,) = node_indices.shape
        
        node_coords = self.node_indexer.indices_to_coords(node_indices)
        assert isinstance(node_coords,Coordinates)
        
        oob = node_coords.oob
        C = node_coords.coords
        assert np.all(np.isnan(C[oob.mask,:]))

        node_points = row_vect(self.lower_bound) + C * row_vect(self.delta)
        assert is_mat(node_points)
        assert np.all(np.isnan(node_points[oob.mask,:]))
        assert node_coords.shape == node_points.shape
        
        return node_points

    def cell_indices_to_vertex_indices(self,cell_indices):
        assert is_vect(cell_indices)
        
        cell_coords = self.cell_indexer.indices_to_coords(cell_indices)
        assert isinstance(cell_coords,Coordinates)
        
        vertex_indices = self.cell_coords_to_vertex_indices(cell_coords)
        assert is_mat(vertex_indices) # (N x 2**D) matrix

        return vertex_indices
        
    def cell_coords_to_vertex_indices(self,cell_coords):
        assert isinstance(cell_coords,Coordinates)
        (N,D) = cell_coords.shape
        assert self.dim == D


        """
        The low node index in the cell has the same coords in node-land
        as the cell in cell-land:
         |   |
        -o - o-
         | x |
        -x - o-
         |   |
        """        
        low_vertex = self.node_indexer.coords_to_indices(cell_coords)

        # Array of index offsets to reach every vertex in cell
        shift = self.node_indexer.cell_shift()
        assert (2**D,) == shift.shape
        
        vertices = col_vect(low_vertex) + row_vect(shift)
        assert (N,2**D) == vertices.shape

        """
        Handle out of bound nodes. There is a constant offset for 
        converting cell oob indices to node oob indices.
        Also the difference between max spatial indices.
        """
        oob = cell_coords.oob
        if oob.has_oob():
            # Figure out the right oob node
            oob_indices = cell_coords.oob.indices[oob.mask]
            offset = self.node_indexer.get_num_spatial_nodes()
            vertices[oob.mask,0] = oob_indices + offset
            vertices[oob.mask,1:] = np.nan

        return vertices

    def points_to_low_vertex_rel_distance(self,points,cell_coords):
        assert is_mat(points)
        assert isinstance(cell_coords,Coordinates)
        (N,D) = points.shape
        assert (N,D) == cell_coords.shape
        
        low_vertex = self.cell_coords_to_low_points(cell_coords)
        
        dist = np.empty((N,D))
        for d in xrange(D):
            dist[:,d] = (points[:,d] - low_vertex[:,d]) / self.delta[d]

        # OOB -> 0 distance from OOB node
        dist[cell_coords.oob.mask,:] = 0.0
        
        assert np.all(dist >= 0.0)
        assert np.all(dist <= 1.0)

        return dist

    def are_points_oob(self,points):
        """
        Check if points are out-of-bounds
        """
        (N,D) = points.shape
        assert D == self.dim

        L = np.any(points < row_vect(self.lower_bound),axis=1)
        U = np.any(points > row_vect(self.upper_bound) + self.fuzz,axis=1)
        assert (N,) == L.shape
        assert (N,) == U.shape

        return np.logical_or(L,U)