Пример #1
0
class TurbulentSuspensionAndBleachingModel(OrientedRasterCTS):
    """
    Example
    -------
    >>> from six import StringIO
    >>> p = StringIO('''
    ... model_grid_row__count: number of rows in grid
    ... 4
    ... model_grid_column__count: number of columns in grid
    ... 4
    ... plot_interval: interval for plotting to display, s
    ... 2.0
    ... model__run_time: duration of model run, s
    ... 1.0
    ... model__report_interval: time interval for reporting progress, real-time seconds
    ... 1.0e6
    ... surface_bleaching_time_scale: time scale for OSL bleaching, s
    ... 2.42
    ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
    ... 2.0
    ... ''')
    >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
    >>> tsbm.node_state
    array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> tsbm.grid.at_node['osl']
    array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,
            0.,  0.,  0.])
    >>> tsbm.n_xn
    array([0, 1, 1, 0, 0, 1, 1, 0])
    >>> tsbm.fluid_surface_height
    3.5
    """
    def __init__(self, input_stream):
        """
        Reads in parameters and initializes the model.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 4
        ... model_grid_column__count: number of columns in grid
        ... 4
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 2.0
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.node_state
        array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
        >>> tsbm.grid.at_node['osl']
        array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,
                0.,  0.,  0.])
        >>> tsbm.n_xn
        array([0, 1, 1, 0, 0, 1, 1, 0])
        >>> tsbm.fluid_surface_height
        3.5
        """
        # Get a source for input parameters.
        params = ModelParameterDictionary(input_stream)

        # Read user-defined parameters
        nr = params.read_int('model_grid_row__count'
                             )  # number of rows (CSDMS Standard Name [CSN])
        nc = params.read_int(
            'model_grid_column__count')  # number of cols (CSN)
        self.plot_interval = params.read_float(
            'plot_interval')  # interval for plotting output, s
        self.run_duration = params.read_float(
            'model__run_time')  # duration of run, sec (CSN)
        self.report_interval = params.read_float(
            'model__report_interval')  # report interval, in real-time seconds
        self.bleach_T0 = params.read_float(
            'surface_bleaching_time_scale'
        )  # time scale for bleaching at fluid surface, s
        self.zstar = params.read_float(
            'light_attenuation_length'
        )  # length scale for light attenuation in fluid, CELLS

        # Derived parameters
        self.fluid_surface_height = nr - 0.5

        # Calculate when we next want to report progress.
        self.next_report = time.time() + self.report_interval

        # Create grid
        mg = RasterModelGrid(nr, nc, 1.0)

        # Make the boundaries be walls
        mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

        # Set up the states and pair transitions.
        ns_dict = {0: 'fluid', 1: 'particle'}
        xn_list = self.setup_transition_list()

        # Create the node-state array and attach it to the grid
        node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)

        # For visual display purposes, set all boundary nodes to fluid
        node_state_grid[mg.closed_boundary_nodes] = 0

        # Initialize the node-state array: here, the initial condition is a pile of
        # resting grains at the bottom of a container.
        bottom_rows = where(mg.node_y < 0.4 * nr)[0]
        node_state_grid[bottom_rows] = 1

        # Create a data array for bleaching.
        # Here, osl=optically stimulated luminescence, normalized to the original
        # signal (hence, initially all unity). Over time this signal may get
        # bleached out due to exposure to light.
        self.osl = mg.add_zeros('node', 'osl')
        self.osl[bottom_rows] = 1.0
        self.osl_display = mg.add_zeros('node', 'osl_display')
        self.osl_display[bottom_rows] = 1.0

        # We'll need an array to track the last time any given node was
        # updated, so we can figure out the duration of light exposure between
        # update events
        self.last_update_time = mg.add_zeros('node', 'last_update_time')

        # Call the  base class (RasterCTS) init method
        super(TurbulentSuspensionAndBleachingModel, \
              self).__init__(mg, ns_dict, xn_list, node_state_grid, prop_data=self.osl)

        # Set up plotting (if plotting desired)
        if self.plot_interval <= self.run_duration:
            self.initialize_plotting()

    def initialize_plotting(self):
        """
        Creates a CA plotter object, sets its colormap, and plots the initial
        model state.
        """
        # Set up some plotting information
        grain = '#5F594D'
        bleached_grain = '#CC0000'
        fluid = '#D0E4F2'
        clist = [fluid, bleached_grain, grain]
        my_cmap = matplotlib.colors.ListedColormap(clist)

        # Create a CAPlotter object for handling screen display
        self.ca_plotter = CAPlotter(self, cmap=my_cmap)

        # Plot the initial grid
        self.ca_plotter.update_plot()

        # Make a colormap for use in showing the bleaching of each grain
        clist = [(0.0, (1.0, 1.0, 1.0)), (0.49, (0.8, 0.8, 0.8)),
                 (1.0, (0.0, 0.0, 0.0))]
        self.cmap_for_osl = matplotlib.colors.LinearSegmentedColormap.from_list(
            'osl_cmap', clist)

    def setup_transition_list(self):
        """
        Creates and returns a list of Transition() objects to represent state
        transitions for a biased random walk, in which the rate of downward
        motion is greater than the rate in the other three directions.

        Parameters
        ----------
        (none)

        Returns
        -------
        xn_list : list of Transition objects
            List of objects that encode information about the link-state transitions.

        Notes
        -----
        State 0 represents fluid and state 1 represents a particle (such as a
        sediment grain, tea leaf, or dissolved heavy particle).

        The states and transitions are as follows:

        Pair state      Transition to       Process             Rate (cells/s)
        ==========      =============       =======             ==============
        0 (0-0)         (none)              -                   -
        1 (0-1)         2 (1-0)             left motion         10.0
        2 (1-0)         1 (0-1)             right motion        10.0
        3 (1-1)         (none)              -                   -
        4 (0-0)         (none)              -                   -
        5 (0-1)         2 (1-0)             down motion         10.55
        6 (1-0)         1 (0-1)             up motion            9.45
        7 (1-1)         (none)              -                   -

        """

        # Create an empty transition list
        xn_list = []

        # Append four transitions to the list.
        # Note that the arguments to the Transition() object constructor are:
        #  - Tuple representing starting pair state
        #    (left cell, right cell, orientation [0=horizontal])
        #  - Tuple representing new pair state
        #    (bottom cell, top cell, orientation [1=vertical])
        #  - Transition rate (cells per time step, in this case 1 sec)
        #  - Name for transition
        #  - Flag indicating that the transition involves an exchange of properties
        #  - Function to be called after each transition, to update a property
        #    (in this case, to simulate bleaching of the luminescence signal)
        xn_list.append(
            Transition((0, 1, 0), (1, 0, 0), 10., 'left motion', True,
                       self.update_bleaching))
        xn_list.append(
            Transition((1, 0, 0), (0, 1, 0), 10., 'right motion', True,
                       self.update_bleaching))
        xn_list.append(
            Transition((0, 1, 1), (1, 0, 1), 10.55, 'down motion', True,
                       self.update_bleaching))
        xn_list.append(
            Transition((1, 0, 1), (0, 1, 1), 9.45, 'up motion', True,
                       self.update_bleaching))

        return xn_list

    def bleach_grain(self, node, dt):
        """
        Updates the luminescence signal at node.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.bleach_grain(10, 1.0)
        >>> int(tsbm.prop_data[tsbm.propid[10]]*1000)
        858
        """
        depth = self.fluid_surface_height - self.grid.node_y[node]
        T_bleach = self.bleach_T0 * exp(depth / self.zstar)
        self.prop_data[self.propid[node]] *= exp(-dt / T_bleach)

    def update_bleaching(self, ca_unused, node1, node2, time_now):
        """
        Updates the luminescence signal at a pair of nodes that have just
        undergone a transition, if either or both nodes is a grain.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.update_bleaching(tsbm, 10, 13, 1.0)
        >>> int(tsbm.prop_data[tsbm.propid[10]]*1000)
        858
        >>> tsbm.prop_data[tsbm.propid[13]]
        0.0
        """
        if self.node_state[node1] == 1:
            dt = time_now - self.last_update_time[self.propid[node1]]
            self.bleach_grain(node1, dt)
            self.last_update_time[self.propid[node1]] = time_now
        if self.node_state[node2] == 1:
            dt = time_now - self.last_update_time[self.propid[node2]]
            self.bleach_grain(node2, dt)
            self.last_update_time[self.propid[node2]] = time_now

    def synchronize_bleaching(self, sync_time):
        """
        Brings all nodes up to the same time, sync_time, by applying bleaching
        up to this time, and updating last_update_time.

        Notes
        -----
        In a CellLab-CTS model, the "time" is usually different for each node:
        some will have only just recently undergone a transition and had their
        properties (in this case, OSL bleaching) updated, while others will
        have last been updated a long time ago, and some may never have had a
        transition. If we want to plot the properties at a consistent time, we
        need to bring all node properties (again, in this case, OSL) up to
        date. This method does so.
            We multiply elapsed time (between last update and "sync time") by
        the node state, because we only want to update the solid particles---
        because the state of a particle is 1 and fluid 0, this multiplication
        masks out the fluid nodes.
            We don't call bleach_grain(), because we want to take advantage of
        numpy array operations rather than calling a method for each node.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.synchronize_bleaching(1.0)
        >>> int(tsbm.osl[10]*100000)
        85897
        """
        dt = (sync_time - self.last_update_time[self.propid]) * self.node_state
        assert (amin(dt) >= 0.0), 'sync_time must be >= 0 everywhere'
        depth = self.fluid_surface_height - self.grid.node_y
        T_bleach = self.bleach_T0 * exp(depth / self.zstar)
        self.prop_data[self.propid] *= exp(-dt / T_bleach)
        self.last_update_time[self.propid] = sync_time * self.node_state

    def go(self):
        """
        Runs the model.
        """
        # RUN
        while self.current_time < self.run_duration:

            # Once in a while, print out simulation and real time to let the user
            # know that the sim is running ok
            current_real_time = time.time()
            if current_real_time >= self.next_report:
                print('Current sim time', self.current_time, '(',
                      100 * self.current_time / self.run_duration, '%)')
                self.next_report = current_real_time + self.report_interval

            # Run the model forward in time until the next output step
            self.run(self.current_time + self.plot_interval,
                     self.node_state,
                     plot_each_transition=False)
            self.current_time += self.plot_interval
            self.synchronize_bleaching(self.current_time)

            if self.plot_interval <= self.run_duration:

                # Plot the current grid
                self.ca_plotter.update_plot()

                # Display the OSL content of grains
                figure(3)
                clf()
                self.osl_display[:] = self.osl[self.propid] + self.node_state
                imshow_node_grid(self.grid,
                                 'osl_display',
                                 limits=(0.0, 2.0),
                                 cmap=self.cmap_for_osl)
                show()
                figure(1)

    def finalize(self):

        # FINALIZE

        # Plot
        self.ca_plotter.finalize()
