Esempio n. 1
0
class DofCellGrid(SDomain):

    '''
    Get an array with element Dof numbers
    '''
    implements(ICellArraySource)

    cell_grid = Instance(CellGrid)

    get_cell_point_X_arr = DelegatesTo('cell_grid')
    get_cell_mvpoints = DelegatesTo('cell_grid')
    cell_node_map = DelegatesTo('cell_grid')
    get_cell_offset = DelegatesTo('cell_grid')

    # offset of dof within domain list
    #
    dof_offset = Int(0)

    # number of degrees of freedom in a single node
    #
    n_nodal_dofs = Int(3)
    #-------------------------------------------------------------------------
    # Generation methods for geometry and index maps
    #-------------------------------------------------------------------------
    n_dofs = Property(depends_on='cell_grid.shape,n_nodal_dofs,dof_offset')

    def _get_n_dofs(self):
        '''
        Get the total number of DOFs
        '''
        unique_cell_nodes = unique(self.cell_node_map.flatten())
        n_unique_nodes = len(unique_cell_nodes)
        return n_unique_nodes * self.n_nodal_dofs

    dofs = Property(depends_on='cell_grid.shape,n_nodal_dofs,dof_offset')

    @cached_property
    def _get_dofs(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        cell_node_map = self.cell_node_map

        unique_cell_nodes = unique(cell_node_map.flatten())
        n_unique_nodes = len(unique_cell_nodes)

        n_nodal_dofs = self.n_nodal_dofs
        n_nodes = self.cell_grid.point_grid_size
        node_dof_array = repeat(-1, n_nodes *
                                n_nodal_dofs).reshape(n_nodes, n_nodal_dofs)

        # Enumerate the DOFs in the mesh. The result is an array with n_nodes rows
        # and n_nodal_dofs columns
        #
        # A = array( [[ 0, 1 ],
        #             [ 2, 3 ],
        #             [ 4, 5 ]] );
        #
        node_dof_array[ index_exp[ unique_cell_nodes ] ] = \
            arange(
                n_unique_nodes * n_nodal_dofs).reshape(n_unique_nodes, n_nodal_dofs)

        # add the dof_offset before returning the array
        #
        node_dof_array += self.dof_offset
        return node_dof_array

    def _get_doffed_nodes(self):
        '''
        Get the indices of nodes containing DOFs. 
        '''
        cell_node_map = self.cell_node_map

        unique_cell_nodes = unique(cell_node_map.flatten())

        n_nodes = self.cell_grid.point_grid_size
        doffed_nodes = repeat(-1, n_nodes)

        doffed_nodes[index_exp[unique_cell_nodes]] = 1
        return where(doffed_nodes > 0)[0]

    #-----------------------------------------------------------------
    # Elementwise-representation of dofs
    #-----------------------------------------------------------------

    cell_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    def _get_cell_dof_map(self):
        return self.dofs[index_exp[self.cell_grid.cell_node_map]]

    cell_grid_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    def _get_cell_grid_dof_map(self):
        return self.dofs[index_exp[self.cell_grid.cell_grid_node_map]]

    def get_cell_dofs(self, cell_idx):
        return self.cell_dof_map[cell_idx]

    elem_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    @cached_property
    def _get_elem_dof_map(self):
        el_dof_map = copy(self.cell_dof_map)
        tot_shape = el_dof_map.shape[0]
        n_entries = el_dof_map.shape[1] * el_dof_map.shape[2]
        elem_dof_map = el_dof_map.reshape(tot_shape, n_entries)
        return elem_dof_map

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.

        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        dgs = DofGridSlice(dof_grid=self, grid_slice=idx)
        return dgs

    #-----------------------------------------------------------------
    # Spatial queries for dofs
    #-----------------------------------------------------------------

    def _get_dofs_for_nodes(self, nodes):
        '''Get the dof numbers and associated coordinates
        given the array of nodes.
        '''
        doffed_nodes = self._get_doffed_nodes()
#         print 'nodes'
#         print nodes
#         print 'doffed_nodes'
#         print doffed_nodes
        intersect_nodes = intersect1d(nodes, doffed_nodes, assume_unique=False)
        return (self.dofs[index_exp[intersect_nodes]],
                self.cell_grid.point_X_arr[index_exp[intersect_nodes]])

    def get_boundary_dofs(self):
        '''Get the boundary dofs and the associated coordinates
        '''
        nodes = [self.cell_grid.point_idx_grid[s]
                 for s in self.cell_grid.boundary_slices]
        dofs, coords = [], []
        for n in nodes:
            d, c = self._get_dofs_for_nodes(n)
            dofs.append(d)
            coords.append(c)
        return (vstack(dofs), vstack(coords))

    def get_all_dofs(self):
        nodes = self.cell_grid.point_idx_grid[...]
        return self._get_dofs_for_nodes(nodes)

    def get_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_top_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_front_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, :, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_back_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, :, 0]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_front_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_back_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, 0]
        return self._get_dofs_for_nodes(nodes)

    def get_top_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_top_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[0] % 2 == 1:
            slice_middle_x = self.cell_grid.point_idx_grid.shape[0] / 2
            nodes = self.cell_grid.point_idx_grid[slice_middle_x, 0, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_bottom_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in x-direction'

    def get_top_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[0] % 2 == 1:
            slice_middle_x = self.cell_grid.point_idx_grid.shape[0] / 2
            nodes = self.cell_grid.point_idx_grid[slice_middle_x, -1, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_top_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in x-direction'

    def get_left_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[0, slice_middle_y, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_left_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    def get_right_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[-1, slice_middle_y, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_right_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    def get_left_front_bottom_dof(self):
        nodes = self.cell_grid.point_idx_grid[0, 0, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_left_front_middle_dof(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[0, slice_middle_y, -1]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_left_middle_front_dof:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    #-----------------------------------------------------------------
    # Visualization related methods
    #-----------------------------------------------------------------

    refresh_button = Button('Draw')

    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.cell_grid.redraw()

    dof_cell_array = Button

    def _dof_cell_array_fired(self):
        cell_array = self.cell_grid.cell_node_map
        self.show_array = CellArray(data=cell_array,
                                    cell_view=DofCellView(cell_grid=self))
        self.show_array.current_row = 0
        self.show_array.configure_traits(kind='live')
    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('n_nodal_dofs'),
                       Item('dof_offset'),
                       Item('cell_grid@', show_label=False),
                       Item('refresh_button', show_label=False),
                       Item('dof_cell_array', show_label=False),
                       resizable=True,
                       scrollable=True,
                       height=0.5,
                       width=0.5)
Esempio n. 2
0
class DofCellGrid(SDomain):
    '''
    Get an array with element Dof numbers
    '''
    implements(ICellArraySource)

    cell_grid = Instance(CellGrid)

    get_cell_point_X_arr = DelegatesTo('cell_grid')
    get_cell_mvpoints = DelegatesTo('cell_grid')
    cell_node_map = DelegatesTo('cell_grid')
    get_cell_offset = DelegatesTo('cell_grid')

    # offset of dof within domain list
    #
    dof_offset = Int(0)

    # number of degrees of freedom in a single node
    #
    n_nodal_dofs = Int(3)
    #-------------------------------------------------------------------------
    # Generation methods for geometry and index maps
    #-------------------------------------------------------------------------
    n_dofs = Property(depends_on='cell_grid.shape,n_nodal_dofs,dof_offset')

    def _get_n_dofs(self):
        '''
        Get the total number of DOFs
        '''
        unique_cell_nodes = unique(self.cell_node_map.flatten())
        n_unique_nodes = len(unique_cell_nodes)
        return n_unique_nodes * self.n_nodal_dofs

    dofs = Property(depends_on='cell_grid.shape,n_nodal_dofs,dof_offset')

    @cached_property
    def _get_dofs(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        cell_node_map = self.cell_node_map

        unique_cell_nodes = unique(cell_node_map.flatten())
        n_unique_nodes = len(unique_cell_nodes)

        n_nodal_dofs = self.n_nodal_dofs
        n_nodes = self.cell_grid.point_grid_size
        node_dof_array = repeat(-1, n_nodes * n_nodal_dofs).reshape(
            n_nodes, n_nodal_dofs)

        # Enumerate the DOFs in the mesh. The result is an array with n_nodes rows
        # and n_nodal_dofs columns
        #
        # A = array( [[ 0, 1 ],
        #             [ 2, 3 ],
        #             [ 4, 5 ]] );
        #
        node_dof_array[ index_exp[ unique_cell_nodes ] ] = \
            arange(
                n_unique_nodes * n_nodal_dofs).reshape(n_unique_nodes, n_nodal_dofs)

        # add the dof_offset before returning the array
        #
        node_dof_array += self.dof_offset
        return node_dof_array

    def _get_doffed_nodes(self):
        '''
        Get the indices of nodes containing DOFs. 
        '''
        cell_node_map = self.cell_node_map

        unique_cell_nodes = unique(cell_node_map.flatten())

        n_nodes = self.cell_grid.point_grid_size
        doffed_nodes = repeat(-1, n_nodes)

        doffed_nodes[index_exp[unique_cell_nodes]] = 1
        return where(doffed_nodes > 0)[0]

    #-----------------------------------------------------------------
    # Elementwise-representation of dofs
    #-----------------------------------------------------------------

    cell_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    def _get_cell_dof_map(self):
        return self.dofs[index_exp[self.cell_grid.cell_node_map]]

    cell_grid_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    def _get_cell_grid_dof_map(self):
        return self.dofs[index_exp[self.cell_grid.cell_grid_node_map]]

    def get_cell_dofs(self, cell_idx):
        return self.cell_dof_map[cell_idx]

    elem_dof_map = Property(depends_on='cell_grid.shape,n_nodal_dofs')

    @cached_property
    def _get_elem_dof_map(self):
        el_dof_map = copy(self.cell_dof_map)
        tot_shape = el_dof_map.shape[0]
        n_entries = el_dof_map.shape[1] * el_dof_map.shape[2]
        elem_dof_map = el_dof_map.reshape(tot_shape, n_entries)
        return elem_dof_map

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.

        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        dgs = DofGridSlice(dof_grid=self, grid_slice=idx)
        return dgs

    #-----------------------------------------------------------------
    # Spatial queries for dofs
    #-----------------------------------------------------------------

    def _get_dofs_for_nodes(self, nodes):
        '''Get the dof numbers and associated coordinates
        given the array of nodes.
        '''
        doffed_nodes = self._get_doffed_nodes()
        #         print 'nodes'
        #         print nodes
        #         print 'doffed_nodes'
        #         print doffed_nodes
        intersect_nodes = intersect1d(nodes, doffed_nodes, assume_unique=False)
        return (self.dofs[index_exp[intersect_nodes]],
                self.cell_grid.point_X_arr[index_exp[intersect_nodes]])

    def get_boundary_dofs(self):
        '''Get the boundary dofs and the associated coordinates
        '''
        nodes = [
            self.cell_grid.point_idx_grid[s]
            for s in self.cell_grid.boundary_slices
        ]
        dofs, coords = [], []
        for n in nodes:
            d, c = self._get_dofs_for_nodes(n)
            dofs.append(d)
            coords.append(c)
        return (vstack(dofs), vstack(coords))

    def get_all_dofs(self):
        nodes = self.cell_grid.point_idx_grid[...]
        return self._get_dofs_for_nodes(nodes)

    def get_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_top_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_front_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, :, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_back_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, :, 0]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_front_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_back_dofs(self):
        nodes = self.cell_grid.point_idx_grid[:, 0, 0]
        return self._get_dofs_for_nodes(nodes)

    def get_top_left_dofs(self):
        nodes = self.cell_grid.point_idx_grid[0, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, 0, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_top_right_dofs(self):
        nodes = self.cell_grid.point_idx_grid[-1, -1, ...]
        return self._get_dofs_for_nodes(nodes)

    def get_bottom_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[0] % 2 == 1:
            slice_middle_x = self.cell_grid.point_idx_grid.shape[0] / 2
            nodes = self.cell_grid.point_idx_grid[slice_middle_x, 0, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_bottom_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in x-direction'

    def get_top_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[0] % 2 == 1:
            slice_middle_x = self.cell_grid.point_idx_grid.shape[0] / 2
            nodes = self.cell_grid.point_idx_grid[slice_middle_x, -1, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_top_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in x-direction'

    def get_left_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[0, slice_middle_y, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_left_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    def get_right_middle_dofs(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[-1, slice_middle_y, ...]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_right_middle_dofs:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    def get_left_front_bottom_dof(self):
        nodes = self.cell_grid.point_idx_grid[0, 0, -1]
        return self._get_dofs_for_nodes(nodes)

    def get_left_front_middle_dof(self):
        if self.cell_grid.point_idx_grid.shape[1] % 2 == 1:
            slice_middle_y = self.cell_grid.point_idx_grid.shape[1] / 2
            nodes = self.cell_grid.point_idx_grid[0, slice_middle_y, -1]
            return self._get_dofs_for_nodes(nodes)
        else:
            print 'Error in get_left_middle_front_dof:'\
                ' the method is only defined for an odd number of dofs in y-direction'

    #-----------------------------------------------------------------
    # Visualization related methods
    #-----------------------------------------------------------------

    refresh_button = Button('Draw')

    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.cell_grid.redraw()

    dof_cell_array = Button

    def _dof_cell_array_fired(self):
        cell_array = self.cell_grid.cell_node_map
        self.show_array = CellArray(data=cell_array,
                                    cell_view=DofCellView(cell_grid=self))
        self.show_array.current_row = 0
        self.show_array.configure_traits(kind='live')

    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('n_nodal_dofs'),
                       Item('dof_offset'),
                       Item('cell_grid@', show_label=False),
                       Item('refresh_button', show_label=False),
                       Item('dof_cell_array', show_label=False),
                       resizable=True,
                       scrollable=True,
                       height=0.5,
                       width=0.5)
Esempio n. 3
0
 def _dof_cell_array_fired(self):
     cell_array = self.cell_grid.cell_node_map
     self.show_array = CellArray(data=cell_array,
                                 cell_view=DofCellView(cell_grid=self))
     self.show_array.current_row = 0
     self.show_array.configure_traits(kind='live')
Esempio n. 4
0
class GeoCellGrid(SDomain):

    '''
    Get an array with element node coordinates
    '''
    implements(ICellArraySource)
    cell_grid = Instance(CellGrid)

    #-------------------------------------------------------------------------
    # Generation methods for geometry and index maps
    #-------------------------------------------------------------------------
    elem_X_map = Property(depends_on='cell_grid.+')

    @cached_property
    def _get_elem_X_map(self):
        iexp = index_exp[self.cell_grid.cell_node_map]
        return self.cell_grid.point_X_arr[iexp]

    elem_x_map = Property(depends_on='cell_grid.+')

    @cached_property
    def _get_elem_x_map(self):
        iexp = index_exp[self.cell_grid.cell_node_map]
        return self.cell_grid.point_x_arr[iexp]

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.

        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        return GeoGridSlice(geo_grid=self, grid_slice=idx)

    get_cell_point_X_arr = DelegatesTo('cell_grid')
    get_cell_point_x_arr = DelegatesTo('cell_grid')
    get_cell_mvpoints = DelegatesTo('cell_grid')
    cell_node_map = DelegatesTo('cell_grid')
    point_X_grid = DelegatesTo('cell_grid')
    point_x_grid = DelegatesTo('cell_grid')
    n_dims = DelegatesTo('cell_grid')

    def get_cell_node_labels(self, cell_idx):
        iexp = index_exp[self.cell_grid.cell_node_map[cell_idx]]
        return self.cell_grid.points[iexp]

    #-----------------------------------------------------------------
    # Level set interaction methods
    #-----------------------------------------------------------------

    def get_ls_mask(self, ls_mask_function):
        '''Return a boolean array indicating the masked entries of the level set.
        '''
        X_pnt = self.cell_grid.vertex_X_grid
        vect_fn = frompyfunc(ls_mask_function, self.n_dims, 1)
        ls_mask = vect_fn(*X_pnt)
        return ls_mask

    def _get_transiting_edges_1d(self, ls_function, ls_mask_function=None):

        X_pnt = self.cell_grid.vertex_X_grid

        vect_fn = frompyfunc(ls_function, self.n_dims, 1)

        ls = vect_fn(*X_pnt)

        x_edges = where(ls[:-1] * ls[1:] <= 0)
        return x_edges

    def _get_transiting_edges(self, ls_function, ls_limits=None):

        X_pnt = self.cell_grid.vertex_X_grid

        vect_fn = frompyfunc(ls_function, self.n_dims, 1)
        ls = vect_fn(*X_pnt)

        x_edges = where(ls[:-1, :] * ls[1:, :] <= 0)
        y_edges = where(ls[:, :-1] * ls[:, 1:] <= 0)

        ii, jj = x_edges
        # Get element numbers for each dimension separately
        # for each entry in x_edges
        e_idx = []
        for i, j in zip(ii, jj):
            if j < self.cell_grid.shape[1]:
                e_idx.append([i, j])
            if j > 0:
                e_idx.append([i, j - 1])

        ii, jj = y_edges
        for i, j in zip(ii, jj):
            if i < self.cell_grid.shape[0]:
                e_idx.append([i, j])
            if i > 0:
                e_idx.append([i - 1, j])

        if e_idx == []:
            return e_idx
        else:
            e_exp = array(e_idx, dtype=int).transpose()
            return (e_exp[0, :], e_exp[1, :])

    def get_intersected_cells(self, ls_function, ls_mask_function=None):

        if self.n_dims == 1:
            e_idx = self._get_transiting_edges_1d(
                ls_function, ls_mask_function)
        else:
            e_idx = self._get_transiting_edges(ls_function, ls_mask_function)
        return unique(self.cell_grid.cell_idx_grid[e_idx])

    def get_negative_cells(self, ls_function):
        vect_fn = frompyfunc(ls_function, self.n_dims, 1)
        X_pnt = self.cell_grid.vertex_X_grid
        ls = vect_fn(*X_pnt)

        cutoff_slices = [slice(0, -1) for i in range(self.n_dims)]

        ls = ls[cutoff_slices]

        neg_idx = where(ls < 0)
        negative = unique(self.cell_grid.cell_idx_grid[neg_idx])

        intersected = unique(self.get_intersected_cells(ls_function))

        remaining = list(negative)
        for i in intersected:
            try:
                remaining.remove(i)
            except:
                ValueError

        remaining = array(remaining, dtype=int)
        return remaining

    #-------------------------------------------------------------------------
    # Visualization of level sets
    #-------------------------------------------------------------------------

    def get_mvscalars(self):
        return self.level_set_grid.swapaxes(0, self.cell_grid.n_dims - 1).flatten()

    def _get_ielem_points(self):
        #icells = self.get_elem_intersection()
        icells = self.elem_intersection
        mvpoints = []
        for cell_idx in icells:
            mvpoints += list(self.get_cell_mvpoints(cell_idx))
        return array(mvpoints, dtype='float_')

    def _get_ielem_polys(self):
        #ncells = len( self.get_elem_intersection() )
        ncells = len(self.elem_intersection)
        return arange(ncells * 4).reshape(ncells, 4)

    #-----------------------------------------------------------------
    # Visualization related methods
    #-----------------------------------------------------------------

    refresh_button = Button('Draw')

    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.cell_grid.redraw()

    geo_cell_array = Button

    def _geo_cell_array_fired(self):
        elem_array = self.cell_grid.cell_node_map
        self.show_array = CellArray(data=elem_array,
                                    cell_view=GeoCellView(cell_grid=self))
        self.show_array.current_row = 0
        self.show_array.configure_traits(kind='live')

    #-----------------------------------------------------------------
    # Visualization of level sets related methods
    #-----------------------------------------------------------------

    mvp_point_grid = Trait(MVStructuredGrid)

    def _mvp_point_grid_default(self):
        return MVStructuredGrid(name='Point grid',
                                dims=self.cell_grid._get_mvpoints_grid_shape,
                                points=self.cell_grid._get_mvpoints,
                                scalars=self.get_mvscalars)

    mvp_intersect_elems = Trait(MVPolyData)

    def _mvp_intersect_elems_default(self):
        return MVPolyData(name='Intersected elements',
                          points=self._get_ielem_points,
                          polys=self._get_ielem_polys)

    ls_refresh_button = Button('Draw Levelset')

    @on_trait_change('ls_refresh_button')
    def ls_redraw(self):
        '''Redraw the point grid.
        '''
        self.mvp_point_grid.redraw()
        self.mvp_intersect_elems.redraw()

    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('cell_grid@', show_label=False),
                       Item('refresh_button', show_label=False),
                       Item('ls_refresh_button', show_label=False),
                       Item('geo_cell_array', show_label=False),
                       resizable=True,
                       scrollable=True,
                       height=0.5,
                       width=0.5)
Esempio n. 5
0
 def _dof_cell_array_fired(self):
     cell_array = self.cell_grid.cell_node_map
     self.show_array = CellArray(data=cell_array,
                                 cell_view=DofCellView(cell_grid=self))
     self.show_array.current_row = 0
     self.show_array.configure_traits(kind='live')
Esempio n. 6
0
 def _geo_cell_array_fired(self):
     elem_array = self.cell_grid.cell_node_map
     self.show_array = CellArray(data=elem_array,
                                 cell_view=GeoCellView(cell_grid=self))
     self.show_array.current_row = 0
     self.show_array.configure_traits(kind='live')
Esempio n. 7
0
class GeoCellGrid(SDomain):
    '''
    Get an array with element node coordinates
    '''
    implements(ICellArraySource)
    cell_grid = Instance(CellGrid)

    #-------------------------------------------------------------------------
    # Generation methods for geometry and index maps
    #-------------------------------------------------------------------------
    elem_X_map = Property(depends_on='cell_grid.+')

    @cached_property
    def _get_elem_X_map(self):
        iexp = index_exp[self.cell_grid.cell_node_map]
        return self.cell_grid.point_X_arr[iexp]

    elem_x_map = Property(depends_on='cell_grid.+')

    @cached_property
    def _get_elem_x_map(self):
        iexp = index_exp[self.cell_grid.cell_node_map]
        return self.cell_grid.point_x_arr[iexp]

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.

        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        return GeoGridSlice(geo_grid=self, grid_slice=idx)

    get_cell_point_X_arr = DelegatesTo('cell_grid')
    get_cell_point_x_arr = DelegatesTo('cell_grid')
    get_cell_mvpoints = DelegatesTo('cell_grid')
    cell_node_map = DelegatesTo('cell_grid')
    point_X_grid = DelegatesTo('cell_grid')
    point_x_grid = DelegatesTo('cell_grid')
    n_dims = DelegatesTo('cell_grid')

    def get_cell_node_labels(self, cell_idx):
        iexp = index_exp[self.cell_grid.cell_node_map[cell_idx]]
        return self.cell_grid.points[iexp]

    #-----------------------------------------------------------------
    # Level set interaction methods
    #-----------------------------------------------------------------

    def get_ls_mask(self, ls_mask_function):
        '''Return a boolean array indicating the masked entries of the level set.
        '''
        X_pnt = self.cell_grid.vertex_X_grid
        vect_fn = frompyfunc(ls_mask_function, self.n_dims, 1)
        ls_mask = vect_fn(*X_pnt)
        return ls_mask

    def _get_transiting_edges_1d(self, ls_function, ls_mask_function=None):

        X_pnt = self.cell_grid.vertex_X_grid

        vect_fn = frompyfunc(ls_function, self.n_dims, 1)

        ls = vect_fn(*X_pnt)

        x_edges = where(ls[:-1] * ls[1:] <= 0)
        return x_edges

    def _get_transiting_edges(self, ls_function, ls_limits=None):

        X_pnt = self.cell_grid.vertex_X_grid

        vect_fn = frompyfunc(ls_function, self.n_dims, 1)
        ls = vect_fn(*X_pnt)

        x_edges = where(ls[:-1, :] * ls[1:, :] <= 0)
        y_edges = where(ls[:, :-1] * ls[:, 1:] <= 0)

        ii, jj = x_edges
        # Get element numbers for each dimension separately
        # for each entry in x_edges
        e_idx = []
        for i, j in zip(ii, jj):
            if j < self.cell_grid.shape[1]:
                e_idx.append([i, j])
            if j > 0:
                e_idx.append([i, j - 1])

        ii, jj = y_edges
        for i, j in zip(ii, jj):
            if i < self.cell_grid.shape[0]:
                e_idx.append([i, j])
            if i > 0:
                e_idx.append([i - 1, j])

        if e_idx == []:
            return e_idx
        else:
            e_exp = array(e_idx, dtype=int).transpose()
            return (e_exp[0, :], e_exp[1, :])

    def get_intersected_cells(self, ls_function, ls_mask_function=None):

        if self.n_dims == 1:
            e_idx = self._get_transiting_edges_1d(ls_function,
                                                  ls_mask_function)
        else:
            e_idx = self._get_transiting_edges(ls_function, ls_mask_function)
        return unique(self.cell_grid.cell_idx_grid[e_idx])

    def get_negative_cells(self, ls_function):
        vect_fn = frompyfunc(ls_function, self.n_dims, 1)
        X_pnt = self.cell_grid.vertex_X_grid
        ls = vect_fn(*X_pnt)

        cutoff_slices = [slice(0, -1) for i in range(self.n_dims)]

        ls = ls[cutoff_slices]

        neg_idx = where(ls < 0)
        negative = unique(self.cell_grid.cell_idx_grid[neg_idx])

        intersected = unique(self.get_intersected_cells(ls_function))

        remaining = list(negative)
        for i in intersected:
            try:
                remaining.remove(i)
            except:
                ValueError

        remaining = array(remaining, dtype=int)
        return remaining

    #-------------------------------------------------------------------------
    # Visualization of level sets
    #-------------------------------------------------------------------------

    def get_mvscalars(self):
        return self.level_set_grid.swapaxes(0, self.cell_grid.n_dims -
                                            1).flatten()

    def _get_ielem_points(self):
        #icells = self.get_elem_intersection()
        icells = self.elem_intersection
        mvpoints = []
        for cell_idx in icells:
            mvpoints += list(self.get_cell_mvpoints(cell_idx))
        return array(mvpoints, dtype='float_')

    def _get_ielem_polys(self):
        #ncells = len( self.get_elem_intersection() )
        ncells = len(self.elem_intersection)
        return arange(ncells * 4).reshape(ncells, 4)

    #-----------------------------------------------------------------
    # Visualization related methods
    #-----------------------------------------------------------------

    refresh_button = Button('Draw')

    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.cell_grid.redraw()

    geo_cell_array = Button

    def _geo_cell_array_fired(self):
        elem_array = self.cell_grid.cell_node_map
        self.show_array = CellArray(data=elem_array,
                                    cell_view=GeoCellView(cell_grid=self))
        self.show_array.current_row = 0
        self.show_array.configure_traits(kind='live')

    #-----------------------------------------------------------------
    # Visualization of level sets related methods
    #-----------------------------------------------------------------

    mvp_point_grid = Trait(MVStructuredGrid)

    def _mvp_point_grid_default(self):
        return MVStructuredGrid(name='Point grid',
                                dims=self.cell_grid._get_mvpoints_grid_shape,
                                points=self.cell_grid._get_mvpoints,
                                scalars=self.get_mvscalars)

    mvp_intersect_elems = Trait(MVPolyData)

    def _mvp_intersect_elems_default(self):
        return MVPolyData(name='Intersected elements',
                          points=self._get_ielem_points,
                          polys=self._get_ielem_polys)

    ls_refresh_button = Button('Draw Levelset')

    @on_trait_change('ls_refresh_button')
    def ls_redraw(self):
        '''Redraw the point grid.
        '''
        self.mvp_point_grid.redraw()
        self.mvp_intersect_elems.redraw()

    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('cell_grid@', show_label=False),
                       Item('refresh_button', show_label=False),
                       Item('ls_refresh_button', show_label=False),
                       Item('geo_cell_array', show_label=False),
                       resizable=True,
                       scrollable=True,
                       height=0.5,
                       width=0.5)
Esempio n. 8
0
 def _geo_cell_array_fired(self):
     elem_array = self.cell_grid.cell_node_map
     self.show_array = CellArray(data=elem_array,
                                 cell_view=GeoCellView(cell_grid=self))
     self.show_array.current_row = 0
     self.show_array.configure_traits(kind='live')
Esempio n. 9
0
class CellGrid(SDomain):
    '''
    Manage an array of cells defined within a structured grid.
    
    The distinction between the coordinate information supplied 
    in the arrazs is done using the following naming convention:
    
    point - geometrical points within the regular grid
    
    node - point specified in the grid_cell specification
    
    vertex - node with topological function (corner nodes)
    
    base_node - the first node of an element
    
    point_idx_grid ... enumeration of points within the point_grid
     
    cell_idx_grid ... enumeration of cells in the grid maps the 
                      topological index to the flattened index
                      ( ix, iy, iz ) -> ii
    
    cell_node_map ... array mapping the cell idx to the  point idx 
                      representing a node of the cell

    '''
    implements(ICellArraySource)

    # Everything depends on the grid_cell_specification
    # defining the distribution of nodes within the cell.
    #
    grid_cell_spec = Instance(CellSpec)
    def _grid_cell_spec_default(self):
        return CellSpec()

    n_dims = Delegate('grid_cell_spec')

    # Grid cell template - gets repeated according to the 
    # within the grid geometry specification
    #
    grid_cell = Property(depends_on = 'grid_cell_spec.+')
    @cached_property
    def _get_grid_cell(self):
        return GridCell(grid_cell_spec = self.grid_cell_spec)

    # Grid geometry specification
    #
    coord_min = Array(Float, value = [ 0., 0., 0.])
    coord_max = Array(Float, value = [ 1., 1., 1.])

    # Remark[rch]: 
    # beware - the Int type is not regarded as a normal int
    # within an array and must be first converted to int array
    #
    # Had we defined int as the dtype of an array, there would
    # be errors during editing
    #
    shape = Array(Int, value = [ 1, 1, 1 ])

    # Derived specifier for element grid shape
    # It converts the Int array to int so that it can be
    # used by general numpy operators
    #
    cell_idx_grid_shape = Property(Array(int), depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid_shape(self):
        return array(self.shape, dtype = int)

    cell_idx_grid_size = Property(Int, depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid_size(self):
        return reduce(lambda x, y: x * y, self.cell_idx_grid_shape)

    # Grid with the enumeration of the cells respecting
    # the dimensionality. This grid is used to implement
    # the mapping between the cells and nodes.
    #
    cell_idx_grid = Property(Array(int), depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid(self):
        return arange(self.cell_idx_grid_size).reshape(self.cell_idx_grid_shape)

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.
        
        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        return CellGridSlice(cell_grid = self, grid_slice = idx)

    #-------------------------------------------------------------------------
    # Shape and size characteristics used for both the idx_grid and point_grid
    #-------------------------------------------------------------------------
    def _get_point_grid_shape(self):
        '''Get the grid shape for the full index and point grids.
        
        This is the background grid. Some of the nodes can be unused by the
        cells depending on the specification in the grid_cell_spec.
        '''
        cell_shape = self.grid_cell_spec.get_cell_shape().astype(int)
        cell_idx_grid_shape = self.cell_idx_grid_shape
        return multiply(cell_shape - 1, cell_idx_grid_shape) + 1

    point_grid_size = Property(depends_on = 'shape,grid_cell_spec.node_coords')
    def _get_point_grid_size(self):
        '''Get the size of the full index and point grids
        '''
        shape = self._get_point_grid_shape()
        return reduce(lambda i, j: i * j, shape)

    #-------------------------------------------------------------------------
    # point_idx_grid - shaping and slicing methods for construction and orientation
    # point_idx_grid represents the enumeration of the nodes of the cell grid. It 
    # serves for constructing the mappings between cells and nodes.   
    #-------------------------------------------------------------------------
    def _get_point_idx_grid_slices(self):
        '''Get slices defining the index grid in a format suitable 
        for mgrid generation.
        '''
        subcell_shape = self.grid_cell_spec.get_cell_shape() - 1
        cell_idx_grid_shape = self.cell_idx_grid_shape
        return tuple([ slice(0, c * g + 1)
                        for c, g in zip(subcell_shape, cell_idx_grid_shape) ])

    point_idx_grid = Property(Array, depends_on = 'shape,grid_cell_spec.node_coords')
    @cached_property
    def _get_point_idx_grid(self):
        '''Get the index numbers of the points within the grid
        '''
        return arange(self.point_grid_size).reshape(self._get_point_grid_shape())

    #-------------------------------------------------------------------------------------
    # Unit cell enumeration - used as a template for enumerations in 3D
    #-------------------------------------------------------------------------------------
    idx_cell_slices = Property(Tuple)
    def _get_idx_cell_slices(self):
        '''Get slices extracting the first cell from the point index grid
        '''
        cell_shape = self.grid_cell_spec.get_cell_shape()
        return tuple([ slice(0, c)
                        for c in cell_shape ])

    idx_cell = Property(Array)
    def _get_idx_cell(self):
        '''Get the node map within a cell of a 1-3 dimensional grid
        
        The enumeration of nodes within a single cell is managed by the
        self.grid_cell. This must be adapted to the global enumeration of the grid.
        
        The innermost index runs over the z-axis. Thus, the index of the points
        on the z axis is [0,1,...,shape[2]-1]. The following node at the y axis has 
        the number [shape[2], shape[2]+1, ..., shape[2]*2].
        '''
        return self.point_idx_grid[ self.idx_cell_slices ]

    def get_cell_idx(self, offset):
        '''Get the address of the cell within the cell grid.
        '''
        idx_tuple = zeros((self.n_dims,), dtype = 'int_')
        roof = offset
        for i, n in enumerate(self.shape[-1:0:-1]):
            idx = roof / (n)
            roof -= idx * n
            idx_tuple[i] = idx
        idx_tuple[ self.n_dims - 1 ] = roof
        return tuple(idx_tuple)

    def get_cell_offset(self, idx_tuple):
        '''Get the index of the cell within the flattened list.
        '''
        return self.cell_idx_grid[ idx_tuple ]

    #-------------------------------------------------------------------------
    # vertex slices
    #-------------------------------------------------------------------------
    vertex_slices = Property
    def _get_vertex_slices(self):
        cell_shape = self.grid_cell_spec.get_cell_shape()
        return tuple([ slice(0, None, c - 1)
                        for c in cell_shape ])

    #-------------------------------------------------------------------------
    # point_grid - shaping and slicing methods for construction and orientation
    #-------------------------------------------------------------------------
    point_x_grid_slices = Property
    def _get_point_x_grid_slices(self):
        '''Get the slices to be used for the mgrid tool 
        to generate the point grid.
        '''
        ndims = self.n_dims
        shape = self._get_point_grid_shape()
        return tuple([ slice(float(self.coord_min[i]),
                               float(self.coord_max[i]),
                               complex(0, shape[i]))
                               for i in range(ndims) ])

    #-------------------------------------------------------------------------------------
    # Geometry transformation
    #-------------------------------------------------------------------------------------
    geo_transform = Callable

    geo_transform_vfn = Property
    def _get_geo_transform_vfn(self):
        vfn_shell_stb = frompyfunc(self.geo_transform, 2, 3)

    #-------------------------------------------------------------------------------------
    # Point coordinates x - is parametric, X - is global
    #-------------------------------------------------------------------------------------
    point_x_grid = Property(depends_on = 'grid_cell_spec.+,shape,coord_min,coord_max')
    @cached_property
    def _get_point_x_grid(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        return mgrid[ self._get_point_x_grid_slices() ]

    point_X_grid = Property
    def _get_point_X_grid(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        x_dim_shape = self.point_x_grid.shape[1:]
        return array([ self.point_X_arr[:, i].reshape(x_dim_shape)
                       for i in range(self.n_dims) ], dtype = 'float_')

    point_x_arr = Property
    def _get_point_x_arr(self):
        return c_[ tuple([ x.flatten() for x in self.point_x_grid ]) ]

    point_X_arr = Property(depends_on = 'grid_cell_spec,shape,coord_min,coord_max')
    @cached_property
    def _get_point_X_arr(self):
        '''Get the (n,3) array with point coordinates.
        '''
        # If the geo transform has been set, perform the mapping
        #
        if self.geo_transform:
            return self.geo_transform(self.point_x_arr)
        else:
            return self.point_x_arr

    #-------------------------------------------------------------------------
    # Vertex manipulations
    #-------------------------------------------------------------------------
    vertex_idx_grid = Property
    def _get_vertex_idx_grid(self):
        '''
        Construct the base node grid. Base node has the lowest number within a cell.
        All relevant cell_node numbers can be derived just be adding an array
        of relative node offsets within the cell to the base node.
        (see the method get_cell_nodes( cell_num)  below)  
        '''
        # get the cell shape - number of cell points without the next base point
        subcell_shape = self.grid_cell_spec.get_cell_shape().astype(int) - 1
        # get the element grid shape (number of elements in each dimension)
        cell_idx_grid_shape = self.cell_idx_grid_shape

        # The following code determines the offsets between two neighbouring nodes
        # along each axis. It loops over the axes so that also 1- and 2- dimensional
        # grids are included. For 3D grid - the following code shows what's happening
        #
        # 1) get the index offset between two neighboring points on the z-axis
        #  
        # z_offset = subcell_shape[2]
        #
        # 2) get the index offset between two neighboring points on the y-axis
        #  
        # y_offset = ( cell_idx_grid_shape[2] * subcell_shape[2] + 1) * subcell_shape[1]
        #
        # 3) get the index offset between two neighboring points on the x-axis
        #  
        # x_offset = ( cell_idx_grid_shape[2] * subcell_shape[2] + 1 ) * \
        #            ( cell_idx_grid_shape[1] * subcell_shape[1] + 1 ) * \
        #            subcell_shape[0]

        offsets = zeros(self.n_dims, dtype = 'int_')

        for i in range(self.n_dims - 1, -1, -1):
            offsets[i] = subcell_shape[i]
            for j in range(i + 1, self.n_dims):
                offsets[i] *= (cell_idx_grid_shape[j] * subcell_shape[j] + 1)

        # grid shape (shape + 1)
        gshape = cell_idx_grid_shape + 1

        # Determine the offsets of all base nodes on each axis by multiplying
        # the respective offset with a point enumeration on that axis
        #
        # In 3D corresponds to the following
        # 
        #        xi_offsets = x_offset * arange( gshape[0] )
        #        yi_offsets = y_offset * arange( gshape[1] )
        #        zi_offsets = z_offset * arange( gshape[2] )

        all_offsets = [ offsets[n] * arange(gshape[n]) for n in range(self.n_dims) ]

        # Construct the broadcastable slices used for the construction of the 
        # base node index grid. In 3D this corresponds to the following:
        #
        # Expand the dimension of offsets and sum them up. using broadcasting
        # this generates the grid of the base nodes (the last node is cut away 
        # as it does not hold any element
        #        idx_grid = xi_offsets[:-1,None,None] + \
        #                   yi_offsets[None,:-1,None] + \
        #                   zi_offsets[None,None,:-1]

        slices = []
        for i in range(self.n_dims):
            s = [ None for j in range(self.n_dims) ]
            s[i] = slice(None)
            slices.append(tuple(s))

        vertex_offsets = [ all_offsets[i][ slices[i] ] for i in range(self.n_dims) ]
        vertex_idx_grid = reduce(add, vertex_offsets)

        # return the indexes of the vertex nodes
        return vertex_idx_grid

    vertex_idx_arr = Property
    def _get_vertex_idx_arr(self):
        '''Get the index of nodes at the vertex of the cells
        of the cells. The result is a sorted flat array. The base node 
        position within the returned array defines the index of the cell. 
        '''
        vertex_idx_grid = self.vertex_idx_grid
        return sort(vertex_idx_grid.flatten())

    vertex_x_grid = Property
    def _get_vertex_x_grid(self):
        return array([ x_grid[ self.vertex_slices ] for x_grid in self.point_x_grid ])

    vertex_X_grid = Property
    def _get_vertex_X_grid(self):
        return array([ X_grid[ self.vertex_slices ] for X_grid in self.point_X_grid ])

    vertex_x_arr = Property
    def _get_vertex_x_arr(self):
        return c_[ tuple([ x.flatten() for x in self.vertex_x_grid ]) ]

    vertex_X_arr = Property
    def _get_vertex_X_arr(self):
        return c_[ tuple([ X.flatten() for X in self.vertex_X_grid ]) ]

    #----------------------------------------------------------------------------
    # Cell manipulations
    #-----------------------------------------------------------------------------
    base_nodes = Property
    def _get_base_nodes(self):
        '''Get the index of nodes that are the bottom left front vertexs
        of the cells. The result is a sorted flat array. The base node 
        position within the returned array defines the index of the cell. 
        '''
        vertex_idx_grid = self.vertex_idx_grid
        cutoff_last = [ slice(0, -1) for i in range(self.n_dims) ]
        base_node_grid = vertex_idx_grid[ cutoff_last ]
        return sort(base_node_grid.flatten())

    cell_node_map = Property(depends_on = 'shape,grid_cell_spec.+')
    @cached_property
    def _get_cell_node_map(self):
        '''
        Construct an array with the mapping between elements and nodes. 
        Returns the dof for [ cell_idx, node, dim ]
        '''
        idx_cell = self.idx_cell
        node_map = idx_cell.flatten()[ self.grid_cell.node_map ]
        base_nodes = self.base_nodes

        # Use broadcasting to construct the node map for all elements
        #
        cell_node_map = base_nodes[:, None] + node_map[None, :]
        return cell_node_map

    cell_grid_node_map = Property(depends_on = 'shape,grid_cell_spec.+')
    @cached_property
    def _get_cell_grid_node_map(self):
        '''
        Return the dof for [ cell_x, cell_y, node, dim ]
        where 
        - cell_x - is the cell index in the first dimension
        - cell_y - is the cell index in the second dimension
        - node - is the node index within the cell
        - dim - is the index of the dof within the node
        '''
        new_shape = tuple(self.shape) + self.cell_node_map.shape[1:]
        return self.cell_node_map.reshape(new_shape)

    def get_cell_point_x_arr(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        '''
        iexp = index_exp[ self.cell_node_map[ cell_idx ] ]
        return self.point_x_arr[ iexp ]

    def get_cell_point_X_arr(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        '''
        iexp = index_exp[ self.cell_node_map[ cell_idx ] ]
        return self.point_X_arr[ iexp ]

    #-----------------------------------------------------------------------------
    # @todo - candidate for deletion - the slicing operator [] is doing this more generally
    #-----------------------------------------------------------------------------
    boundary_slices = Property(depends_on = 'grid_cell_spec.+')
    @cached_property
    def _get_boundary_slices(self):
        '''Get the slices to get the boundary nodes.
        '''
        # slices must correspond to the dimensions
        slices = []
        for i in range(self.n_dims):
            s_low = [ slice(None) for j in range(self.n_dims) ]
            s_low[i] = 0
            s_high = [ slice(None) for j in range(self.n_dims) ]
            s_high[i] = -1
            slices.append(s_low)
            slices.append(s_high)
        return slices

    #--------------------------------------------------------------------------
    # Wrappers exporting the grid date to mayavi pipelines
    #--------------------------------------------------------------------------\

    def get_cell_mvpoints(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        In case that the grid is in reduced dimensions - blow it up with zeros.
        '''
        points = self.get_cell_point_X_arr(cell_idx)

        # augment the points to be 3D
        if self.n_dims < 3:
            mvpoints = zeros((points.shape[ 0 ], 3), dtype = 'float_')
            mvpoints[ :, :self.n_dims ] = points
            return mvpoints
        else:
            return points

    def _get_mvpoints_grid_shape(self):
        '''Shape of point grid in 3D.
        The information is needed by the mayavi pipeline to use the
        StructuredGrid source - tvtk class.
        '''
        shape = self._get_point_grid_shape()
        return tuple(list(shape) + [1 for n in range(3 - len(shape)) ])

    def _get_mvpoints(self, swap = True):
        '''Get the points in with deepest index along the x axes.
        This format is required when putting the point data to the 
        vtk structured grid.
        '''
        point_X_grid = self.point_X_grid
        if swap == True:
            point_X_grid = point_X_grid.swapaxes(1, self.n_dims)

        point_X_arr = c_[ tuple([ X.flatten() for X in point_X_grid ]) ]

        # augment the points to be 3D
        if self.n_dims < 3:
            mv_points = zeros((point_X_arr.shape[ 0 ], 3), dtype = 'float_')
            mv_points[ :, :self.n_dims ] = point_X_arr
            return mv_points
        else:
            return point_X_arr

    #-----------------------------------------------------------------
    # Visualization-related methods
    #-----------------------------------------------------------------

    mvp_point_grid = Trait(MVStructuredGrid)
    def _mvp_point_grid_default(self):
        return MVStructuredGrid(name = 'Point grid',
                                  dims = self._get_mvpoints_grid_shape,
                                  points = self._get_mvpoints)

    refresh_button = Button('Draw')
    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.mvp_point_grid.redraw()

    cell_array = Button('Browse cell array')
    def _cell_array_fired(self):
        cell_array = self.cell_node_map
        self.show_array = CellArray(data = cell_array,
                                     cell_view = CellView(cell_grid = self))
        self.show_array.configure_traits(kind = 'live')

    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('grid_cell_spec'),
                       Item('shape@'),
                       Item('coord_min'),
                       Item('coord_max'),
                       Item('refresh_button'),
                       Item('cell_array'),
                       resizable = True,
                       scrollable = True,
                       height = 0.5,
                       width = 0.5)
Esempio n. 10
0
class CellGrid(SDomain):
    '''
    Manage an array of cells defined within a structured grid.
    
    The distinction between the coordinate information supplied 
    in the arrazs is done using the following naming convention:
    
    point - geometrical points within the regular grid
    
    node - point specified in the grid_cell specification
    
    vertex - node with topological function (corner nodes)
    
    base_node - the first node of an element
    
    point_idx_grid ... enumeration of points within the point_grid
     
    cell_idx_grid ... enumeration of cells in the grid maps the 
                      topological index to the flattened index
                      ( ix, iy, iz ) -> ii
    
    cell_node_map ... array mapping the cell idx to the  point idx 
                      representing a node of the cell

    '''
    implements(ICellArraySource)

    # Everything depends on the grid_cell_specification
    # defining the distribution of nodes within the cell.
    #
    grid_cell_spec = Instance(CellSpec)
    def _grid_cell_spec_default(self):
        return CellSpec()

    n_dims = Delegate('grid_cell_spec')

    # Grid cell template - gets repeated according to the 
    # within the grid geometry specification
    #
    grid_cell = Property(depends_on = 'grid_cell_spec.+')
    @cached_property
    def _get_grid_cell(self):
        return GridCell(grid_cell_spec = self.grid_cell_spec)

    # Grid geometry specification
    #
    coord_min = Array(Float, value = [ 0., 0., 0.])
    coord_max = Array(Float, value = [ 1., 1., 1.])

    # Remark[rch]: 
    # beware - the Int type is not regarded as a normal int
    # within an array and must be first converted to int array
    #
    # Had we defined int as the dtype of an array, there would
    # be errors during editing
    #
    shape = Array(Int, value = [ 1, 1, 1 ])

    # Derived specifier for element grid shape
    # It converts the Int array to int so that it can be
    # used by general numpy operators
    #
    cell_idx_grid_shape = Property(Array(int), depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid_shape(self):
        return array(self.shape, dtype = int)

    cell_idx_grid_size = Property(Int, depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid_size(self):
        return reduce(lambda x, y: x * y, self.cell_idx_grid_shape)

    # Grid with the enumeration of the cells respecting
    # the dimensionality. This grid is used to implement
    # the mapping between the cells and nodes.
    #
    cell_idx_grid = Property(Array(int), depends_on = 'shape')
    @cached_property
    def _get_cell_idx_grid(self):
        return arange(self.cell_idx_grid_size).reshape(self.cell_idx_grid_shape)

    def __getitem__(self, idx):
        '''High level access and slicing to the cells within the grid.
        
        The return value is a tuple with 
        1. array of cell indices
        2. array of nodes for each element
        3. array of coordinates for each node.
        '''
        return CellGridSlice(cell_grid = self, grid_slice = idx)

    #-------------------------------------------------------------------------
    # Shape and size characteristics used for both the idx_grid and point_grid
    #-------------------------------------------------------------------------
    def _get_point_grid_shape(self):
        '''Get the grid shape for the full index and point grids.
        
        This is the background grid. Some of the nodes can be unused by the
        cells depending on the specification in the grid_cell_spec.
        '''
        cell_shape = self.grid_cell_spec.get_cell_shape().astype(int)
        cell_idx_grid_shape = self.cell_idx_grid_shape
        return multiply(cell_shape - 1, cell_idx_grid_shape) + 1

    point_grid_size = Property(depends_on = 'shape,grid_cell_spec.node_coords')
    def _get_point_grid_size(self):
        '''Get the size of the full index and point grids
        '''
        shape = self._get_point_grid_shape()
        return reduce(lambda i, j: i * j, shape)

    #-------------------------------------------------------------------------
    # point_idx_grid - shaping and slicing methods for construction and orientation
    # point_idx_grid represents the enumeration of the nodes of the cell grid. It 
    # serves for constructing the mappings between cells and nodes.   
    #-------------------------------------------------------------------------
    def _get_point_idx_grid_slices(self):
        '''Get slices defining the index grid in a format suitable 
        for mgrid generation.
        '''
        subcell_shape = self.grid_cell_spec.get_cell_shape() - 1
        cell_idx_grid_shape = self.cell_idx_grid_shape
        return tuple([ slice(0, c * g + 1)
                        for c, g in zip(subcell_shape, cell_idx_grid_shape) ])

    point_idx_grid = Property(Array, depends_on = 'shape,grid_cell_spec.node_coords')
    @cached_property
    def _get_point_idx_grid(self):
        '''Get the index numbers of the points within the grid
        '''
        return arange(self.point_grid_size).reshape(self._get_point_grid_shape())

    #-------------------------------------------------------------------------------------
    # Unit cell enumeration - used as a template for enumerations in 3D
    #-------------------------------------------------------------------------------------
    idx_cell_slices = Property(Tuple)
    def _get_idx_cell_slices(self):
        '''Get slices extracting the first cell from the point index grid
        '''
        cell_shape = self.grid_cell_spec.get_cell_shape()
        return tuple([ slice(0, c)
                        for c in cell_shape ])

    idx_cell = Property(Array)
    def _get_idx_cell(self):
        '''Get the node map within a cell of a 1-3 dimensional grid
        
        The enumeration of nodes within a single cell is managed by the
        self.grid_cell. This must be adapted to the global enumeration of the grid.
        
        The innermost index runs over the z-axis. Thus, the index of the points
        on the z axis is [0,1,...,shape[2]-1]. The following node at the y axis has 
        the number [shape[2], shape[2]+1, ..., shape[2]*2].
        '''
        return self.point_idx_grid[ self.idx_cell_slices ]

    def get_cell_idx(self, offset):
        '''Get the address of the cell within the cell grid.
        '''
        idx_tuple = zeros((self.n_dims,), dtype = 'int_')
        roof = offset
        for i, n in enumerate(self.shape[-1:0:-1]):
            idx = roof / (n)
            roof -= idx * n
            idx_tuple[i] = idx
        idx_tuple[ self.n_dims - 1 ] = roof
        return tuple(idx_tuple)

    def get_cell_offset(self, idx_tuple):
        '''Get the index of the cell within the flattened list.
        '''
        return self.cell_idx_grid[ idx_tuple ]

    #-------------------------------------------------------------------------
    # vertex slices
    #-------------------------------------------------------------------------
    vertex_slices = Property
    def _get_vertex_slices(self):
        cell_shape = self.grid_cell_spec.get_cell_shape()
        return tuple([ slice(0, None, c - 1)
                        for c in cell_shape ])

    #-------------------------------------------------------------------------
    # point_grid - shaping and slicing methods for construction and orientation
    #-------------------------------------------------------------------------
    point_x_grid_slices = Property
    def _get_point_x_grid_slices(self):
        '''Get the slices to be used for the mgrid tool 
        to generate the point grid.
        '''
        ndims = self.n_dims
        shape = self._get_point_grid_shape()
        return tuple([ slice(float(self.coord_min[i]),
                               float(self.coord_max[i]),
                               complex(0, shape[i]))
                               for i in range(ndims) ])

    #-------------------------------------------------------------------------------------
    # Geometry transformation
    #-------------------------------------------------------------------------------------
    geo_transform = Callable

    geo_transform_vfn = Property
    def _get_geo_transform_vfn(self):
        vfn_shell_stb = frompyfunc(self.geo_transform, 2, 3)

    #-------------------------------------------------------------------------------------
    # Point coordinates x - is parametric, X - is global
    #-------------------------------------------------------------------------------------
    point_x_grid = Property(depends_on = 'grid_cell_spec.+,shape,coord_min,coord_max')
    @cached_property
    def _get_point_x_grid(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        return mgrid[ self._get_point_x_grid_slices() ]

    point_X_grid = Property
    def _get_point_X_grid(self):
        '''
        Construct the point grid underlying the mesh grid structure.
        '''
        x_dim_shape = self.point_x_grid.shape[1:]
        return array([ self.point_X_arr[:, i].reshape(x_dim_shape)
                       for i in range(self.n_dims) ], dtype = 'float_')

    point_x_arr = Property
    def _get_point_x_arr(self):
        return c_[ tuple([ x.flatten() for x in self.point_x_grid ]) ]

    point_X_arr = Property(depends_on = 'grid_cell_spec,shape,coord_min,coord_max')
    @cached_property
    def _get_point_X_arr(self):
        '''Get the (n,3) array with point coordinates.
        '''
        # If the geo transform has been set, perform the mapping
        #
        if self.geo_transform:
            return self.geo_transform(self.point_x_arr)
        else:
            return self.point_x_arr

    #-------------------------------------------------------------------------
    # Vertex manipulations
    #-------------------------------------------------------------------------
    vertex_idx_grid = Property
    def _get_vertex_idx_grid(self):
        '''
        Construct the base node grid. Base node has the lowest number within a cell.
        All relevant cell_node numbers can be derived just be adding an array
        of relative node offsets within the cell to the base node.
        (see the method get_cell_nodes( cell_num)  below)  
        '''
        # get the cell shape - number of cell points without the next base point
        subcell_shape = self.grid_cell_spec.get_cell_shape().astype(int) - 1
        # get the element grid shape (number of elements in each dimension)
        cell_idx_grid_shape = self.cell_idx_grid_shape

        # The following code determines the offsets between two neighbouring nodes
        # along each axis. It loops over the axes so that also 1- and 2- dimensional
        # grids are included. For 3D grid - the following code shows what's happening
        #
        # 1) get the index offset between two neighboring points on the z-axis
        #  
        # z_offset = subcell_shape[2]
        #
        # 2) get the index offset between two neighboring points on the y-axis
        #  
        # y_offset = ( cell_idx_grid_shape[2] * subcell_shape[2] + 1) * subcell_shape[1]
        #
        # 3) get the index offset between two neighboring points on the x-axis
        #  
        # x_offset = ( cell_idx_grid_shape[2] * subcell_shape[2] + 1 ) * \
        #            ( cell_idx_grid_shape[1] * subcell_shape[1] + 1 ) * \
        #            subcell_shape[0]

        offsets = zeros(self.n_dims, dtype = 'int_')

        for i in range(self.n_dims - 1, -1, -1):
            offsets[i] = subcell_shape[i]
            for j in range(i + 1, self.n_dims):
                offsets[i] *= (cell_idx_grid_shape[j] * subcell_shape[j] + 1)

        # grid shape (shape + 1)
        gshape = cell_idx_grid_shape + 1

        # Determine the offsets of all base nodes on each axis by multiplying
        # the respective offset with a point enumeration on that axis
        #
        # In 3D corresponds to the following
        # 
        #        xi_offsets = x_offset * arange( gshape[0] )
        #        yi_offsets = y_offset * arange( gshape[1] )
        #        zi_offsets = z_offset * arange( gshape[2] )

        all_offsets = [ offsets[n] * arange(gshape[n]) for n in range(self.n_dims) ]

        # Construct the broadcastable slices used for the construction of the 
        # base node index grid. In 3D this corresponds to the following:
        #
        # Expand the dimension of offsets and sum them up. using broadcasting
        # this generates the grid of the base nodes (the last node is cut away 
        # as it does not hold any element
        #        idx_grid = xi_offsets[:-1,None,None] + \
        #                   yi_offsets[None,:-1,None] + \
        #                   zi_offsets[None,None,:-1]

        slices = []
        for i in range(self.n_dims):
            s = [ None for j in range(self.n_dims) ]
            s[i] = slice(None)
            slices.append(tuple(s))

        vertex_offsets = [ all_offsets[i][ slices[i] ] for i in range(self.n_dims) ]
        vertex_idx_grid = reduce(add, vertex_offsets)

        # return the indexes of the vertex nodes
        return vertex_idx_grid

    vertex_idx_arr = Property
    def _get_vertex_idx_arr(self):
        '''Get the index of nodes at the vertex of the cells
        of the cells. The result is a sorted flat array. The base node 
        position within the returned array defines the index of the cell. 
        '''
        vertex_idx_grid = self.vertex_idx_grid
        return sort(vertex_idx_grid.flatten())

    vertex_x_grid = Property
    def _get_vertex_x_grid(self):
        return array([ x_grid[ self.vertex_slices ] for x_grid in self.point_x_grid ])

    vertex_X_grid = Property
    def _get_vertex_X_grid(self):
        return array([ X_grid[ self.vertex_slices ] for X_grid in self.point_X_grid ])

    vertex_x_arr = Property
    def _get_vertex_x_arr(self):
        return c_[ tuple([ x.flatten() for x in self.vertex_x_grid ]) ]

    vertex_X_arr = Property
    def _get_vertex_X_arr(self):
        return c_[ tuple([ X.flatten() for X in self.vertex_X_grid ]) ]

    #----------------------------------------------------------------------------
    # Cell manipulations
    #-----------------------------------------------------------------------------
    base_nodes = Property
    def _get_base_nodes(self):
        '''Get the index of nodes that are the bottom left front vertexs
        of the cells. The result is a sorted flat array. The base node 
        position within the returned array defines the index of the cell. 
        '''
        vertex_idx_grid = self.vertex_idx_grid
        cutoff_last = [ slice(0, -1) for i in range(self.n_dims) ]
        base_node_grid = vertex_idx_grid[ cutoff_last ]
        return sort(base_node_grid.flatten())

    cell_node_map = Property(depends_on = 'shape,grid_cell_spec.+')
    @cached_property
    def _get_cell_node_map(self):
        '''
        Construct an array with the mapping between elements and nodes. 
        Returns the dof for [ cell_idx, node, dim ]
        '''
        idx_cell = self.idx_cell
        node_map = idx_cell.flatten()[ self.grid_cell.node_map ]
        base_nodes = self.base_nodes

        # Use broadcasting to construct the node map for all elements
        #
        cell_node_map = base_nodes[:, None] + node_map[None, :]
        return cell_node_map

    cell_grid_node_map = Property(depends_on = 'shape,grid_cell_spec.+')
    @cached_property
    def _get_cell_grid_node_map(self):
        '''
        Return the dof for [ cell_x, cell_y, node, dim ]
        where 
        - cell_x - is the cell index in the first dimension
        - cell_y - is the cell index in the second dimension
        - node - is the node index within the cell
        - dim - is the index of the dof within the node
        '''
        new_shape = tuple(self.shape) + self.cell_node_map.shape[1:]
        return self.cell_node_map.reshape(new_shape)

    def get_cell_point_x_arr(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        '''
        iexp = index_exp[ self.cell_node_map[ cell_idx ] ]
        return self.point_x_arr[ iexp ]

    def get_cell_point_X_arr(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        '''
        iexp = index_exp[ self.cell_node_map[ cell_idx ] ]
        return self.point_X_arr[ iexp ]

    #-----------------------------------------------------------------------------
    # @todo - candidate for deletion - the slicing operator [] is doing this more generally
    #-----------------------------------------------------------------------------
    boundary_slices = Property(depends_on = 'grid_cell_spec.+')
    @cached_property
    def _get_boundary_slices(self):
        '''Get the slices to get the boundary nodes.
        '''
        # slices must correspond to the dimensions
        slices = []
        for i in range(self.n_dims):
            s_low = [ slice(None) for j in range(self.n_dims) ]
            s_low[i] = 0
            s_high = [ slice(None) for j in range(self.n_dims) ]
            s_high[i] = -1
            slices.append(s_low)
            slices.append(s_high)
        return slices

    #--------------------------------------------------------------------------
    # Wrappers exporting the grid date to mayavi pipelines
    #--------------------------------------------------------------------------\

    def get_cell_mvpoints(self, cell_idx):
        '''Return the node coordinates included in the cell cell_idx. 
        In case that the grid is in reduced dimensions - blow it up with zeros.
        '''
        points = self.get_cell_point_X_arr(cell_idx)

        # augment the points to be 3D
        if self.n_dims < 3:
            mvpoints = zeros((points.shape[ 0 ], 3), dtype = 'float_')
            mvpoints[ :, :self.n_dims ] = points
            return mvpoints
        else:
            return points

    def _get_mvpoints_grid_shape(self):
        '''Shape of point grid in 3D.
        The information is needed by the mayavi pipeline to use the
        StructuredGrid source - tvtk class.
        '''
        shape = self._get_point_grid_shape()
        return tuple(list(shape) + [1 for n in range(3 - len(shape)) ])

    def _get_mvpoints(self, swap = True):
        '''Get the points in with deepest index along the x axes.
        This format is required when putting the point data to the 
        vtk structured grid.
        '''
        point_X_grid = self.point_X_grid
        if swap == True:
            point_X_grid = point_X_grid.swapaxes(1, self.n_dims)

        point_X_arr = c_[ tuple([ X.flatten() for X in point_X_grid ]) ]

        # augment the points to be 3D
        if self.n_dims < 3:
            mv_points = zeros((point_X_arr.shape[ 0 ], 3), dtype = 'float_')
            mv_points[ :, :self.n_dims ] = point_X_arr
            return mv_points
        else:
            return point_X_arr

    #-----------------------------------------------------------------
    # Visualization-related methods
    #-----------------------------------------------------------------

    mvp_point_grid = Trait(MVStructuredGrid)
    def _mvp_point_grid_default(self):
        return MVStructuredGrid(name = 'Point grid',
                                  dims = self._get_mvpoints_grid_shape,
                                  points = self._get_mvpoints)

    refresh_button = Button('Draw')
    @on_trait_change('refresh_button')
    def redraw(self):
        '''Redraw the point grid.
        '''
        self.mvp_point_grid.redraw()

    cell_array = Button('Browse cell array')
    def _cell_array_fired(self):
        cell_array = self.cell_node_map
        self.show_array = CellArray(data = cell_array,
                                     cell_view = CellView(cell_grid = self))
        self.show_array.configure_traits(kind = 'live')

    #------------------------------------------------------------------
    # UI - related methods
    #------------------------------------------------------------------
    traits_view = View(Item('grid_cell_spec'),
                       Item('shape@'),
                       Item('coord_min'),
                       Item('coord_max'),
                       Item('refresh_button'),
                       Item('cell_array'),
                       resizable = True,
                       scrollable = True,
                       height = 0.5,
                       width = 0.5)