def initializer(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, **kwds) self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state'])
def initializer(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, dissolution_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, opt_track_grains, prop_data, prop_reset_value, callback_fn, closed_boundaries, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.dissolution_rate = dissolution_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) self.opt_track_grains = opt_track_grains self.callback_fn = callback_fn if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation="vertical", grid_shape="rect", show_plots=show_plots, cts_type="oriented_hex", run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, prop_data=prop_data, prop_reset_value=prop_reset_value, closed_boundaries=closed_boundaries, **kwds) # Set some things related to property-swapping and/or callback fn # if the user wants to track grain motion. # if opt_track_grains: # propid = self.ca.propid # else: # propid = None self.uplifter = LatticeUplifter( self.grid, self.grid.at_node["node_state"], propid=self.ca.propid, prop_data=self.ca.prop_data, prop_reset_value=self.ca.prop_reset_value, ) self.initialize_timing(output_interval, plot_interval, uplift_interval, report_interval)
def initialize(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval, **kwds) self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state'])
def test_shift_link_and_transition_data_upward(): """Test the LatticeUplifter method that uplifts link data and tr'ns.""" mg = HexModelGrid((4, 3), spacing=1.0, orientation="vertical", node_layout="rect") nsd = {0: "yes", 1: "no"} xnlist = [] xnlist.append(Transition((0, 0, 0), (1, 1, 0), 1.0, "frogging")) xnlist.append(Transition((0, 0, 1), (1, 1, 1), 1.0, "frogging")) xnlist.append(Transition((0, 0, 2), (1, 1, 2), 1.0, "frogging")) nsg = mg.add_zeros("node_state_grid", at="node") ohcts = OrientedHexCTS(mg, nsd, xnlist, nsg) assert_array_equal(ohcts.link_state[mg.active_links], [0, 4, 8, 8, 4, 0, 4, 8, 8, 4, 0]) assert_array_equal(ohcts.next_trn_id[mg.active_links], [0, 1, 2, 2, 1, 0, 1, 2, 2, 1, 0]) assert_array_equal( np.round(ohcts.next_update[mg.active_links], 2), [0.8, 1.26, 0.92, 0.79, 0.55, 1.04, 0.58, 2.22, 3.31, 0.48, 1.57], ) pq = ohcts.priority_queue assert_equal(pq._queue[0][2], 19) # link for first event = 19, not shifted assert_equal(round(pq._queue[0][0], 2), 0.48) # trn scheduled for t = 0.48 assert_equal(pq._queue[2][2], 14) # this event scheduled for link 15... assert_equal(round(pq._queue[2][0], 2), 0.58) # ...trn sched for t = 0.58 lu = LatticeUplifter(grid=mg) lu.shift_link_and_transition_data_upward(ohcts, 0.0) # note new events lowest 5 links assert_array_equal( np.round(ohcts.next_update[mg.active_links], 2), [0.75, 0.84, 2.6, 0.07, 0.09, 0.8, 0.02, 1.79, 1.51, 2.04, 3.85], ) assert_equal(pq._queue[0][2], 14) # new soonest event assert_equal(pq._queue[9][2], 13) # was previously 7, now shifted up... assert_equal(round(pq._queue[9][0], 2), 0.8) # ...still sched for t = 0.80
def test_shift_link_and_transition_data_upward(): """Test the LatticeUplifter method that uplifts link data and tr'ns.""" mg = HexModelGrid(4, 3, 1.0, orientation="vertical", shape="rect") nsd = {0: "yes", 1: "no"} xnlist = [] xnlist.append(Transition((0, 0, 0), (1, 1, 0), 1.0, "frogging")) xnlist.append(Transition((0, 0, 1), (1, 1, 1), 1.0, "frogging")) xnlist.append(Transition((0, 0, 2), (1, 1, 2), 1.0, "frogging")) nsg = mg.add_zeros("node", "node_state_grid") ohcts = OrientedHexCTS(mg, nsd, xnlist, nsg) assert_array_equal( ohcts.link_state[mg.active_links], [0, 4, 8, 8, 4, 0, 4, 8, 8, 4, 0] ) assert_array_equal( ohcts.next_trn_id[mg.active_links], [0, 1, 2, 2, 1, 0, 1, 2, 2, 1, 0] ) assert_array_equal( np.round(ohcts.next_update[mg.active_links], 2), [0.8, 1.26, 0.92, 0.79, 0.55, 1.04, 0.58, 2.22, 3.31, 0.48, 1.57], ) pq = ohcts.priority_queue assert_equal(pq._queue[0][2], 20) # link for first event = 20, not shifted assert_equal(round(pq._queue[0][0], 2), 0.48) # trn scheduled for t = 0.48 assert_equal(pq._queue[2][2], 15) # this event scheduled for link 15... assert_equal(round(pq._queue[2][0], 2), 0.58) # ...trn sched for t = 0.58 lu = LatticeUplifter(grid=mg) lu.shift_link_and_transition_data_upward(ohcts, 0.0) # note new events lowest 5 links assert_array_equal( np.round(ohcts.next_update[mg.active_links], 2), [0.75, 0.84, 2.6, 0.07, 0.09, 0.8, 0.02, 1.79, 1.51, 2.04, 3.85], ) assert_equal(pq._queue[0][2], 15) # new soonest event assert_equal(pq._queue[9][2], 14) # was previously 7, now shifted up... assert_equal(round(pq._queue[9][0], 2), 0.8) # ...still sched for t = 0.80
def initializer(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, dissolution_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, opt_track_grains, prop_data, prop_reset_value, callback_fn, closed_boundaries, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.dissolution_rate = dissolution_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) self.opt_track_grains = opt_track_grains self.callback_fn = callback_fn if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, prop_data=prop_data, prop_reset_value=prop_reset_value, closed_boundaries=closed_boundaries, **kwds) # Set some things related to property-swapping and/or callback fn # if the user wants to track grain motion. #if opt_track_grains: # propid = self.ca.propid #else: # propid = None self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state'], propid=self.ca.propid, prop_data=self.ca.prop_data, prop_reset_value=self.ca.prop_reset_value) self.initialize_timing(output_interval, plot_interval, uplift_interval, report_interval)
def initialize(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, show_plots, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval) self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state'])
def bh_initialize(self, grid_size, cell_width, grav_accel, report_interval, run_duration, output_interval, disturbance_rate, weathering_rate, uplift_interval, uplift_duration, plot_interval, save_plots, plot_filename, plot_filetype, friction_coef, rock_state_for_uplift, opt_rock_collapse, block_layer_dip_angle, block_layer_thickness, layer_left_x, y0_top): """Initialize the BlockHill model.""" # Set block-related variables self.block_layer_dip_angle = block_layer_dip_angle self.block_layer_thickness = block_layer_thickness self.layer_left_x = layer_left_x self.y0_top = y0_top # Call parent class init super(BlockHill, self).__init__(grid_size=grid_size, cell_width=cell_width, grav_accel=grav_accel, report_interval=report_interval, run_duration=run_duration, output_interval=output_interval, disturbance_rate=disturbance_rate, weathering_rate=weathering_rate, uplift_interval=uplift_interval, uplift_duration=uplift_duration, plot_interval=plot_interval, friction_coef=friction_coef, rock_state_for_uplift=rock_state_for_uplift, opt_rock_collapse=opt_rock_collapse, save_plots=save_plots, plot_filename=plot_filename, plot_filetype=plot_filetype) self.uplifter = LatticeUplifter( self.grid, self.grid.at_node['node_state'], opt_block_layer=True, block_ID=8, block_layer_dip_angle=block_layer_dip_angle, block_layer_thickness=block_layer_thickness, layer_left_x=layer_left_x, y0_top=y0_top)
def initialize(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, block_layer_dip_angle, block_layer_thickness, layer_left_x, y0_top, show_plots, **kwds): """Initialize the BlockHill model.""" print('bh initil') # Set block-related variables self.block_layer_dip_angle = block_layer_dip_angle self.block_layer_thickness = block_layer_thickness self.layer_left_x = layer_left_x self.y0_top = y0_top # Call parent class init super(BlockHill, self).__init__(grid_size=grid_size, report_interval=report_interval, run_duration=run_duration, output_interval=output_interval, settling_rate=settling_rate, disturbance_rate=disturbance_rate, weathering_rate=weathering_rate, uplift_interval=uplift_interval, plot_interval=plot_interval, friction_coef=friction_coef, rock_state_for_uplift=rock_state_for_uplift, opt_rock_collapse=opt_rock_collapse, show_plots=show_plots, **kwds) self.uplifter = LatticeUplifter( self.grid, self.grid.at_node['node_state'], opt_block_layer=True, block_ID=8, block_layer_dip_angle=block_layer_dip_angle, block_layer_thickness=block_layer_thickness, layer_left_x=layer_left_x, y0_top=y0_top) # print('bh initil done') sys.stdout.flush()
class GrainHill(CTSModel): """ Model hillslope evolution with block uplift. """ def __init__(self, grid_size, report_interval=1.0e8, run_duration=1.0, output_interval=1.0e99, settling_rate=2.2e8, disturbance_rate=1.0, weathering_rate=1.0, dissolution_rate=0.0, uplift_interval=1.0, plot_interval=1.0e99, friction_coef=0.3, rock_state_for_uplift=7, opt_rock_collapse=False, show_plots=True, initial_state_grid=None, opt_track_grains=False, prop_data=None, prop_reset_value=None, callback_fn=None, closed_boundaries=(False, False, False, False), **kwds): """Call the initialize() method.""" self.initializer(grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, dissolution_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, opt_track_grains, prop_data, prop_reset_value, callback_fn, closed_boundaries, **kwds) def initializer(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, dissolution_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, opt_track_grains, prop_data, prop_reset_value, callback_fn, closed_boundaries, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.dissolution_rate = dissolution_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) self.opt_track_grains = opt_track_grains self.callback_fn = callback_fn if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation="vertical", grid_shape="rect", show_plots=show_plots, cts_type="oriented_hex", run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, prop_data=prop_data, prop_reset_value=prop_reset_value, closed_boundaries=closed_boundaries, **kwds) # Set some things related to property-swapping and/or callback fn # if the user wants to track grain motion. # if opt_track_grains: # propid = self.ca.propid # else: # propid = None self.uplifter = LatticeUplifter( self.grid, self.grid.at_node["node_state"], propid=self.ca.propid, prop_data=self.ca.prop_data, prop_reset_value=self.ca.prop_reset_value, ) self.initialize_timing(output_interval, plot_interval, uplift_interval, report_interval) def initialize_timing(self, output_interval, plot_interval, uplift_interval, report_interval): """Set up variables related to timing of uplift, output, reporting""" self.current_time = 0.0 # Next time for output to file self.next_output = output_interval # Next time for a plot if self._show_plots: self.next_plot = plot_interval else: self.next_plot = self.run_duration + 1 # Next time for a progress report to user self.next_report = report_interval # Next time to add baselevel adjustment self.next_uplift = uplift_interval # Iteration numbers, for output files self.output_iteration = 1 def node_state_dictionary(self): """ Create and return dict of node states. Overrides base-class method. Here, we simply call on a function in the lattice_grain module. """ return lattice_grain_node_states() def transition_list(self): """ Make and return list of Transition object. """ xn_list = lattice_grain_transition_list( g=self.settling_rate, f=self.friction_coef, motion=self.settling_rate, swap=self.opt_track_grains, callback=self.callback_fn, ) xn_list = self.add_weathering_and_disturbance_transitions( xn_list, self.disturbance_rate, self.weathering_rate, self.dissolution_rate, collapse_rate=self.collapse_rate, ) return xn_list def add_weathering_and_disturbance_transitions( self, xn_list, d=0.0, w=0.0, diss=0.0, collapse_rate=0.0, swap=False, callback=None, ): """ Add transition rules representing weathering and/or grain disturbance to the list, and return the list. Parameters ---------- xn_list : list of Transition objects List of objects that encode information about the link-state transitions. Normally should first be initialized with lattice-grain transition rules, then passed to this function to add rules for weathering and disturbance. d : float (optional) Rate of transition (1/time) from fluid / resting grain pair to mobile-grain / fluid pair, representing grain disturbance. w : float (optional) Rate of transition (1/time) from fluid / rock pair to fluid / resting-grain pair, representing weathering. diss : float (optional) Dissolution rate: transition rate from fluid / rock pair to fluid / fluid pair. Returns ------- xn_list : list of Transition objects Modified transition list. """ # Disturbance rule if d > 0.0: xn_list.append( Transition((7, 0, 0), (0, 1, 0), d, "disturbance", swap, callback)) xn_list.append( Transition((7, 0, 1), (0, 2, 1), d, "disturbance", swap, callback)) xn_list.append( Transition((7, 0, 2), (0, 3, 2), d, "disturbance", swap, callback)) xn_list.append( Transition((0, 7, 0), (4, 0, 0), d, "disturbance", swap, callback)) xn_list.append( Transition((0, 7, 1), (5, 0, 1), d, "disturbance", swap, callback)) xn_list.append( Transition((0, 7, 2), (6, 0, 2), d, "disturbance", swap, callback)) # Weathering rule if w > 0.0: xn_list.append(Transition((8, 0, 0), (7, 0, 0), w, "weathering")) xn_list.append(Transition((8, 0, 1), (7, 0, 1), w, "weathering")) xn_list.append(Transition((8, 0, 2), (7, 0, 2), w, "weathering")) xn_list.append(Transition((0, 8, 0), (0, 7, 0), w, "weathering")) xn_list.append(Transition((0, 8, 1), (0, 7, 1), w, "weathering")) xn_list.append(Transition((0, 8, 2), (0, 7, 2), w, "weathering")) # "Vertical rock collapse" rule: a rock particle overlying air # will collapse, transitioning to a downward-moving grain if collapse_rate > 0.0: xn_list.append( Transition( (0, 8, 0), (4, 0, 0), collapse_rate, "rock collapse", swap, callback, )) # Dissolution rule if diss > 0.0: xn_list.append( Transition((8, 0, 0), (0, 0, 0), diss, "dissolution")) xn_list.append( Transition((8, 0, 1), (0, 0, 1), diss, "dissolution")) xn_list.append( Transition((8, 0, 2), (0, 0, 2), diss, "dissolution")) xn_list.append( Transition((0, 8, 0), (0, 0, 0), diss, "dissolution")) xn_list.append( Transition((0, 8, 1), (0, 0, 1), diss, "dissolution")) xn_list.append( Transition((0, 8, 2), (0, 0, 2), diss, "dissolution")) if _DEBUG: print() print("setup_transition_list(): list has " + str(len(xn_list)) + " transitions:") for t in xn_list: print(" From state " + str(t.from_state) + " to state " + str(t.to_state) + " at rate " + str(t.rate) + " called " + str(t.name)) return xn_list def initialize_node_state_grid(self): """Set up initial node states. Examples -------- >>> gh = GrainHill((5, 7)) >>> gh.grid.at_node['node_state'] # doctest: +NORMALIZE_WHITESPACE array([8, 7, 7, 8, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) """ # For shorthand, get a reference to the node-state grid and to x coord nsg = self.grid.at_node["node_state"] nodex = self.grid.node_x # Fill the bottom two rows with grains right_side_x = 0.866025403784 * (self.grid.number_of_node_columns - 1) for i in range(self.grid.number_of_nodes): if self.grid.node_y[i] < 2.0: if nodex[i] > 0.0 and nodex[i] < right_side_x: nsg[i] = 7 # Place "wall" particles in the lower-left and lower-right corners if self.grid.number_of_node_columns % 2 == 0: bottom_right = self.grid.number_of_node_columns - 1 else: bottom_right = self.grid.number_of_node_columns // 2 nsg[0] = 8 # bottom left nsg[bottom_right] = 8 return nsg def run(self, to=None): """Run the model.""" if to is None: run_to = self.run_duration else: run_to = to while self.current_time < run_to: # Figure out what time to run to this iteration next_pause = min(self.next_output, self.next_plot) next_pause = min(next_pause, self.next_uplift) next_pause = min(next_pause, run_to) # 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 " + str(self.current_time) + " (" + str(100 * self.current_time / self.run_duration) + "%)") self.next_report = current_real_time + self.report_interval # Run until next pause self.ca.run(next_pause, self.ca.node_state) self.current_time = next_pause # Handle output to file if self.current_time >= self.next_output: self.write_output(self.grid, "grain_hill_model", self.output_iteration) self.output_iteration += 1 self.next_output += self.output_interval # Handle plotting on display if self._show_plots and self.current_time >= self.next_plot: self.ca_plotter.update_plot() axis("off") self.next_plot += self.plot_interval # Handle uplift if self.current_time >= self.next_uplift: self.uplifter.uplift_interior_nodes(self.ca, self.current_time, rock_state=self.rock_state) self.next_uplift += self.uplift_interval def get_profile_and_soil_thickness(self, grid, data): """Calculate and return profiles of elevation and soil thickness. Examples -------- >>> from landlab import HexModelGrid >>> hg = HexModelGrid((4, 5), node_layout='rect', orientation='vertical') >>> ns = hg.add_zeros("node_state", at="node", dtype=int) >>> ns[[0, 3, 1, 6, 4, 9, 2]] = 8 >>> ns[[8, 13, 11, 16, 14]] = 7 >>> gh = GrainHill((3, 7)) # grid size arbitrary here >>> (elev, thickness) = gh.get_profile_and_soil_thickness(hg, ns) >>> list(elev) [0.0, 2.5, 3.0, 2.5, 0.0] >>> list(thickness) [0.0, 2.0, 2.0, 1.0, 0.0] """ nc = grid.number_of_node_columns elev = zeros(nc) soil = zeros(nc) for col in range(nc): base_id = (col // 2) + (col % 2) * ((nc + 1) // 2) node_ids = arange(base_id, grid.number_of_nodes, nc) states = data[node_ids] (rows_with_rock_or_sed, ) = where(states > 0) if len(rows_with_rock_or_sed) == 0: elev[col] = 0.0 else: elev[col] = amax(rows_with_rock_or_sed) + 0.5 * (col % 2) soil[col] = count_nonzero(logical_and(states > 0, states < 8)) return elev, soil
class GrainHill(CTSModel): """ Model hillslope evolution with block uplift. """ def __init__(self, grid_size, report_interval=1.0e8, run_duration=1.0, output_interval=1.0e99, settling_rate=2.2e8, disturbance_rate=1.0, weathering_rate=1.0, uplift_interval=1.0, plot_interval=1.0e99, friction_coef=0.3, rock_state_for_uplift=7, opt_rock_collapse=False, show_plots=True, initial_state_grid=None, **kwds): """Call the initialize() method.""" self.initializer(grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, **kwds) def initializer(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, initial_state_grid, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, **kwds) self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state']) def node_state_dictionary(self): """ Create and return dict of node states. Overrides base-class method. Here, we simply call on a function in the lattice_grain module. """ return lattice_grain_node_states() def transition_list(self): """ Make and return list of Transition object. """ xn_list = lattice_grain_transition_list(g=self.settling_rate, f=self.friction_coef, motion=self.settling_rate) xn_list = self.add_weathering_and_disturbance_transitions( xn_list, self.disturbance_rate, self.weathering_rate, collapse_rate=self.collapse_rate) return xn_list def add_weathering_and_disturbance_transitions(self, xn_list, d=0.0, w=0.0, collapse_rate=0.0): """ Add transition rules representing weathering and/or grain disturbance to the list, and return the list. Parameters ---------- xn_list : list of Transition objects List of objects that encode information about the link-state transitions. Normally should first be initialized with lattice-grain transition rules, then passed to this function to add rules for weathering and disturbance. d : float (optional) Rate of transition (1/time) from fluid / resting grain pair to mobile-grain / fluid pair, representing grain disturbance. w : float (optional) Rate of transition (1/time) from fluid / rock pair to fluid / resting-grain pair, representing weathering. Returns ------- xn_list : list of Transition objects Modified transition list. """ # Disturbance rule if d > 0.0: xn_list.append(Transition((7, 0, 0), (0, 1, 0), d, 'disturbance')) xn_list.append(Transition((7, 0, 1), (0, 2, 1), d, 'disturbance')) xn_list.append(Transition((7, 0, 2), (0, 3, 2), d, 'disturbance')) xn_list.append(Transition((0, 7, 0), (4, 0, 0), d, 'disturbance')) xn_list.append(Transition((0, 7, 1), (5, 0, 1), d, 'disturbance')) xn_list.append(Transition((0, 7, 2), (6, 0, 2), d, 'disturbance')) # Weathering rule if w > 0.0: xn_list.append(Transition((8, 0, 0), (7, 0, 0), w, 'weathering')) xn_list.append(Transition((8, 0, 1), (7, 0, 1), w, 'weathering')) xn_list.append(Transition((8, 0, 2), (7, 0, 2), w, 'weathering')) xn_list.append(Transition((0, 8, 0), (0, 7, 0), w, 'weathering')) xn_list.append(Transition((0, 8, 1), (0, 7, 1), w, 'weathering')) xn_list.append(Transition((0, 8, 2), (0, 7, 2), w, 'weathering')) # "Vertical rock collapse" rule: a rock particle overlying air # will collapse, transitioning to a downward-moving grain if collapse_rate > 0.0: xn_list.append( Transition((0, 8, 0), (4, 0, 0), collapse_rate, 'rock collapse')) if _DEBUG: print() print('setup_transition_list(): list has ' + str(len(xn_list)) + ' transitions:') for t in xn_list: print(' From state ' + str(t.from_state) + ' to state ' + str(t.to_state) + ' at rate ' + str(t.rate) + ' called ' + str(t.name)) return xn_list def initialize_node_state_grid(self): """Set up initial node states. Examples -------- >>> gh = GrainHill((5, 7)) >>> gh.grid.at_node['node_state'] array([8, 7, 7, 8, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) """ # For shorthand, get a reference to the node-state grid nsg = self.grid.at_node['node_state'] # Fill the bottom two rows with grains right_side_x = 0.866025403784 * (self.grid.number_of_node_columns - 1) for i in range(self.grid.number_of_nodes): if self.grid.node_y[i] < 2.0: if (self.grid.node_x[i] > 0.0 and self.grid.node_x[i] < right_side_x): nsg[i] = 7 # Place "wall" particles in the lower-left and lower-right corners if self.grid.number_of_node_columns % 2 == 0: bottom_right = self.grid.number_of_node_columns - 1 else: bottom_right = self.grid.number_of_node_columns // 2 nsg[0] = 8 # bottom left nsg[bottom_right] = 8 return nsg def run(self): """Run the model.""" # Work out the next times to plot and output next_output = self.output_interval if self._show_plots: next_plot = self.plot_interval else: next_plot = self.run_duration + 1 # Next time for a progress report to user next_report = self.report_interval # And baselevel adjustment next_uplift = self.uplift_interval current_time = 0.0 output_iteration = 1 while current_time < self.run_duration: # Figure out what time to run to this iteration next_pause = min(next_output, next_plot) next_pause = min(next_pause, next_uplift) next_pause = min(next_pause, 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 >= next_report: print('Current sim time' + str(current_time) + '(' + \ str(100 * current_time / self.run_duration) + '%)') next_report = current_real_time + self.report_interval # Run the model forward in time until the next output step self.ca.run(next_pause, self.ca.node_state) #plot_each_transition=pet, plotter=self.ca_plotter) current_time = next_pause # Handle output to file if current_time >= next_output: self.write_output(self.grid, 'grain_hill_model', output_iteration) output_iteration += 1 next_output += self.output_interval # Handle plotting on display if self._show_plots and current_time >= next_plot: self.ca_plotter.update_plot() axis('off') next_plot += self.plot_interval # Handle uplift if current_time >= next_uplift: self.uplifter.uplift_interior_nodes(self.ca, current_time, rock_state=self.rock_state) next_uplift += self.uplift_interval def get_profile_and_soil_thickness(self, grid, data): """Calculate and return profiles of elevation and soil thickness. Examples -------- >>> from landlab import HexModelGrid >>> hg = HexModelGrid(4, 5, shape='rect', orientation='vert') >>> ns = hg.add_zeros('node', 'node_state', dtype=int) >>> ns[[0, 3, 1, 6, 4, 9, 2]] = 8 >>> ns[[8, 13, 11, 16, 14]] = 7 >>> gh = GrainHill((3, 7)) # grid size arbitrary here >>> (elev, thickness) = gh.get_profile_and_soil_thickness(hg, ns) >>> elev array([ 0. , 2.5, 3. , 2.5, 0. ]) >>> thickness array([ 0., 2., 2., 1., 0.]) """ nc = grid.number_of_node_columns elev = zeros(nc) soil = zeros(nc) for col in range(nc): states = data[grid.nodes[:, col]] (rows_with_rock_or_sed, ) = where(states > 0) if len(rows_with_rock_or_sed) == 0: elev[col] = 0.0 else: elev[col] = amax(rows_with_rock_or_sed) + 0.5 * (col % 2) soil[col] = count_nonzero(logical_and(states > 0, states < 8)) return elev, soil
class GrainHill(CTSModel): """ Model hillslope evolution with block uplift. """ def __init__(self, grid_size, report_interval=1.0e8, run_duration=1.0, output_interval=1.0e99, settling_rate=2.2e8, disturbance_rate=1.0, weathering_rate=1.0, uplift_interval=1.0, plot_interval=1.0e99, friction_coef=0.3, rock_state_for_uplift=7, opt_rock_collapse=False, show_plots=True, **kwds): """Call the initialize() method.""" self.initialize(grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, **kwds) def initialize(self, grid_size, report_interval, run_duration, output_interval, settling_rate, disturbance_rate, weathering_rate, uplift_interval, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, show_plots, **kwds): """Initialize the grain hill model.""" self.settling_rate = settling_rate self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.uplift_interval = uplift_interval self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize(grid_size=grid_size, report_interval=report_interval, grid_orientation='vertical', grid_shape='rect', show_plots=show_plots, cts_type='oriented_hex', run_duration=run_duration, output_interval=output_interval, **kwds) self.uplifter = LatticeUplifter(self.grid, self.grid.at_node['node_state']) def node_state_dictionary(self): """ Create and return dict of node states. Overrides base-class method. Here, we simply call on a function in the lattice_grain module. """ return lattice_grain_node_states() def transition_list(self): """ Make and return list of Transition object. """ xn_list = lattice_grain_transition_list(g=self.settling_rate, f=self.friction_coef, motion=self.settling_rate) xn_list = self.add_weathering_and_disturbance_transitions(xn_list, self.disturbance_rate, self.weathering_rate, collapse_rate=self.collapse_rate) return xn_list def add_weathering_and_disturbance_transitions(self, xn_list, d=0.0, w=0.0, collapse_rate=0.0): """ Add transition rules representing weathering and/or grain disturbance to the list, and return the list. Parameters ---------- xn_list : list of Transition objects List of objects that encode information about the link-state transitions. Normally should first be initialized with lattice-grain transition rules, then passed to this function to add rules for weathering and disturbance. d : float (optional) Rate of transition (1/time) from fluid / resting grain pair to mobile-grain / fluid pair, representing grain disturbance. w : float (optional) Rate of transition (1/time) from fluid / rock pair to fluid / resting-grain pair, representing weathering. Returns ------- xn_list : list of Transition objects Modified transition list. """ # Disturbance rule xn_list.append( Transition((7,0,0), (0,1,0), d, 'disturbance') ) xn_list.append( Transition((7,0,1), (0,2,1), d, 'disturbance') ) xn_list.append( Transition((7,0,2), (0,3,2), d, 'disturbance') ) xn_list.append( Transition((0,7,0), (4,0,0), d, 'disturbance') ) xn_list.append( Transition((0,7,1), (5,0,1), d, 'disturbance') ) xn_list.append( Transition((0,7,2), (6,0,2), d, 'disturbance') ) # Weathering rule if w > 0.0: xn_list.append( Transition((8,0,0), (7,0,0), w, 'weathering') ) xn_list.append( Transition((8,0,1), (7,0,1), w, 'weathering') ) xn_list.append( Transition((8,0,2), (7,0,2), w, 'weathering') ) xn_list.append( Transition((0,8,0), (0,7,0), w, 'weathering') ) xn_list.append( Transition((0,8,1), (0,7,1), w, 'weathering') ) xn_list.append( Transition((0,8,2), (0,7,2), w, 'weathering') ) # "Vertical rock collapse" rule: a rock particle overlying air # will collapse, transitioning to a downward-moving grain if collapse_rate > 0.0: xn_list.append( Transition((0,8,0), (4,0,0), collapse_rate, 'rock collapse')) return xn_list def initialize_node_state_grid(self): """Set up initial node states. Examples -------- >>> gh = GrainHill((5, 7)) >>> gh.grid.at_node['node_state'] array([8, 7, 7, 8, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) """ # For shorthand, get a reference to the node-state grid nsg = self.grid.at_node['node_state'] # Fill the bottom two rows with grains right_side_x = 0.866025403784 * (self.grid.number_of_node_columns - 1) for i in range(self.grid.number_of_nodes): if self.grid.node_y[i] < 2.0: if (self.grid.node_x[i] > 0.0 and self.grid.node_x[i] < right_side_x): nsg[i] = 7 # Place "wall" particles in the lower-left and lower-right corners if self.grid.number_of_node_columns % 2 == 0: bottom_right = self.grid.number_of_node_columns - 1 else: bottom_right = self.grid.number_of_node_columns // 2 nsg[0] = 8 # bottom left nsg[bottom_right] = 8 return nsg def run(self): """Run the model.""" # Work out the next times to plot and output next_output = self.output_interval if self._show_plots: next_plot = self.plot_interval else: next_plot = self.run_duration + 1 # Next time for a progress report to user next_report = self.report_interval # And baselevel adjustment next_uplift = self.uplift_interval current_time = 0.0 output_iteration = 1 while current_time < self.run_duration: # Figure out what time to run to this iteration next_pause = min(next_output, next_plot) next_pause = min(next_pause, next_uplift) next_pause = min(next_pause, 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 >= next_report: print('Current sim time' + str(current_time) + '(' + \ str(100 * current_time / self.run_duration) + '%)') next_report = current_real_time + self.report_interval # Run the model forward in time until the next output step self.ca.run(next_pause, self.ca.node_state) current_time = next_pause # Handle output to file if current_time >= next_output: self.write_output(self.grid, 'grain_hill_model', output_iteration) output_iteration += 1 next_output += self.output_interval # Handle plotting on display if self._show_plots and current_time >= next_plot: self.ca_plotter.update_plot() axis('off') next_plot += self.plot_interval # Handle uplift if current_time >= next_uplift: self.uplifter.uplift_interior_nodes(self.ca, rock_state=self.rock_state) if _RUN_NEW: self.ca.update_link_states_and_transitions_new(current_time) else: self.ca.update_link_states_and_transitions(current_time) next_uplift += self.uplift_interval def get_profile_and_soil_thickness(self, grid, data): """Calculate and return profiles of elevation and soil thickness. Examples -------- >>> from landlab import HexModelGrid >>> hg = HexModelGrid(4, 5, shape='rect', orientation='vert') >>> ns = hg.add_zeros('node', 'node_state', dtype=int) >>> ns[[0, 3, 1, 6, 4, 9, 2]] = 8 >>> ns[[8, 13, 11, 16, 14]] = 7 >>> gh = GrainHill((3, 7)) # grid size arbitrary here >>> (elev, thickness) = gh.get_profile_and_soil_thickness(hg, ns) >>> elev array([ 0. , 2.5, 3. , 2.5, 0. ]) >>> thickness array([ 0., 2., 2., 1., 0.]) """ nc = grid.number_of_node_columns elev = zeros(nc) soil = zeros(nc) for col in range(nc): states = data[grid.nodes[:, col]] (rows_with_rock_or_sed, ) = where(states > 0) if len(rows_with_rock_or_sed) == 0: elev[col] = 0.0 else: elev[col] = amax(rows_with_rock_or_sed) + 0.5 * (col % 2) soil[col] = count_nonzero(logical_and(states > 0, states < 8)) return elev, soil
def run(uplift_interval, d): #d_ratio_exp): # INITIALIZE #uplift_interval = 1e7 #filenm = 'test_output' #imagenm = 'Hill141213/hill'+str(int(d_ratio_exp))+'d' # 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 next_uplift = uplift_interval # Create a grid hmg = HexModelGrid(nr, nc, 1.0, orientation='vertical', shape='rect', reorient_links=True) # Close the right-hand grid boundaries #hmg.set_closed_nodes(arange((nc-1)*nr, hmg.number_of_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, d) #xn_list = [] #xn_list.append( Transition((0,1,0), (0,7,0), g, 'gravity 1') ) # Create data and initialize values. node_state_grid = hmg.add_zeros('node', 'node_state_grid', dtype=int) # Lower rows get resting particles if nc % 2 == 0: # if even num cols, bottom right is... bottom_right = nc - 1 else: bottom_right = nc // 2 right_side_x = 0.866025403784 * (nc - 1) for i in range(hmg.number_of_nodes): if hmg.node_y[i] < 3.0: if hmg.node_x[i] > 0.0 and hmg.node_x[i] < right_side_x: node_state_grid[i] = 7 #elif hmg.node_x[i]>((nc-1)*0.866): # node_state_grid[i] = 8 node_state_grid[0] = 8 # bottom left node_state_grid[bottom_right] = 8 #for i in range(hmg.number_of_nodes): # print i, hmg.node_x[i], hmg.node_y[i], node_state_grid[i] # Create an uplift object uplifter = LatticeUplifter(hmg, node_state_grid) # Create the CA model ca = OrientedHexCTS(hmg, ns_dict, xn_list, node_state_grid) # Create a CAPlotter object for handling screen display # potential colors: red3='#CD0000' #mob = 'r' #rock = '#5F594D' sed = '#A4874B' #sky = '#CBD5E1' #sky = '#85A5CC' sky = '#D0E4F2' rock = '#000000' #sky mob = '#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) ca_plotter = CAPlotter(ca, cmap=my_cmap) k = 0 # Plot the initial grid ca_plotter.update_plot() axis('off') #savefig(imagenm+str(k)+'.png') k += 1 # Write output for initial grid #write_output(hmg, filenm, 0) #output_iteration = 1 # Create an array to store the numbers of states at each plot interval #nstates = zeros((9, int(run_duration/plot_interval))) #k = 0 # Work out the next times to plot and output next_output = output_interval next_plot = plot_interval # RUN current_time = 0.0 while current_time < run_duration: # Figure out what time to run to this iteration next_pause = min(next_output, next_plot) next_pause = min(next_pause, next_uplift) next_pause = min(next_pause, 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 print('Running to...' + str(next_pause)) ca.run(next_pause, ca.node_state) #, #plot_each_transition=plot_every_transition, plotter=ca_plotter) current_time = next_pause # Handle output to file if current_time >= next_output: #write_output(hmg, filenm, output_iteration) #output_iteration += 1 next_output += output_interval # Handle plotting on display if current_time >= next_plot: #node_state_grid[hmg.number_of_node_rows-1] = 8 ca_plotter.update_plot() axis('off') next_plot += plot_interval # Handle uplift if current_time >= next_uplift: uplifter.uplift_interior_nodes(rock_state=7) ca.update_link_states_and_transitions(current_time) next_uplift += uplift_interval print('Finished with main loop')
def initialize( self, grid_size, cell_width, grav_accel, report_interval, run_duration, output_interval, disturbance_rate, weathering_rate, dissolution_rate, uplift_interval, uplift_duration, plot_interval, friction_coef, rock_state_for_uplift, opt_rock_collapse, save_plots, plot_filename, plot_filetype, initial_state_grid, opt_track_grains, prop_data, prop_reset_value, callback_fn, closed_boundaries, ): """Initialize the grain hill model.""" self.settling_rate = calculate_settling_rate(cell_width, grav_accel) self.disturbance_rate = disturbance_rate self.weathering_rate = weathering_rate self.dissolution_rate = dissolution_rate self.uplift_interval = uplift_interval if uplift_duration is not None: self.uplift_duration = uplift_duration else: self.uplift_duration = run_duration self.plot_interval = plot_interval self.friction_coef = friction_coef self.rock_state = rock_state_for_uplift # 7 (resting sed) or 8 (rock) self.opt_track_grains = opt_track_grains self.callback_fn = callback_fn if opt_rock_collapse: self.collapse_rate = self.settling_rate else: self.collapse_rate = 0.0 # Call base class init super(GrainHill, self).initialize( grid_size=grid_size, report_interval=report_interval, grid_orientation="vertical", grid_shape="rect", cts_type="oriented_hex", run_duration=run_duration, output_interval=output_interval, initial_state_grid=initial_state_grid, prop_data=prop_data, prop_reset_value=prop_reset_value, closed_boundaries=closed_boundaries ) # Set some things related to property-swapping and/or callback fn # if the user wants to track grain motion. # if opt_track_grains: # propid = self.ca.propid # else: # propid = None self.uplifter = LatticeUplifter( self.grid, self.grid.at_node["node_state"], propid=self.ca.propid, prop_data=self.ca.prop_data, prop_reset_value=self.ca.prop_reset_value, ) self.initialize_timing( output_interval, plot_interval, uplift_interval, report_interval ) # initialize plotting if plot_interval <= run_duration: import matplotlib.pyplot as plt plt.ion() plt.figure(1) self.save_plots = save_plots if save_plots: self.plot_filename = plot_filename self.plot_filetype = plot_filetype nplots = (self.run_duration / self.plot_interval) + 1 self.ndigits = int(np.floor(np.log10(nplots))) + 1 this_filename = (plot_filename + '0'.zfill(self.ndigits) + plot_filetype) print(this_filename) else: this_filename = None plot_hill(self.grid, this_filename)