Пример #2
0
def main():
    
    # INITIALIZE
    
    # User-defined parameters
    nr = 21
    nc = 21
    plot_interval = 0.5
    run_duration = 25.0
    report_interval = 5.0  # report interval, in real-time seconds
    
    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0, orientation='vertical', reorient_links=True)
    
    # Close the grid boundaries
    hmg.set_closed_nodes(hmg.open_boundary_nodes)
    
    # Set up the states and pair transitions.
    # Transition data here represent the disease status of a population.
    ns_dict = { 0 : 'fluid', 1 : 'grain' }
    xn_list = setup_transition_list()

    # Create data and initialize values. We start with the 3 middle columns full
    # of grains, and the others empty.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')
    middle = 0.25*(nc-1)*sqrt(3)
    is_middle_cols = logical_and(hmg.node_x<middle+1., hmg.node_x>middle-1.)
    node_state_grid[where(is_middle_cols)[0]] = 1
    
    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)
    
    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)
    
    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:
        
        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval
        
        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state, 
               plot_each_transition=False)
        current_time += plot_interval
        
        # Plot the current grid
        ca_plotter.update_plot()


    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #3
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 100  # number of rows in grid
    nc = 64  # number of columns in grid
    plot_interval = 0.5  # time interval for plotting, sec
    run_duration = 20.0  # duration of run, sec
    report_interval = 10.0  # report interval, in real-time seconds

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)

    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

    # Set up the states and pair transitions.
    ns_dict = {0: "fluid", 1: "particle"}
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid
    node_state_grid = mg.add_zeros("node", "node_state_map", dtype=int)

    # Initialize the node-state array: here, the initial condition is a pile of
    # resting grains at the bottom of a container.
    bottom_rows = where(mg.node_y < 0.1 * nr)[0]
    node_state_grid[bottom_rows] = 1

    # For visual display purposes, set all boundary nodes to fluid
    node_state_grid[mg.closed_boundary_nodes] = 0

    # Create the CA model
    ca = OrientedRasterCTS(mg, ns_dict, xn_list, node_state_grid)

    grain = "#5F594D"
    fluid = "#D0E4F2"
    clist = [fluid, grain]
    my_cmap = matplotlib.colors.ListedColormap(clist)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print(
                "Current sim time",
                current_time,
                "(",
                100 * current_time / run_duration,
                "%)",
            )
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval, ca.node_state, plot_each_transition=False)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

    # FINALIZE

    # Plot
    ca_plotter.finalize()

    # Calculate concentration profile
    c = zeros(nr)
    for r in range(nr):
        c[r] = mean(node_state_grid[r * nc : (r + 1) * nc])

    figure(2)
    plot(c, range(nr), "o")
    show()
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 41
    nc = 61
    g = 0.8
    f = 1.0
    plot_interval = 1.0
    run_duration = 200.0
    report_interval = 5.0  # report interval, in real-time seconds
    p_init = 0.4  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr,
                       nc,
                       1.0,
                       orientation='vertical',
                       reorient_links=True)

    # Close the grid boundaries
    #hmg.set_closed_nodes(hmg.open_boundary_nodes)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = {
        0: 'empty',
        1: 'moving up',
        2: 'moving right and up',
        3: 'moving right and down',
        4: 'moving down',
        5: 'moving left and down',
        6: 'moving left and up',
        7: 'rest',
        8: 'wall'
    }
    xn_list = setup_transition_list(g, f)

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if random.random() < p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time', current_time, '(',
                  100 * current_time / run_duration, '%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=plot_every_transition,
               plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

    # FINALIZE

    # Plot
    ca_plotter.finalize()
class TurbulentSuspensionAndBleachingModel(OrientedRasterCTS):
    """
    Example
    -------
    >>> from six import StringIO
    >>> p = StringIO('''
    ... model_grid_row__count: number of rows in grid
    ... 4
    ... model_grid_column__count: number of columns in grid
    ... 4
    ... plot_interval: interval for plotting to display, s
    ... 2.0
    ... model__run_time: duration of model run, s
    ... 1.0
    ... model__report_interval: time interval for reporting progress, real-time seconds
    ... 1.0e6
    ... surface_bleaching_time_scale: time scale for OSL bleaching, s
    ... 2.42
    ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
    ... 2.0
    ... ''')
    >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
    >>> tsbm.node_state
    array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> tsbm.grid.at_node['osl']
    array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,
            0.,  0.,  0.])
    >>> tsbm.n_xn
    array([0, 1, 1, 0, 0, 1, 1, 0])
    >>> tsbm.fluid_surface_height
    3.5
    """

    def __init__(self, input_stream):
        """
        Reads in parameters and initializes the model.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 4
        ... model_grid_column__count: number of columns in grid
        ... 4
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 2.0
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.node_state
        array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
        >>> tsbm.grid.at_node['osl']
        array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,
                0.,  0.,  0.])
        >>> tsbm.n_xn
        array([0, 1, 1, 0, 0, 1, 1, 0])
        >>> tsbm.fluid_surface_height
        3.5
        """
        # Get a source for input parameters.
        params = ModelParameterDictionary(input_stream)

        # Read user-defined parameters
        nr = params.read_int('model_grid_row__count')    # number of rows (CSDMS Standard Name [CSN])
        nc = params.read_int('model_grid_column__count') # number of cols (CSN)
        self.plot_interval = params.read_float('plot_interval')  # interval for plotting output, s
        self.run_duration = params.read_float('model__run_time')   # duration of run, sec (CSN)
        self.report_interval = params.read_float('model__report_interval')  # report interval, in real-time seconds
        self.bleach_T0 = params.read_float('surface_bleaching_time_scale')  # time scale for bleaching at fluid surface, s
        self.zstar = params.read_float('light_attenuation_length')  # length scale for light attenuation in fluid, CELLS

        # Derived parameters
        self.fluid_surface_height = nr-0.5

        # Calculate when we next want to report progress.
        self.next_report = time.time() + self.report_interval

        # Create grid
        mg = RasterModelGrid(nr, nc, 1.0)

        # Make the boundaries be walls
        mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

        # Set up the states and pair transitions.
        ns_dict = { 0 : 'fluid', 1 : 'particle' }
        xn_list = self.setup_transition_list()

        # Create the node-state array and attach it to the grid
        node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)

        # For visual display purposes, set all boundary nodes to fluid
        node_state_grid[mg.closed_boundary_nodes] = 0

        # Initialize the node-state array: here, the initial condition is a pile of
        # resting grains at the bottom of a container.
        bottom_rows = where(mg.node_y<0.4*nr)[0]
        node_state_grid[bottom_rows] = 1

        # Create a data array for bleaching.
        # Here, osl=optically stimulated luminescence, normalized to the original
        # signal (hence, initially all unity). Over time this signal may get
        # bleached out due to exposure to light.
        self.osl = mg.add_zeros('node', 'osl')
        self.osl[bottom_rows] = 1.0
        self.osl_display = mg.add_zeros('node', 'osl_display')
        self.osl_display[bottom_rows] = 1.0

        # We'll need an array to track the last time any given node was
        # updated, so we can figure out the duration of light exposure between
        # update events
        self.last_update_time = mg.add_zeros('node','last_update_time')

        # Call the  base class (RasterCTS) init method
        super(TurbulentSuspensionAndBleachingModel, \
              self).__init__(mg, ns_dict, xn_list, node_state_grid, prop_data=self.osl)

        # Set up plotting (if plotting desired)
        if self.plot_interval <= self.run_duration:
            self.initialize_plotting()


    def initialize_plotting(self):
        """
        Creates a CA plotter object, sets its colormap, and plots the initial
        model state.
        """
        # Set up some plotting information
        grain = '#5F594D'
        bleached_grain = '#CC0000'
        fluid = '#D0E4F2'
        clist = [fluid,bleached_grain,grain]
        my_cmap = matplotlib.colors.ListedColormap(clist)

        # Create a CAPlotter object for handling screen display
        self.ca_plotter = CAPlotter(self, cmap=my_cmap)

        # Plot the initial grid
        self.ca_plotter.update_plot()

        # Make a colormap for use in showing the bleaching of each grain
        clist = [(0.0, (1.0, 1.0, 1.0)), (0.49, (0.8, 0.8, 0.8)), (1.0, (0.0, 0.0, 0.0))]
        self.cmap_for_osl = matplotlib.colors.LinearSegmentedColormap.from_list('osl_cmap', clist)


    def setup_transition_list(self):
        """
        Creates and returns a list of Transition() objects to represent state
        transitions for a biased random walk, in which the rate of downward
        motion is greater than the rate in the other three directions.

        Parameters
        ----------
        (none)

        Returns
        -------
        xn_list : list of Transition objects
            List of objects that encode information about the link-state transitions.

        Notes
        -----
        State 0 represents fluid and state 1 represents a particle (such as a
        sediment grain, tea leaf, or dissolved heavy particle).

        The states and transitions are as follows:

        Pair state      Transition to       Process             Rate (cells/s)
        ==========      =============       =======             ==============
        0 (0-0)         (none)              -                   -
        1 (0-1)         2 (1-0)             left motion         10.0
        2 (1-0)         1 (0-1)             right motion        10.0
        3 (1-1)         (none)              -                   -
        4 (0-0)         (none)              -                   -
        5 (0-1)         2 (1-0)             down motion         10.55
        6 (1-0)         1 (0-1)             up motion            9.45
        7 (1-1)         (none)              -                   -

        """

        # Create an empty transition list
        xn_list = []

        # Append four transitions to the list.
        # Note that the arguments to the Transition() object constructor are:
        #  - Tuple representing starting pair state
        #    (left cell, right cell, orientation [0=horizontal])
        #  - Tuple representing new pair state
        #    (bottom cell, top cell, orientation [1=vertical])
        #  - Transition rate (cells per time step, in this case 1 sec)
        #  - Name for transition
        #  - Flag indicating that the transition involves an exchange of properties
        #  - Function to be called after each transition, to update a property
        #    (in this case, to simulate bleaching of the luminescence signal)
        xn_list.append( Transition((0,1,0), (1,0,0), 10., 'left motion', True, self.update_bleaching) )
        xn_list.append( Transition((1,0,0), (0,1,0), 10., 'right motion', True, self.update_bleaching) )
        xn_list.append( Transition((0,1,1), (1,0,1), 10.55, 'down motion', True, self.update_bleaching) )
        xn_list.append( Transition((1,0,1), (0,1,1), 9.45, 'up motion', True, self.update_bleaching) )

        return xn_list


    def bleach_grain(self, node, dt):
        """
        Updates the luminescence signal at node.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.bleach_grain(10, 1.0)
        >>> int(tsbm.prop_data[tsbm.propid[10]]*1000)
        858
        """
        depth = self.fluid_surface_height - self.grid.node_y[node]
        T_bleach = self.bleach_T0*exp( depth/self.zstar)
        self.prop_data[self.propid[node]] *= exp( -dt/T_bleach )


    def update_bleaching(self, ca_unused, node1, node2, time_now):
        """
        Updates the luminescence signal at a pair of nodes that have just
        undergone a transition, if either or both nodes is a grain.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.update_bleaching(tsbm, 10, 13, 1.0)
        >>> int(tsbm.prop_data[tsbm.propid[10]]*1000)
        858
        >>> tsbm.prop_data[tsbm.propid[13]]
        0.0
        """
        if self.node_state[node1]==1:
            dt = time_now - self.last_update_time[self.propid[node1]]
            self.bleach_grain(node1, dt)
            self.last_update_time[self.propid[node1]] = time_now
        if self.node_state[node2]==1:
            dt = time_now - self.last_update_time[self.propid[node2]]
            self.bleach_grain(node2, dt)
            self.last_update_time[self.propid[node2]] = time_now


    def synchronize_bleaching(self, sync_time):
        """
        Brings all nodes up to the same time, sync_time, by applying bleaching
        up to this time, and updating last_update_time.

        Notes
        -----
        In a CellLab-CTS model, the "time" is usually different for each node:
        some will have only just recently undergone a transition and had their
        properties (in this case, OSL bleaching) updated, while others will
        have last been updated a long time ago, and some may never have had a
        transition. If we want to plot the properties at a consistent time, we
        need to bring all node properties (again, in this case, OSL) up to
        date. This method does so.
            We multiply elapsed time (between last update and "sync time") by
        the node state, because we only want to update the solid particles---
        because the state of a particle is 1 and fluid 0, this multiplication
        masks out the fluid nodes.
            We don't call bleach_grain(), because we want to take advantage of
        numpy array operations rather than calling a method for each node.

        Example
        -------
        >>> from six import StringIO
        >>> p = StringIO('''
        ... model_grid_row__count: number of rows in grid
        ... 10
        ... model_grid_column__count: number of columns in grid
        ... 3
        ... plot_interval: interval for plotting to display, s
        ... 2.0
        ... model__run_time: duration of model run, s
        ... 1.0
        ... model__report_interval: time interval for reporting progress, real-time seconds
        ... 1.0e6
        ... surface_bleaching_time_scale: time scale for OSL bleaching, s
        ... 2.42
        ... light_attenuation_length: length scale for light attenuation, cells (1 cell = 1 mm)
        ... 6.5
        ... ''')
        >>> tsbm = TurbulentSuspensionAndBleachingModel(p)
        >>> tsbm.synchronize_bleaching(1.0)
        >>> int(tsbm.osl[10]*100000)
        85897
        """
        dt = (sync_time - self.last_update_time[self.propid])*self.node_state
        assert (amin(dt)>=0.0), 'sync_time must be >= 0 everywhere'
        depth = self.fluid_surface_height - self.grid.node_y
        T_bleach = self.bleach_T0*exp( depth/self.zstar)
        self.prop_data[self.propid] *= exp( -dt/T_bleach )
        self.last_update_time[self.propid] = sync_time*self.node_state


    def go(self):
        """
        Runs the model.
        """
        # RUN
        while self.current_time < self.run_duration:

            # Once in a while, print out simulation and real time to let the user
            # know that the sim is running ok
            current_real_time = time.time()
            if current_real_time >= self.next_report:
                print('Current sim time',self.current_time,'(',100*self.current_time/self.run_duration,'%)')
                self.next_report = current_real_time + self.report_interval

            # Run the model forward in time until the next output step
            self.run(self.current_time+self.plot_interval, self.node_state,
                   plot_each_transition=False)
            self.current_time += self.plot_interval
            self.synchronize_bleaching(self.current_time)

            if self.plot_interval <= self.run_duration:

                # Plot the current grid
                self.ca_plotter.update_plot()

                # Display the OSL content of grains
                figure(3)
                clf()
                self.osl_display[:] = self.osl[self.propid]+self.node_state
                imshow_node_grid(self.grid, 'osl_display', limits=(0.0, 2.0),
                                 cmap=self.cmap_for_osl)
                show()
                figure(1)


    def finalize(self):

        # FINALIZE

        # Plot
        self.ca_plotter.finalize()
Пример #6
0
def main():
    
    # INITIALIZE

    # User-defined parameters
    nr = 80
    nc = 80
    plot_interval = 2
    run_duration = 200
    report_interval = 5.0  # report interval, in real-time seconds
    
    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)
    
    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)
    
    # Set up the states and pair transitions.
    ns_dict = { 0 : 'fluid', 1 : 'particle' }
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid
    node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)
    
    # Initialize the node-state array
    middle_rows = where(bitwise_and(mg.node_y>0.45*nr, mg.node_y<0.55*nr))[0]
    node_state_grid[middle_rows] = 1    
    
    # Create the CA model
    ca = OrientedRasterCTS(mg, ns_dict, xn_list, node_state_grid)
    
    # Debug output if needed    
    if _DEBUG:
        n = ca.grid.number_of_nodes
        for r in range(ca.grid.number_of_node_rows):
            for c in range(ca.grid.number_of_node_columns):
                n -= 1
                print('{0:.0f}'.format(ca.node_state[n]), end=' ')
            print()

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)
    
    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:
        
        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval
        
        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state, 
               plot_each_transition=False) #, plotter=ca_plotter)
        current_time += plot_interval
        
        # Plot the current grid
        ca_plotter.update_plot()

        # for debugging        
        if _DEBUG:
            n = ca.grid.number_of_nodes
            for r in range(ca.grid.number_of_node_rows):
                for c in range(ca.grid.number_of_node_columns):
                    n -= 1
                    print('{0:.0f}'.format(ca.node_state[n]), end=' ')
                print()


    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #7
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 41
    nc = 61
    plot_interval = 1.0
    run_duration = 100.0
    report_interval = 5.0  # report interval, in real-time seconds
    p_init = 0.1  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr,
                       nc,
                       1.0,
                       orientation='vertical',
                       reorient_links=True)

    # Close the grid boundaries
    #hmg.set_closed_nodes(hmg.open_boundary_nodes)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = {
        0: 'empty',
        1: 'moving up',
        2: 'moving right and up',
        3: 'moving right and down',
        4: 'moving down',
        5: 'moving left and down',
        6: 'moving left and up',
        7: 'rest',
        8: 'wall'
    }
    xn_list = setup_transition_list()

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid', dtype=int)

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if random.random() < p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # Create an array to store the numbers of states at each plot interval
    nstates = zeros((9, int(run_duration / plot_interval)))
    k = 0

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time', current_time, '(',
                  100 * current_time / run_duration, '%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=plot_every_transition,
               plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

        # Record numbers in each state
        nstates[:, k] = bincount(node_state_grid)
        k += 1

    # FINALIZE

    # Plot
    ca_plotter.finalize()

    # Display the numbers of each state
    fig, ax = subplots()
    for i in range(1, 8):
        plot(arange(plot_interval, run_duration + plot_interval,
                    plot_interval),
             nstates[i, :],
             label=ns_dict[i])
    ax.legend()
    xlabel('Time')
    ylabel('Number of particles in state')
    title('Particle distribution by state')
    axis([0, run_duration, 0, 2 * nstates[7, 0]])
    show()
Пример #8
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 10
    nc = 10
    plot_interval = 0.25
    run_duration = 40.0
    report_interval = 5.0  # report interval, in real-time seconds

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

    # Set up the states and pair transitions.
    # Transition data here represent a body of fractured rock, with rock
    # represented by nodes with state 0, and saprolite (weathered rock)
    # represented by nodes with state 1. Node pairs (links) with 0-1 or 1-0
    # can undergo a transition to 1-1, representing chemical weathering of the
    # rock.
    ns_dict = { 0 : 'air', 1 : 'particle' }
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid
    node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)
    node_state_grid[where(mg.node_y>nr-3)[0]] = 1

        # Create the CA model
    ca = OrientedRasterCTS(mg, ns_dict, xn_list, node_state_grid)
    #ca = RasterCTS(mg, ns_dict, xn_list, node_state_grid)

    # Debug output if needed
    if _DEBUG:
        n = ca.grid.number_of_nodes
        for r in range(ca.grid.number_of_node_rows):
            for c in range(ca.grid.number_of_node_columns):
                n -= 1
                print('{0:.0f}'.format(ca.node_state[n]), end=' ')
            print()

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    updated = False
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=False) #, plotter=ca_plotter)
        current_time += plot_interval

        # Add a bunch of particles
        if current_time > run_duration/2. and not updated:
            print('updating...')
            node_state_grid[where(ca.grid.node_y>(nc/2.0))[0]] = 1
            ca.update_link_states_and_transitions(current_time)
            updated = True

        # Plot the current grid
        ca_plotter.update_plot()

        # for debugging
        if _DEBUG:
            n = ca.grid.number_of_nodes
            for r in range(ca.grid.number_of_node_rows):
                for c in range(ca.grid.number_of_node_columns):
                    n -= 1
                    print('{0:.0f}'.format(ca.node_state[n]), end=' ')
                print()


    # FINALIZE

    # Plot
    ca_plotter.finalize()
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 41
    nc = 61
    g = 0.05
    plot_interval = 1.0
    run_duration = 100.0
    report_interval = 5.0  # report interval, in real-time seconds
    p_init = 0.1  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0, orientation='vertical', reorient_links=True)

    # Close the grid boundaries
    #hmg.set_closed_nodes(hmg.open_boundary_nodes)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = { 0 : 'empty',
                1 : 'moving up',
                2 : 'moving right and up',
                3 : 'moving right and down',
                4 : 'moving down',
                5 : 'moving left and down',
                6 : 'moving left and up',
                7 : 'rest',
                8 : 'wall'}
    xn_list = setup_transition_list(g)

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if random.random()<p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=plot_every_transition, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()


    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #10
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 41
    nc = 61
    g = 0.8
    f = 1.0
    silo_y0 = 30.0
    silo_opening_half_width = 6
    plot_interval = 1.0
    run_duration = 80.0
    report_interval = 5.0  # report interval, in real-time seconds
    p_init = 0.4  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0, orientation='vertical', reorient_links=True)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = { 0 : 'empty',
                1 : 'moving up',
                2 : 'moving right and up',
                3 : 'moving right and down',
                4 : 'moving down',
                5 : 'moving left and down',
                6 : 'moving left and up',
                7 : 'rest',
                8 : 'wall'}
    xn_list = setup_transition_list(g, f)

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Place wall particles to form the base of the silo, initially closed
    tan30deg = numpy.tan(numpy.pi/6.)
    rampy1 = silo_y0-hmg.node_x*tan30deg
    rampy2 = silo_y0-((nc*0.866-1.)-hmg.node_x)*tan30deg
    rampy = numpy.maximum(rampy1, rampy2)
    (ramp_nodes, ) = numpy.where(numpy.logical_and(hmg.node_y>rampy-0.5, \
                                   hmg.node_y<rampy+0.5))
    node_state_grid[ramp_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if hmg.node_y[i]>rampy[i] and random.random()<p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN

    # Run with closed silo
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time '+str(current_time)+' ('+str(100*current_time/run_duration)+'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=plot_every_transition, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

    # Open the silo
    xmid = nc*0.866*0.5
    for i in range(hmg.number_of_nodes):
        if node_state_grid[i]==8 and hmg.node_x[i]>(xmid-silo_opening_half_width) \
           and hmg.node_x[i]<(xmid+silo_opening_half_width) \
           and hmg.node_y[i]>0:
               node_state_grid[i]=0

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # Re-run with open silo
    current_time = 0.0
    while current_time < 5*run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time '+str(current_time)+' ('+str(100*current_time/run_duration)+'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=plot_every_transition, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()


    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #11
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 200  # number of rows in grid
    nc = 200  # number of columns in grid
    plot_interval = 0.05  # time interval for plotting (unscaled)
    run_duration = 5.0  # duration of run (unscaled)
    report_interval = 10.0  # report interval, in real-time seconds
    frac_spacing = 10  # average fracture spacing, nodes
    outfilename = 'wx'  # name for netCDF files

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Counter for output files
    time_slice = 0

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)

    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

    # Set up the states and pair transitions.
    ns_dict = {0: 'rock', 1: 'saprolite'}
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid.
    # (Note use of numpy's uint8 data type. This saves memory AND allows us
    # to write output to a netCDF3 file; netCDF3 does not handle the default
    # 64-bit integer type)
    node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=np.uint8)

    node_state_grid[:] = make_frac_grid(frac_spacing, model_grid=mg)

    # Create the CA model
    ca = RasterCTS(mg, ns_dict, xn_list, node_state_grid)

    # Set up the color map
    rock_color = (0.8, 0.8, 0.8)
    sap_color = (0.4, 0.2, 0)
    clist = [rock_color, sap_color]
    my_cmap = matplotlib.colors.ListedColormap(clist)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)

    # Plot the initial grid
    ca_plotter.update_plot()

    # Output the initial grid to file
    write_netcdf(
        (outfilename + str(time_slice) + '.nc'),
        mg,
        #format='NETCDF3_64BIT',
        names='node_state_map')

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time', current_time, '(',
                  100 * current_time / run_duration, '%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=False)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

        # Output the current grid to a netCDF file
        time_slice += 1
        write_netcdf(
            (outfilename + str(time_slice) + '.nc'),
            mg,
            #format='NETCDF3_64BIT',
            names='node_state_map')

    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #12
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 80
    nc = 41
    plot_interval = 0.25
    run_duration = 5.0
    report_interval = 5.0  # report interval, in real-time seconds
    infection_rate = 8.0
    outfilename = 'sirmodel'+str(int(infection_rate))+'ir'

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    time_slice = 0

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0)

    # Set up the states and pair transitions.
    # Transition data here represent the disease status of a population.
    ns_dict = { 0 : 'susceptible', 1 : 'infectious', 2: 'recovered' }
    xn_list = setup_transition_list(infection_rate)

    # Create data and initialize values
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')
    wid = nc-1.0
    ht = (nr-1.0)*0.866
    is_middle_rows = logical_and(hmg.node_y>=0.4*ht, hmg.node_y<=0.5*ht)
    is_middle_cols = logical_and(hmg.node_x>=0.4*wid, hmg.node_x<=0.6*wid)
    middle_area = where(logical_and(is_middle_rows, is_middle_cols))[0]
    node_state_grid[middle_area] = 1
    node_state_grid[0] = 2  # to force full color range, set lower left to 'recovered'

    # Create the CA model
    ca = HexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Set up the color map
    import matplotlib
    susceptible_color = (0.5, 0.5, 0.5)  # gray
    infectious_color = (0.5, 0.0, 0.0)  # dark red
    recovered_color = (0.0, 0.0, 1.0)  # blue
    clist = [susceptible_color, infectious_color, recovered_color]
    my_cmap = matplotlib.colors.ListedColormap(clist)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)

    # Plot the initial grid
    ca_plotter.update_plot()
    pylab.axis('off')
    savename = outfilename+'0'
    pylab.savefig(savename+'.pdf', format='pdf')

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=False) #True, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()
        pylab.axis('off')
        time_slice += 1
        savename = outfilename+str(time_slice)
        pylab.savefig(savename+'.pdf', format='pdf')

    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #13
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 52
    nc = 120
    plot_interval = 1.0
    run_duration = 100.0
    report_interval = 5.0  # report interval, in real-time seconds
    p_init = 0.1  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0, orientation='vertical', reorient_links=True)

    # Close the grid boundaries
    #hmg.set_closed_nodes(hmg.open_boundary_nodes)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = { 0 : 'empty',
                1 : 'moving up',
                2 : 'moving right and up',
                3 : 'moving right and down',
                4 : 'moving down',
                5 : 'moving left and down',
                6 : 'moving left and up',
                7 : 'rest',
                8 : 'wall'}
    xn_list = setup_transition_list()

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid', dtype=int)

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if random.random()<p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Set up a color map for plotting
    import matplotlib
    clist = [ (1.0, 1.0, 1.0),   # empty = white
              (1.0, 0.0, 0.0),   # up = red
              (1.0, 1.0, 0.0),   # right-up = yellow
              (0.0, 1.0, 0.0),   # down-up = green
              (0.0, 1.0, 1.0),   # down = cyan
              (0.0, 0.0, 1.0),   # left-down = blue
              (1.0, 0.0, 1.0),   # left-up = magenta
              (0.5, 0.5, 0.5),   # resting = gray
              (0.0, 0.0, 0.0) ]   # wall = black
    my_cmap = matplotlib.colors.ListedColormap(clist)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)

    # Plot the initial grid
    ca_plotter.update_plot()

    # Create an array to store the numbers of states at each plot interval
    nstates = zeros((9, int(run_duration/plot_interval)))
    k = 0

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state,
               plot_each_transition=plot_every_transition, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()
        axis('off')

        # Record numbers in each state
        nstates[:,k] = bincount(node_state_grid)
        k += 1

    # FINALIZE

    # Plot
    ca_plotter.finalize()

    # Display the numbers of each state
    fig, ax = subplots()
    for i in range(1, 8):
        plot(arange(plot_interval, run_duration+plot_interval, plot_interval), nstates[i,:], label=ns_dict[i], color=clist[i])
    ax.legend()
    xlabel('Time')
    ylabel('Number of particles in state')
    title('Particle distribution by state')
    axis([0, run_duration, 0, 2*nstates[7,0]])
    show()
Пример #14
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 41
    nc = 61
    g = 1.0
    f = 0.7
    silo_y0 = 30.0
    silo_opening_half_width = 6
    plot_interval = 10.0
    run_duration = 240.0
    report_interval = 300.0  # report interval, in real-time seconds
    p_init = 0.4  # probability that a cell is occupied at start
    plot_every_transition = False

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create a grid
    hmg = HexModelGrid(nr,
                       nc,
                       1.0,
                       orientation='vertical',
                       shape='rect',
                       reorient_links=True)

    # Set up the states and pair transitions.
    # Transition data here represent particles moving on a lattice: one state
    # per direction (for 6 directions), plus an empty state, a stationary
    # state, and a wall state.
    ns_dict = {
        0: 'empty',
        1: 'moving up',
        2: 'moving right and up',
        3: 'moving right and down',
        4: 'moving down',
        5: 'moving left and down',
        6: 'moving left and up',
        7: 'rest',
        8: 'wall'
    }
    xn_list = setup_transition_list(g, f)

    # Create data and initialize values.
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')

    # Make the grid boundary all wall particles
    node_state_grid[hmg.boundary_nodes] = 8

    # Place wall particles to form the base of the silo, initially closed
    tan30deg = numpy.tan(numpy.pi / 6.)
    rampy1 = silo_y0 - hmg.node_x * tan30deg
    rampy2 = silo_y0 - ((nc * 0.866 - 1.) - hmg.node_x) * tan30deg
    rampy = numpy.maximum(rampy1, rampy2)
    (ramp_nodes, ) = numpy.where(numpy.logical_and(hmg.node_y>rampy-0.5, \
                                   hmg.node_y<rampy+0.5))
    node_state_grid[ramp_nodes] = 8

    # Seed the grid interior with randomly oriented particles
    for i in hmg.core_nodes:
        if hmg.node_y[i] > rampy[i] and random.random() < p_init:
            node_state_grid[i] = random.randint(1, 7)

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    import matplotlib
    rock = (0.0, 0.0, 0.0)  #'#5F594D'
    sed = (0.6, 0.6, 0.6)  #'#A4874B'
    #sky = '#CBD5E1'
    #sky = '#85A5CC'
    sky = (1.0, 1.0, 1.0)  #'#D0E4F2'
    mob = (0.3, 0.3, 0.3)  #'#D98859'
    #mob = '#DB764F'
    #mob = '#FFFF00'
    #sed = '#CAAE98'
    #clist = [(0.5, 0.9, 0.9),mob, mob, mob, mob, mob, mob,'#CD6839',(0.3,0.3,0.3)]
    clist = [sky, mob, mob, mob, mob, mob, mob, sed, rock]
    my_cmap = matplotlib.colors.ListedColormap(clist)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)
    k = 0

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN

    # Run with closed silo
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print 'Current sim time', current_time, '(', 100 * current_time / run_duration, '%)'
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=plot_every_transition,
               plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

    # Open the silo
    xmid = nc * 0.866 * 0.5
    for i in range(hmg.number_of_nodes):
        if node_state_grid[i]==8 and hmg.node_x[i]>(xmid-silo_opening_half_width) \
           and hmg.node_x[i]<(xmid+silo_opening_half_width) \
           and hmg.node_y[i]>0 and hmg.node_y[i]<38.0:
            node_state_grid[i] = 0

    # Create the CA model
    ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # Re-run with open silo
    savefig('silo' + str(k) + '.png')
    k += 1
    current_time = 0.0
    while current_time < 5 * run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print 'Current sim time', current_time, '(', 100 * current_time / run_duration, '%)'
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=plot_every_transition,
               plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()
        savefig('silo' + str(k) + '.png')
        k += 1

    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #15
0
def main():
    
    # INITIALIZE
    
    # User-defined parameters
    nr = 80
    nc = 41
    plot_interval = 0.25
    run_duration = 5.0
    report_interval = 5.0  # report interval, in real-time seconds
    infection_rate = 3.0
    outfilename = 'sirmodel'+str(int(infection_rate))+'ir'
    
    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval
    
    time_slice = 0

    # Create a grid
    hmg = HexModelGrid(nr, nc, 1.0)
    
    # Set up the states and pair transitions.
    # Transition data here represent the disease status of a population.
    ns_dict = { 0 : 'susceptible', 1 : 'infectious', 2: 'recovered' }
    xn_list = setup_transition_list(infection_rate)

    # Create data and initialize values
    node_state_grid = hmg.add_zeros('node', 'node_state_grid')
    wid = nc-1.0
    ht = (nr-1.0)*0.866
    is_middle_rows = logical_and(hmg.node_y>=0.4*ht, hmg.node_y<=0.5*ht)
    is_middle_cols = logical_and(hmg.node_x>=0.4*wid, hmg.node_x<=0.6*wid)
    middle_area = where(logical_and(is_middle_rows, is_middle_cols))[0]
    node_state_grid[middle_area] = 1
    node_state_grid[0] = 2  # to force full color range, set lower left to 'recovered'
    
    # Create the CA model
    ca = HexCTS(hmg, ns_dict, xn_list, node_state_grid)
    
    # Set up the color map
    import matplotlib
    susceptible_color = (0.5, 0.5, 0.5)  # gray
    infectious_color = (0.05, 0.0, 0.0)  # dark red
    recovered_color = (0.95, 0.95, 1.0)  # white w/ faint blue
    clist = [susceptible_color, infectious_color, recovered_color]
    my_cmap = matplotlib.colors.ListedColormap(clist)
    
    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)
    
    # Plot the initial grid
    ca_plotter.update_plot()
    pylab.axis('off')
    savename = outfilename+'0'
    pylab.savefig(savename+'.pdf', format='pdf')

    # RUN
    current_time = 0.0
    while current_time < run_duration:
        
        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time',current_time,'(',100*current_time/run_duration,'%)')
            next_report = current_real_time + report_interval
        
        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state, 
               plot_each_transition=False) #True, plotter=ca_plotter)
        current_time += plot_interval
        
        # Plot the current grid
        ca_plotter.update_plot()
        pylab.axis('off')
        time_slice += 1
        savename = outfilename+str(time_slice)
        pylab.savefig(savename+'.pdf', format='pdf')

    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #16
0
def main():
    
    # INITIALIZE

    # User-defined parameters
    nr = 200  # number of rows in grid
    nc = 200  # number of columns in grid
    plot_interval = 0.05   # time interval for plotting (unscaled)
    run_duration = 5.0   # duration of run (unscaled)
    report_interval = 10.0  # report interval, in real-time seconds
    frac_spacing = 10  # average fracture spacing, nodes
    outfilename = 'wx' # name for netCDF files
    
    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval
    
    # Counter for output files
    time_slice = 0

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)
    
    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)
    
    # Set up the states and pair transitions.
    ns_dict = { 0 : 'rock', 1 : 'saprolite' }
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid.
    # (Note use of numpy's uint8 data type. This saves memory AND allows us
    # to write output to a netCDF3 file; netCDF3 does not handle the default
    # 64-bit integer type)
    node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=np.uint8)
    
    node_state_grid[:] = make_frac_grid(frac_spacing, model_grid=mg)    
    
    # Create the CA model
    ca = RasterCTS(mg, ns_dict, xn_list, node_state_grid)

    # Set up the color map
    rock_color = (0.8, 0.8, 0.8)
    sap_color = (0.4, 0.2, 0)
    clist = [rock_color, sap_color]
    my_cmap = matplotlib.colors.ListedColormap(clist)
    
    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca, cmap=my_cmap)
    
    # Plot the initial grid
    ca_plotter.update_plot()
    
    # Output the initial grid to file
    write_netcdf((outfilename+str(time_slice)+'.nc'), mg, 
                 #format='NETCDF3_64BIT',
                 names='node_state_map')

    # RUN
    current_time = 0.0
    while current_time < run_duration:
        
        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time', current_time, '(',
                  100 * current_time/run_duration, '%)')
            next_report = current_real_time + report_interval
        
        # Run the model forward in time until the next output step
        ca.run(current_time+plot_interval, ca.node_state, 
               plot_each_transition=False)
        current_time += plot_interval
        
        # Plot the current grid
        ca_plotter.update_plot()
        
        # Output the current grid to a netCDF file
        time_slice += 1
        write_netcdf((outfilename+str(time_slice)+'.nc'), mg, 
                     #format='NETCDF3_64BIT',
                     names='node_state_map')        
        

    # FINALIZE

    # Plot
    ca_plotter.finalize()
Пример #17
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 5  # number of rows in grid
    nc = 5  # number of columns in grid
    plot_interval = 10.0  # time interval for plotting, sec
    run_duration = 10.0  # duration of run, sec
    report_interval = 10.0  # report interval, in real-time seconds

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)

    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

    # Set up the states and pair transitions.
    ns_dict = {0: "black", 1: "white"}
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid
    node_state_grid = mg.add_zeros("node", "node_state_map", dtype=int)

    # For visual display purposes, set all boundary nodes to fluid
    node_state_grid[mg.closed_boundary_nodes] = 0

    # Create the CA model
    ca = RasterCTS(mg, ns_dict, xn_list, node_state_grid)

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print("Current sim time", current_time, "(", 100 * current_time / run_duration, "%)")
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval, ca.node_state, plot_each_transition=True, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

    # FINALIZE

    # Plot
    ca_plotter.finalize()

    print("ok, here are the keys")
    print(ca.__dict__.keys())
Пример #18
0
def main():

    # INITIALIZE

    # User-defined parameters
    nr = 80
    nc = 80
    plot_interval = 2
    run_duration = 200
    report_interval = 5.0  # report interval, in real-time seconds

    # Remember the clock time, and calculate when we next want to report
    # progress.
    current_real_time = time.time()
    next_report = current_real_time + report_interval

    # Create grid
    mg = RasterModelGrid(nr, nc, 1.0)

    # Make the boundaries be walls
    mg.set_closed_boundaries_at_grid_edges(True, True, True, True)

    # Set up the states and pair transitions.
    ns_dict = {0: 'fluid', 1: 'particle'}
    xn_list = setup_transition_list()

    # Create the node-state array and attach it to the grid
    node_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)

    # Initialize the node-state array
    middle_rows = where(
        bitwise_and(mg.node_y > 0.45 * nr, mg.node_y < 0.55 * nr))[0]
    node_state_grid[middle_rows] = 1

    # Create the CA model
    ca = OrientedRasterCTS(mg, ns_dict, xn_list, node_state_grid)

    # Debug output if needed
    if _DEBUG:
        n = ca.grid.number_of_nodes
        for r in range(ca.grid.number_of_node_rows):
            for c in range(ca.grid.number_of_node_columns):
                n -= 1
                print('{0:.0f}'.format(ca.node_state[n]), end=' ')
            print()

    # Create a CAPlotter object for handling screen display
    ca_plotter = CAPlotter(ca)

    # Plot the initial grid
    ca_plotter.update_plot()

    # RUN
    current_time = 0.0
    while current_time < run_duration:

        # Once in a while, print out simulation and real time to let the user
        # know that the sim is running ok
        current_real_time = time.time()
        if current_real_time >= next_report:
            print('Current sim time', current_time, '(',
                  100 * current_time / run_duration, '%)')
            next_report = current_real_time + report_interval

        # Run the model forward in time until the next output step
        ca.run(current_time + plot_interval,
               ca.node_state,
               plot_each_transition=False)  #, plotter=ca_plotter)
        current_time += plot_interval

        # Plot the current grid
        ca_plotter.update_plot()

        # for debugging
        if _DEBUG:
            n = ca.grid.number_of_nodes
            for r in range(ca.grid.number_of_node_rows):
                for c in range(ca.grid.number_of_node_columns):
                    n -= 1
                    print('{0:.0f}'.format(ca.node_state[n]), end=' ')
                print()

    # FINALIZE

    # Plot
    ca_plotter.finalize()