def test_symmetry_of_solution(): """test that water table is symmetric under constant recharge Notes: ---- Under constant recharge with radially symmetric aquifer base elevation, the model should produce a water table that is radially symmetric. This test demonstrates this is the case where topographic elevation and aquifer base elevation are radially symmetric parabolas on a hexagonal grid. """ hmg = HexModelGrid(shape=(7, 4), spacing=10.0) x = hmg.x_of_node y = hmg.y_of_node elev = hmg.add_zeros("topographic__elevation", at="node") elev[:] = 1e-3 * (x * (max(x) - x) + y * (max(y) - y)) + 2 base = hmg.add_zeros("aquifer_base__elevation", at="node") base[:] = elev - 2 wt = hmg.add_zeros("water_table__elevation", at="node") wt[:] = elev wt[hmg.open_boundary_nodes] = 0.0 gdp = GroundwaterDupuitPercolator(hmg, recharge_rate=1e-7, hydraulic_conductivity=1e-4) for _ in range(1000): gdp.run_one_step(1e3) tc = hmg.at_node["aquifer__thickness"] assert_almost_equal(tc[5], tc[31]) # SW-NE assert_almost_equal(tc[29], tc[7]) # NW-SE assert_almost_equal(tc[16], tc[20]) # W-E
def test_hex_grid(): mg = HexModelGrid((5, 5)) mg.add_zeros("soil__depth", at="node") dt = 1000.0 expw3 = ExponentialWeathererIntegrated( mg, soil_production__maximum_rate=1.0, soil_production__decay_depth=1.0, soil_production__expansion_factor=1.3, ) expw3.run_one_step(dt) errors = [] # replace assertions by conditions if not np.allclose( mg.at_node["soil_production__dt_weathered_depth"][mg.core_nodes], 5.5161 ): errors.append("error in weathered depth") if not np.allclose( mg.at_node["soil_production__dt_produced_depth"][mg.core_nodes], 7.1709 ): errors.append("error in produced depth") if not np.allclose(dt * mg.at_node["soil_production__rate"][mg.core_nodes], 1000.0): errors.append("error in basic euler integration") # assert no error message has been registered, else print messages assert not errors, "errors occured:\n{}".format("\n".join(errors))
def test_with_lake_mapper_barnes(): hmg_hole = HexModelGrid((9, 5)) z = hmg_hole.add_field( "topographic__elevation", hmg_hole.x_of_node + np.round(hmg_hole.y_of_node), at="node", ) hole_nodes = [21, 22, 23, 30, 31, 39, 40] z[hole_nodes] = z[hole_nodes] * 0.1 hmg_hole.add_zeros("filled__elevation", at="node") fa = FlowAccumulator( hmg_hole, flow_director="Steepest", depression_finder="LakeMapperBarnes", fill_flat=False, redirect_flow_steepest_descent=True, reaccumulate_flow=True, fill_surface="filled__elevation", ) fa.run_one_step() rcvrs = hmg_hole.at_node["flow__receiver_node"] assert_array_equal(rcvrs[[13, 21, 46]], [6, 13, 39]) from landlab.components import LakeMapperBarnes fa = FlowAccumulator(hmg_hole, depression_finder=LakeMapperBarnes) lmb = LakeMapperBarnes(hmg_hole) fa = FlowAccumulator(hmg_hole, depression_finder=lmb)
def test_outlet_lowering_object_bad_file(): """Test using an outlet lowering object with a bad file.""" mg = HexModelGrid((5, 5)) mg.add_zeros("node", "topographic__elevation") with pytest.raises(ValueError): NotCoreNodeBaselevelHandler(mg, lowering_file_path="foo.txt")
def test_function_of_four_variables(): mg = HexModelGrid((5, 5)) mg.add_zeros("node", "topographic__elevation") with pytest.raises(ValueError): GenericFuncBaselevelHandler(mg, function=lambda x, y, t, q: (10 * x + 10 * y + 10 * t, +10 * q))
def test_neighbor_shaping_hex(): hmg = HexModelGrid((6, 5), spacing=1.0) hmg.add_zeros("topographic__elevation", at="node", dtype=float) _ = FlowAccumulator(hmg) lmb = LakeMapperBarnes(hmg, redirect_flow_steepest_descent=True) for arr in (lmb._neighbor_arrays, lmb._link_arrays): assert len(arr) == 1 assert arr[0].shape == (hmg.number_of_nodes, 6) assert len(lmb._neighbor_lengths) == hmg.number_of_links
def test_with_hex_grid(): grid = HexModelGrid((5, 5), node_layout="rect") grid.add_zeros("topographic__elevation", at="node") ListricKinematicExtender(grid) ListricKinematicExtender(grid, fault_location=2.0) grid = HexModelGrid((5, 5), node_layout="rect", orientation="vertical") grid.add_zeros("topographic__elevation", at="node") assert_raises(NotImplementedError, ListricKinematicExtender, grid)
def test_save_and_load_hex(): """Test saving and loading of a HexModelGrid.""" mg1 = HexModelGrid(3, 3, 1.0) mg1.add_zeros("node", "topographic__elevation") save_grid(mg1, "testsavedgrid.grid") mg2 = load_grid("testsavedgrid.grid") assert mg1.x_of_node[0] == mg2.x_of_node[0] assert_array_equal(mg1.status_at_node, mg2.status_at_node) for name in mg1.at_node: assert_array_equal(mg1.at_node[name], mg2.at_node[name])
def test_function_that_returns_wrong_size(): mg = HexModelGrid((5, 5)) mg.add_zeros("node", "topographic__elevation") with pytest.raises(ValueError): GenericFuncBaselevelHandler( mg, function=lambda mg, t: np.mean(10 * mg.x_of_node + 10 * mg. y_of_node + 10 * t), )
def test_stream_power_save_output_hex(tmpdir): mg = HexModelGrid((3, 3), node_layout="rect", spacing=10.0) mg.status_at_node[mg.status_at_node == 1] = 4 mg.status_at_node[1] = 1 mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-4) hm = HydrologySteadyStreamPower(mg, groundwater_model=gdp, routing_method="Steepest") sp = FastscapeEroder( mg, K_sp=1e-10, m_sp=1, n_sp=1, discharge_field="surface_water_area_norm__discharge", ) ld = LinearDiffuser(mg, linear_diffusivity=1e-10) rm = RegolithConstantThickness(mg, uplift_rate=0.0) output = {} output["output_interval"] = 1000 output["output_fields"] = [ "at_node:topographic__elevation", "at_node:aquifer_base__elevation", "at_node:water_table__elevation", ] output["base_output_path"] = tmpdir.strpath + "/" output["run_id"] = 0 # make this task_id if multiple runs mdl = StreamPowerModel( mg, hydrology_model=hm, diffusion_model=ld, erosion_model=sp, regolith_model=rm, total_morphological_time=1e8, output_dict=output, ) mdl.run_model() file = tmpdir.join("0_grid_0.nc") mg1 = from_netcdf(file.strpath) keys = [ "topographic__elevation", "aquifer_base__elevation", "water_table__elevation", ] assert isinstance(mg1, HexModelGrid) assert set(mg1.at_node.keys()) == set(keys) assert_equal(mg1.status_at_node, mg.status_at_node)
def test_outlet_lowering_modify_other_nodes(): mg = HexModelGrid(5, 5) mg.add_zeros("node", "topographic__elevation") node_id = 27 file = os.path.join(_TEST_DATA_DIR, "outlet_history.txt") with pytest.raises(ValueError): SingleNodeBaselevelHandler( mg, outlet_id=node_id, lowering_file_path=file, modify_outlet_id=False, )
def test_hex(): """Test using a hex grid.""" mg = HexModelGrid((5, 5)) mg.add_zeros("node", "topographic__elevation") bh = CaptureNodeBaselevelHandler( mg, capture_node=3, capture_incision_rate=-3.0, capture_start_time=10, capture_stop_time=20, post_capture_incision_rate=-0.1, ) bh.run_one_step(10)
def test_non_raster(): """Test a hex model grid.""" grid = HexModelGrid(7, 3, dx=10) _ = grid.add_zeros('node', 'topographic__elevation') param_dict = {'faulted_surface': 'topographic__elevation', 'fault_dip_angle': 90.0, 'fault_throw_rate_through_time': {'time': [0, 9, 10], 'rate': [0, 0, 0.05]}, 'fault_trace': {'y1': 30.0, 'x1': 30.0, 'y2': 20.0, 'x2': 0.0}, 'include_boundaries': True} nf = NormalFault(grid, **param_dict) # plotting, to test this. it works! #import matplotlib.pyplot as plt #plt.figure() #imshow_grid(grid, nf.faulted_nodes, color_for_background='y') #plt.plot(grid.x_of_node, grid.y_of_node, 'c.') #plt.plot([param_dict['fault_trace']['x1'], param_dict['fault_trace']['x2']], # [param_dict['fault_trace']['y1'], param_dict['fault_trace']['y2']], 'r') #plt.show() out = np.array([ True, True, True, True, True, True, True, False, True, True, True, True, False, False, False, False, True, True, False, False, False, False, False, False, False, False, False, False, False, False], dtype=bool) assert_array_equal(nf.faulted_nodes, out)
def test_initial_state_grid(): """Test passing in an initial array of node states.""" nr = 4 nc = 3 hg = HexModelGrid(shape=(nr, nc), node_layout='rect', orientation='vertical') ins = hg.add_zeros('node', 'node_state', dtype=np.int) ins[hg.y_of_node < 2] = 8 params = { 'grid_size': (nr, nc), 'report_interval': 5.0, 'output_interval': 1.0e99, 'disturbance_rate': 0.0, 'weathering_rate': 0.0, 'dissolution_rate': 1.0, 'run_duration': 3.0e3, 'plot_interval': 1.0e99, 'uplift_interval': 1.0e7, 'friction_coef': 1.0, 'fault_x': -0.001, 'cell_width': 1.0, 'grav_accel': 9.8, 'plot_file_name': 'test_column_dissolution', 'init_state_grid': ins, 'seed': 0, } gfs = GrainFacetSimulator(**params) assert_equal(np.count_nonzero(gfs.ca.node_state), 6)
def test_can_run_with_hex(): """Test that model can run with hex model grid.""" # Set up a 5x5 grid with open boundaries and low initial elevations. mg = HexModelGrid(7, 7) z = mg.add_zeros('node', 'topographic__elevation') z[:] = 0.01 * mg.x_of_node # Create a D8 flow handler fa = FlowAccumulator(mg, flow_director='FlowDirectorSteepest') # Parameter values for test 1 U = 0.001 dt = 10.0 # Create the Space component... sp = Space(mg, K_sed=0.00001, K_br=0.00000000001, F_f=0.5, phi=0.1, H_star=1., v_s=0.001, m_sp=0.5, n_sp=1.0, sp_crit_sed=0, sp_crit_br=0) # ... and run it to steady state. for i in range(2000): fa.run_one_step() sp.run_one_step(dt=dt) z[mg.core_nodes] += U * dt
def test_can_run_with_hex(): """Test that model can run with hex model grid.""" # Set up a 5x5 grid with open boundaries and low initial elevations. mg = HexModelGrid(7, 7) z = mg.add_zeros("node", "topographic__elevation") z[:] = 0.01 * mg.x_of_node # Create a D8 flow handler fa = FlowAccumulator(mg, flow_director="FlowDirectorSteepest") # Parameter values for test 1 U = 0.001 dt = 10.0 # Create the Space component... sp = Space( mg, K_sed=0.00001, K_br=0.00000000001, F_f=0.5, phi=0.1, H_star=1., v_s=0.001, m_sp=0.5, n_sp=1.0, sp_crit_sed=0, sp_crit_br=0, ) # ... and run it to steady state. for i in range(2000): fa.run_one_step() sp.run_one_step(dt=dt) z[mg.core_nodes] += U * dt
class HexLatticeTectonicizer(object): """Base class from which classes to represent particular baselevel/fault geometries are derived. """ def __init__(self, grid=None, node_state=None): # If needed, create grid if grid is None: num_rows = _DEFAULT_NUM_ROWS num_cols = _DEFAULT_NUM_COLS self.grid = HexModelGrid(num_rows, num_cols, dx=1.0, orientation='vertical', shape='rect', reorient_links=True) else: # Make sure caller passed the right type of grid assert (grid.orientation=='vertical'), \ 'Grid must have vertical orientation' # Keep a reference to the grid self.grid = grid # If needed, create node-state grid if node_state is None: self.node_state = self.grid.add_zeros('node', 'node_state_map') else: print 'setting node state' self.node_state = node_state # Remember the # of rows and cols self.nr = self.grid.number_of_node_rows self.nc = self.grid.number_of_node_columns
class HexLatticeTectonicizer(object): """Base class from which classes to represent particular baselevel/fault geometries are derived. """ def __init__(self, grid=None, node_state=None): # If needed, create grid if grid is None: num_rows = _DEFAULT_NUM_ROWS num_cols = _DEFAULT_NUM_COLS self.grid = HexModelGrid(num_rows, num_cols, dx=1.0, orientation='vertical', shape='rect', reorient_links=True) else: # Make sure caller passed the right type of grid assert (grid.orientation == 'vertical'), \ 'Grid must have vertical orientation' # Keep a reference to the grid self.grid = grid # If needed, create node-state grid if node_state is None: self.node_state = self.grid.add_zeros('node', 'node_state_map') else: self.node_state = node_state # Remember the # of rows and cols self.nr = self.grid.number_of_node_rows self.nc = self.grid.number_of_node_columns
def test_functions_with_Hex(): mg = HexModelGrid(10, 10) z = mg.add_zeros("node", "topographic__elevation") z += mg.x_of_node + mg.y_of_node fa = FlowAccumulator(mg) fa.run_one_step() ch = ChiFinder(mg, min_drainage_area=1.0, reference_concavity=1.0) ch.calculate_chi()
def test_neighbor_shaping_hex(): hmg = HexModelGrid(6, 5, dx=1.) hmg.add_zeros("node", "topographic__elevation", dtype=float) hmg.add_zeros("node", "topographic__steepest_slope", dtype=float) hmg.add_zeros("node", "flow__receiver_node", dtype=int) hmg.add_zeros("node", "flow__link_to_receiver_node", dtype=int) lmb = LakeMapperBarnes(hmg, redirect_flow_steepest_descent=True) for arr in (lmb._neighbor_arrays, lmb._link_arrays): assert len(arr) == 1 assert arr[0].shape == (hmg.number_of_nodes, 6) assert len(lmb._neighbor_lengths) == hmg.number_of_links
def test_transitions_as_ids(): """Test passing from-state and to-state IDs instead of tuples """ mg = HexModelGrid(3, 2, 1.0, orientation="vertical", reorient_links=True) nsd = {0: "zero", 1: "one"} xnlist = [] xnlist.append(Transition(2, 3, 1.0, "transitioning")) nsg = mg.add_zeros("node", "node_state_grid") cts = HexCTS(mg, nsd, xnlist, nsg) assert cts.num_link_states == 4, "wrong number of transitions"
def test_write_hex_to_path(tmpdir, fname): grid = HexModelGrid((3, 2), spacing=2.0) z = grid.add_zeros("topographic__elevation", at="node") z[3] = 1.0 with tmpdir.as_cwd(): actual = write_obj(fname, grid) assert actual == fname with open(fname, "r") as fp: assert fp.read() == LITTLE_HEX_OBJ
def test_oriented_hex_cts(): """Tests instantiation of an OrientedHexCTS() object""" mg = HexModelGrid(3, 2, 1.0, orientation="vertical", reorient_links=True) nsd = {0: "zero", 1: "one"} xnlist = [] xnlist.append(Transition((0, 1, 0), (1, 1, 0), 1.0, "transitioning")) nsg = mg.add_zeros("node", "node_state_grid") ohcts = OrientedHexCTS(mg, nsd, xnlist, nsg) assert_equal(ohcts.num_link_states, 12) assert_array_equal(ohcts.link_orientation, [2, 1, 0, 0, 0, 2, 1, 0, 2, 1, 0])
def test_hex(): """Test using a hex grid.""" mg = HexModelGrid(5, 5) z = mg.add_zeros("node", "topographic__elevation") bh = SingleNodeBaselevelHandler(mg, outlet_id=0, lowering_rate=-0.1) bh.run_one_step(10.0) assert z[1] == 0.0 assert z[0] == -1.0
def test_hex_cts(): """Tests instantiation of a HexCTS() object""" mg = HexModelGrid(3, 2, 1.0, orientation='vertical', reorient_links=True) nsd = {0 : 'zero', 1 : 'one'} xnlist = [] xnlist.append(Transition((0,1,0), (1,1,0), 1.0, 'transitioning')) nsg = mg.add_zeros('node', 'node_state_grid') hcts = HexCTS(mg, nsd, xnlist, nsg) assert_equal(hcts.num_link_states, 4) assert_array_equal(hcts.link_orientation, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
def test_hex_cts(): """Tests instantiation of a HexCTS() object""" mg = HexModelGrid(3, 2, 1.0, orientation="vertical", reorient_links=True) nsd = {0: "zero", 1: "one"} xnlist = [] xnlist.append(Transition((0, 1, 0), (1, 1, 0), 1.0, "transitioning")) nsg = mg.add_zeros("node", "node_state_grid") hcts = HexCTS(mg, nsd, xnlist, nsg) assert hcts.num_link_states == 4 assert_array_equal(hcts.link_orientation, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
def test_stoch_sp_threshold_hex(): """ Initialize HydrologyEventStreamPower on a hex grid. Use single storm-interstorm pair and make sure it returns the quantity calculated. This is not an analytical solution, just the value that is returned when using gdp and adaptive timestep solver. Confirms that hex grid returns the same value as raster grid, adjusted for cell area. Confirms that when streampower threshold is zero (Default), returns the same values as HydrologyEventStreamPower. """ mg = HexModelGrid((3, 3), node_layout="rect", spacing=10.0) mg.status_at_node[mg.status_at_node == 1] = 4 mg.status_at_node[0] = 1 mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-6) pd = PrecipitationDistribution( mg, mean_storm_duration=10, mean_interstorm_duration=100, mean_storm_depth=1e-3, total_t=100, ) pd.seed_generator(seedval=1) hm = HydrologyEventThresholdStreamPower(mg, precip_generator=pd, groundwater_model=gdp, routing_method="Steepest") hm.run_step() assert_almost_equal(hm.q_eff[4], 0.00017614 * np.sqrt(3) / 2) assert_almost_equal( hm.q_an[4], 0.00017614 * np.sqrt(3) / 2 / np.sqrt(np.sqrt(3) / 2 * 100))
def test_handle_grid_mismatch(): """Test error handling when user passes wrong grid type.""" mg = HexModelGrid(3, 2, 1.0, orientation="vertical", reorient_links=True) nsd = {0: "zero", 1: "one"} xnlist = [] xnlist.append(Transition(2, 3, 1.0, "transitioning")) nsg = mg.add_zeros("node", "node_state_grid") assert_raises(TypeError, RasterCTS, mg, nsd, xnlist, nsg) assert_raises(TypeError, OrientedRasterCTS, mg, nsd, xnlist, nsg) mg = RasterModelGrid((3, 3)) assert_raises(TypeError, HexCTS, mg, nsd, xnlist, nsg) assert_raises(TypeError, OrientedHexCTS, mg, nsd, xnlist, nsg)
def test_steady_sp_hex(): """ Initialize HydrologySteadyStreamPower on a hex grid. After one timestep it returns all recharge as discharge. """ mg = HexModelGrid((3, 3), node_layout="rect", spacing=10.0) mg.status_at_node[mg.status_at_node == 1] = 4 mg.status_at_node[0] = 1 mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-6) hm = HydrologySteadyStreamPower(mg, groundwater_model=gdp, routing_method="Steepest") hm.run_step() assert_almost_equal(hm.q[4], (np.sqrt(3) / 2) * 10**(-4)) assert_almost_equal(hm.q_an[4], np.sqrt((np.sqrt(3) / 2)) * 10**(-5))
def test_outlet_lowering_object_no_scaling(): """Test using an outlet lowering object with no scaling.""" mg = HexModelGrid(5, 5) z = mg.add_zeros("node", "topographic__elevation") node_id = 27 file = os.path.join(_TEST_DATA_DIR, "outlet_history.txt") bh = SingleNodeBaselevelHandler( mg, outlet_id=node_id, lowering_file_path=file ) for _ in range(241): bh.run_one_step(10) assert z[1] == 0.0 assert bh.z[node_id] == -47.5
def test_outlet_lowering_rate_no_scaling_bedrock(): """Test using an rate lowering object with no scaling and bedrock.""" mg = HexModelGrid(5, 5) z = mg.add_ones("node", "topographic__elevation") b = mg.add_zeros("node", "bedrock__elevation") node_id = 27 bh = SingleNodeBaselevelHandler(mg, outlet_id=node_id, lowering_rate=-0.1) for _ in range(240): bh.run_one_step(10) assert z[1] == 1.0 assert b[1] == 0.0 assert z[node_id] == -239.0 assert b[node_id] == -240.0
def test_with_hex_grid(): """Test mass balance with a hex grid. The test here is based on a simple mass balance: the computed velocity at the open boundaries, when multiplied by the depth and the width of all open cell faces, should equal the total inflow or outflow rate, which is the inundation rate times the total area. The test configuration is a hex grid with 5 rows and a maximum width of 5 columns. The bottom 3 nodes are open (fixed value) boundaries; the rest are closed. The tidal range is 1 meter, the mean depth is 5 meters, and the tidal period is 40,000 seconds. Node spacing will be 2 meters. Inundation rate = I = tidal range / tidal half period = 1 / 20,000 = 5 x 10^-5 m/s Area of one cell = (3^0.5 / 2) dx^2 ~ 3.4641 Width of one face = dx / 3^0.5 Inundation volume rate = I x cell area x 7 cells = ~0.0012124 m3/s Outflow volume = velocity at one the edge of any one of the lower active links x (solved) depth at that link x width of face x 4 faces. Call the velocity-depth product q. Then the predicted q should be: q = inundation volume rate / (face width x 4 faces) = (7 I (3^0.5 / 2) dx^2) / (4 dx / 3^0.5) = (21/8) I dx = (21/4) r dx / T = 0.0002625 """ grid = HexModelGrid((5, 3), spacing=2.0) z = grid.add_zeros("topographic__elevation", at="node") z[:] = -5.0 # Close all boundary nodes except the bottom row grid.status_at_node[ grid.status_at_node != grid.BC_NODE_IS_CORE ] = grid.BC_NODE_IS_CLOSED grid.status_at_node[0:3] = grid.BC_NODE_IS_FIXED_VALUE tfc = TidalFlowCalculator(grid, tidal_period=4.0e4) tfc.run_one_step() q = grid.at_link["flood_tide_flow__velocity"] * tfc._water_depth_at_links assert_array_almost_equal(q[3:7], [0.0002625, 0.0002625, 0.0002625, 0.0002625])
def test_can_run_with_hex(): """Test that model can run with hex model grid.""" # Set up a 5x5 grid with open boundaries and low initial elevations. mg = HexModelGrid(7, 7) z = mg.add_zeros('node', 'topographic__elevation') z[:] = 0.01 * mg.x_of_node # Create a D8 flow handler fa = FlowAccumulator(mg, flow_director='FlowDirectorSteepest') # Parameter values for test 1 K = 0.001 vs = 0.0001 U = 0.001 dt = 10.0 # Create the ErosionDeposition component... ed = ErosionDeposition(mg, K=K, phi=0.0, v_s=vs, m_sp=0.5, n_sp=1.0, method='simple_stream_power', discharge_method='drainage_area', area_field='drainage_area', solver='adaptive') # ... and run it to steady state. for i in range(2000): fa.run_one_step() ed.run_one_step(dt=dt) z[mg.core_nodes] += U * dt # Test the results s = mg.at_node['topographic__steepest_slope'] sa_factor = (1.0 + vs) * U / K a18 = mg.at_node['drainage_area'][18] a28 = mg.at_node['drainage_area'][28] s = mg.at_node['topographic__steepest_slope'] s18 = sa_factor * (a18**-0.5) s28 = sa_factor * (a28**-0.5) assert_equal(np.round(s[18], 3), np.round(s18, 3)) assert_equal(np.round(s[28], 3), np.round(s28, 3))
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 test_can_run_with_hex(): """Test that model can run with hex model grid.""" # Set up a 5x5 grid with open boundaries and low initial elevations. mg = HexModelGrid(7, 7) z = mg.add_zeros('node', 'topographic__elevation') z[:] = 0.01 * mg.x_of_node # Create a D8 flow handler fa = FlowAccumulator(mg, flow_director='FlowDirectorSteepest') # Parameter values for test 1 K = 0.001 vs = 0.0001 U = 0.001 dt = 10.0 # Create the ErosionDeposition component... ed = ErosionDeposition(mg, K=K, phi=0.0, v_s=vs, m_sp=0.5, n_sp=1.0, method='simple_stream_power', discharge_method='drainage_area', area_field='drainage_area', solver='adaptive') # ... and run it to steady state. for i in range(2000): fa.run_one_step() ed.run_one_step(dt=dt) z[mg.core_nodes] += U * dt # Test the results s = mg.at_node['topographic__steepest_slope'] sa_factor = (1.0 + vs) * U / K a18 = mg.at_node['drainage_area'][18] a28 = mg.at_node['drainage_area'][28] s = mg.at_node['topographic__steepest_slope'] s18 = sa_factor * (a18 ** -0.5) s28 = sa_factor * (a28 ** -0.5) assert_equal(np.round(s[18], 3), np.round(s18, 3)) assert_equal(np.round(s[28], 3), np.round(s28, 3))
def test_non_raster(): """Test a hex model grid.""" grid = HexModelGrid(7, 3, dx=10, xy_of_lower_left=(-15.0, 0.0)) grid.add_zeros("node", "topographic__elevation") param_dict = { "faulted_surface": "topographic__elevation", "fault_dip_angle": 90.0, "fault_throw_rate_through_time": {"time": [0, 9, 10], "rate": [0, 0, 0.05]}, "fault_trace": {"y1": 30.0, "x1": 30.0, "y2": 20.0, "x2": 0.0}, "include_boundaries": True, } nf = NormalFault(grid, **param_dict) # plotting, to test this. it works! # import matplotlib.pyplot as plt # plt.figure() # imshow_grid(grid, nf.faulted_nodes, color_for_background='y') # plt.plot(grid.x_of_node, grid.y_of_node, 'c.') # plt.plot([param_dict['fault_trace']['x1'], param_dict['fault_trace']['x2']], # [param_dict['fault_trace']['y1'], param_dict['fault_trace']['y2']], 'r') # plt.show() out = np.array( [ True, True, True, True, True, True, True, False, True, True, True, True, False, False, False, False, True, True, False, False, False, False, False, False, False, False, False, False, False, False, ], dtype=bool, ) assert_array_equal(nf.faulted_nodes, out)
def main(): # INITIALIZE # User-defined parameters nr = 80 # number of rows in grid nc = 50 # 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 = HexModelGrid(nr, nc, 1.0) # Make the boundaries be walls # mg.set_closed_boundaries_at_grid_edges(True, True, True, True)<--I am not sure what the equivalent is for hexgrid #Create a node-state dictionary ns_dict = { 0 : 'fluid', 1 : 'particle' } #Create the transition list 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 = OrientedHexCTS(mg, ns_dict, xn_list, node_state_grid) # Set up colors for plotting 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 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 simulation time '+str(current_time)+' \ ('+str(int(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() ca_plotter.finalize()
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 = OrientedHexLCA(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',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: node_state_grid[i]=0 # Create the CA model ca = OrientedHexLCA(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',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()
Created on Sun Nov 16 09:25:04 2014 @author: gtucker """ from landlab import HexModelGrid from numpy import arange from pylab import figure, show, title # Case 1: Make and display a hex-shaped grid with horizontal rows of nodes # Create the grid hg1 = HexModelGrid(5, 3, 1.0, orientation='horizontal', shape='hex') # Make some data d = hg1.add_zeros('node', 'mydata') d[:] = arange(hg1.number_of_nodes) # Display the grid figure(1) hg1.hexplot(d) title('hexagon shape, horizontal orientation') show() # Case 2: Make and display a hex-shaped grid with vertical columns of nodes # Create the grid hg2 = HexModelGrid(3, 5, 1.0, orientation='vertical', shape='hex') # Make some data
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()
class CTSModel(object): """ Implement a generic CellLab-CTS model. This is the base class from which models should inherit. """ def __init__(self, grid_size=(5, 5), report_interval=5.0, grid_orientation='vertical', grid_shape='rect', show_plots=False, cts_type='oriented_hex', run_duration=1.0, output_interval=1.0e99, plot_every_transition=False, **kwds): self.initialize(grid_size, report_interval, grid_orientation, grid_shape, show_plots, cts_type, run_duration, output_interval, plot_every_transition, **kwds) def initialize(self, grid_size=(5, 5), report_interval=5.0, grid_orientation='vertical', grid_shape='rect', show_plots=False, cts_type='oriented_hex', run_duration=1.0, output_interval=1.0e99, plot_every_transition=False, **kwds): # Remember the clock time, and calculate when we next want to report # progress. self.current_real_time = time.time() self.next_report = self.current_real_time + report_interval self.report_interval = report_interval # Interval for output self.output_interval = output_interval # Duration for run self.run_duration = run_duration # Create a grid self.create_grid_and_node_state_field(grid_size[0], grid_size[1], grid_orientation, grid_shape, cts_type) # Create the node-state dictionary ns_dict = self.node_state_dictionary() # Initialize values of the node-state grid nsg = self.initialize_node_state_grid() # Create the transition list xn_list = self.transition_list() # Create the CA object if cts_type == 'raster': from landlab.ca.raster_cts import RasterCTS self.ca = RasterCTS(self.grid, ns_dict, xn_list, nsg) elif cts_type == 'oriented_raster': from landlab.ca.oriented_raster_cts import OrientedRasterCTS self.ca = OrientedRasterCTS(self.grid, ns_dict, xn_list, nsg) elif cts_type == 'hex': from landlab.ca.hex_cts import HexCTS self.ca = HexCTS(self.grid, ns_dict, xn_list, nsg) else: from landlab.ca.oriented_hex_cts import OrientedHexCTS self.ca = OrientedHexCTS(self.grid, ns_dict, xn_list, nsg) # Initialize graphics self._show_plots = show_plots if show_plots == True: self.initialize_plotting(**kwds) def create_grid_and_node_state_field(self, num_rows, num_cols, grid_orientation, grid_shape, cts_type): """Create the grid and the field containing node states.""" if cts_type == 'raster' or cts_type == 'oriented_raster': from landlab import RasterModelGrid self.grid = RasterModelGrid(shape=(num_rows, num_cols), spacing=1.0) else: from landlab import HexModelGrid self.grid = HexModelGrid(num_rows, num_cols, 1.0, orientation=grid_orientation, shape=grid_shape) self.grid.add_zeros('node', 'node_state', dtype=int) def node_state_dictionary(self): """Create and return a dictionary of all possible node (cell) states. This method creates a default set of states (just two); it is a template meant to be overridden. """ ns_dict = { 0 : 'on', 1 : 'off'} return ns_dict def transition_list(self): """Create and return a list of transition objects. This method creates a default set of transitions (just two); it is a template meant to be overridden. """ xn_list = [] xn_list.append(Transition((0, 1, 0), (1, 0, 0), 1.0)) xn_list.append(Transition((1, 0, 0), (0, 1, 0), 1.0)) return xn_list def write_output(self, grid, outfilename, iteration): """Write output to file (currently netCDF).""" filename = outfilename + str(iteration).zfill(4) + '.nc' save_grid(grid, filename) def initialize_node_state_grid(self): """Initialize values in the node-state grid. This method should be overridden. The default is random "on" and "off". """ num_states = 2 for i in range(self.grid.number_of_nodes): self.grid.at_node['node_state'][i] = random.randint(num_states) return self.grid.at_node['node_state'] def initialize_plotting(self, **kwds): """Create and configure CAPlotter object.""" self.ca_plotter = CAPlotter(self.ca, **kwds) self.ca_plotter.update_plot() axis('off') def run_for(self, dt): self.ca.run(self.ca.current_time + dt, self.ca.node_state)
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()
for j in range(self.grid.number_of_active_links): i = self.grid.active_links[j] dy = self.grid.node_y[self.grid.link_tonode[i]]-self.grid.node_y[self.grid.link_fromnode[i]] dx = self.grid.node_x[self.grid.link_tonode[i]]-self.grid.node_x[self.grid.link_fromnode[i]] if dx <= 0.: self.active_link_orientation[j] = 0 elif dy<=0.: self.active_link_orientation[j] = 2 elif dx>0. and dy>0.: self.active_link_orientation[j] = 1 else: assert (False), 'Non-handled link orientation case' if __name__=='__main__': print 'main here' from landlab import HexModelGrid mg = HexModelGrid(2, 3, 1.0, orientation='vertical', reorient_links=True) print mg.number_of_active_links nsd = {0 : 'yes', 1 : 'no'} xnlist = [] xnlist.append( Transition( (0,1,0), (1,0,0), 1.0, 'falling' ) ) nsg = mg.add_zeros('node', 'node_state_grid') ohlca = OrientedHexLCA(mg, nsd, xnlist, nsg) for i in range(mg.number_of_active_links): j = mg.active_links[i] print i,j,'(',mg.node_x[mg.link_fromnode[j]],',',mg.node_y[mg.link_fromnode[j]],\ ')','(',mg.node_x[mg.link_tonode[j]],',',mg.node_y[mg.link_tonode[j]],\ ')',ohlca.active_link_orientation[i]
class CTSModel(object): """ Implement a generic CellLab-CTS model. This is the base class from which models should inherit. """ def __init__(self, grid_size=(5, 5), report_interval=5.0, grid_orientation='vertical', grid_shape='rect', show_plots=False, cts_type='oriented_hex', run_duration=1.0, output_interval=1.0e99, plot_every_transition=False, initial_state_grid=None, prop_data=None, prop_reset_value=None, closed_boundaries=(False, False, False, False), **kwds): self.initialize(grid_size, report_interval, grid_orientation, grid_shape, show_plots, cts_type, run_duration, output_interval, plot_every_transition, initial_state_grid, prop_data, prop_reset_value, closed_boundaries, **kwds) def initialize(self, grid_size=(5, 5), report_interval=5.0, grid_orientation='vertical', grid_shape='rect', show_plots=False, cts_type='oriented_hex', run_duration=1.0, output_interval=1.0e99, plot_every_transition=False, initial_state_grid=None, prop_data=None, prop_reset_value=None, closed_boundaries=(False, False, False, False), **kwds): """Initialize CTSModel.""" # Remember the clock time, and calculate when we next want to report # progress. self.current_real_time = time.time() self.next_report = self.current_real_time + report_interval self.report_interval = report_interval # Interval for output self.output_interval = output_interval # Duration for run self.run_duration = run_duration # Create a grid self.create_grid_and_node_state_field(grid_size[0], grid_size[1], grid_orientation, grid_shape, cts_type, closed_boundaries) # If prop_data is a string, we assume it is a field name if isinstance(prop_data, string_types): prop_data = self.grid.add_zeros('node', prop_data) # Create the node-state dictionary ns_dict = self.node_state_dictionary() # Initialize values of the node-state grid if initial_state_grid is None: nsg = self.initialize_node_state_grid() else: try: nsg = initial_state_grid self.grid.at_node['node_state'][:] = nsg except: #TODO: use new Messaging capability print('If initial_state_grid given, must be array of int') raise # Create the transition list xn_list = self.transition_list() # Create the CA object if cts_type == 'raster': from landlab.ca.raster_cts import RasterCTS self.ca = RasterCTS(self.grid, ns_dict, xn_list, nsg, prop_data, prop_reset_value) elif cts_type == 'oriented_raster': from landlab.ca.oriented_raster_cts import OrientedRasterCTS self.ca = OrientedRasterCTS(self.grid, ns_dict, xn_list, nsg, prop_data, prop_reset_value) elif cts_type == 'hex': from landlab.ca.hex_cts import HexCTS self.ca = HexCTS(self.grid, ns_dict, xn_list, nsg, prop_data, prop_reset_value) else: from landlab.ca.oriented_hex_cts import OrientedHexCTS self.ca = OrientedHexCTS(self.grid, ns_dict, xn_list, nsg, prop_data, prop_reset_value) # Initialize graphics self._show_plots = show_plots if show_plots == True: self.initialize_plotting(**kwds) def _set_closed_boundaries_for_hex_grid(self, closed_boundaries): """Setup one or more closed boundaries for a hex grid. Parameters ---------- closed_boundaries : 4-element tuple of bool\ Whether right, top, left, and bottom edges have closed nodes Examples -------- >>> from grainhill import CTSModel >>> cm = CTSModel(closed_boundaries=(True, True, True, True)) >>> cm.grid.status_at_node array([4, 4, 4, 4, 4, 4, 0, 4, 0, 0, 4, 0, 4, 0, 0, 4, 0, 4, 0, 0, 4, 4, 4, 4, 4], dtype=uint8) """ g = self.grid if closed_boundaries[0]: g.status_at_node[g.nodes_at_right_edge] = CLOSED_BOUNDARY if closed_boundaries[1]: g.status_at_node[g.nodes_at_top_edge] = CLOSED_BOUNDARY if closed_boundaries[2]: g.status_at_node[g.nodes_at_left_edge] = CLOSED_BOUNDARY if closed_boundaries[3]: g.status_at_node[g.nodes_at_bottom_edge] = CLOSED_BOUNDARY def create_grid_and_node_state_field(self, num_rows, num_cols, grid_orientation, grid_shape, cts_type, closed_bounds): """Create the grid and the field containing node states.""" if cts_type == 'raster' or cts_type == 'oriented_raster': from landlab import RasterModelGrid self.grid = RasterModelGrid(shape=(num_rows, num_cols), spacing=1.0) self.grid.set_closed_boundaries_at_grid_edges(closed_bounds[0], closed_bounds[1], closed_bounds[2], closed_bounds[3]) else: from landlab import HexModelGrid self.grid = HexModelGrid(num_rows, num_cols, 1.0, orientation=grid_orientation, shape=grid_shape) if True in closed_bounds: self._set_closed_boundaries_for_hex_grid(closed_bounds) self.grid.add_zeros('node', 'node_state', dtype=int) def node_state_dictionary(self): """Create and return a dictionary of all possible node (cell) states. This method creates a default set of states (just two); it is a template meant to be overridden. """ ns_dict = { 0 : 'on', 1 : 'off'} return ns_dict def transition_list(self): """Create and return a list of transition objects. This method creates a default set of transitions (just two); it is a template meant to be overridden. """ xn_list = [] xn_list.append(Transition((0, 1, 0), (1, 0, 0), 1.0)) xn_list.append(Transition((1, 0, 0), (0, 1, 0), 1.0)) return xn_list def write_output(self, grid, outfilename, iteration): """Write output to file (currently netCDF).""" filename = outfilename + str(iteration).zfill(4) + '.nc' save_grid(grid, filename) def initialize_node_state_grid(self): """Initialize values in the node-state grid. This method should be overridden. The default is random "on" and "off". """ num_states = 2 for i in range(self.grid.number_of_nodes): self.grid.at_node['node_state'][i] = random.randint(num_states) return self.grid.at_node['node_state'] def initialize_plotting(self, **kwds): """Create and configure CAPlotter object.""" self.ca_plotter = CAPlotter(self.ca, **kwds) self.ca_plotter.update_plot() axis('off') def run_for(self, dt): self.ca.run(self.ca.current_time + dt, self.ca.node_state)
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()
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()
class HexLatticeTectonicizer(object): """Handles tectonics and baselevel for CellLab-CTS models. This is the base class from which classes to represent particular baselevel/fault geometries are derived. Examples -------- >>> hlt = HexLatticeTectonicizer() >>> hlt.grid.number_of_nodes 25 >>> hlt.nr 5 >>> hlt.nc 5 """ def __init__(self, grid=None, node_state=None, propid=None, prop_data=None, prop_reset_value=None): """ Create and initialize a HexLatticeTectonicizer. Examples -------- >>> from landlab import HexModelGrid >>> hg = HexModelGrid(6, 6, shape='rect') >>> hlt = HexLatticeTectonicizer() >>> hlt.grid.number_of_nodes 25 >>> hlt.nr 5 >>> hlt.nc 5 """ # If needed, create grid if grid is None: num_rows = _DEFAULT_NUM_ROWS num_cols = _DEFAULT_NUM_COLS self.grid = HexModelGrid(num_rows, num_cols, dx=1.0, orientation='vertical', shape='rect', reorient_links=True) else: # Make sure caller passed the right type of grid assert (grid.orientation == 'vertical'), \ 'Grid must have vertical orientation' # Keep a reference to the grid self.grid = grid # If needed, create node-state grid if node_state is None: self.node_state = self.grid.add_zeros('node', 'node_state_map', dtype=int) else: self.node_state = node_state # Remember the # of rows and cols self.nr = self.grid.number_of_node_rows self.nc = self.grid.number_of_node_columns # propid should be either a reference to a CA model's "property id" # array, or None self.propid = propid self.prop_data = prop_data self.prop_reset_value = prop_reset_value
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()
def test_bad_init_gridmethod(): hmg = HexModelGrid(30, 29, dx=3.) hmg.add_zeros("node", "topographic__elevation", dtype=float) with pytest.raises(ValueError): LakeMapperBarnes(hmg, method="D8")
def main(): """ In this simple tutorial example, the main function does all the work: it sets the parameter values, creates and initializes a grid, sets up the state variables, runs the main loop, and cleans up. """ # INITIALIZE # User-defined parameter values numrows = 7 # number of rows in the grid basenumcols = 6 # number of columns in the grid dx = 10.0 # grid cell spacing kd = 0.01 # diffusivity coefficient, in m2/yr uplift_rate = 0.001 # baselevel/uplift rate, in m/yr num_time_steps = 1000 # number of time steps in run # Derived parameters dt = 0.1*dx**2 / kd # time-step size set by CFL condition # Create and initialize a raster model grid mg = HexModelGrid(numrows, basenumcols, dx) # Set up scalar values: elevation and elevation time derivative z = mg.add_zeros('node', 'Land_surface__elevation') dzdt = mg.add_zeros('node', 'Land_surface__time_derivative_of_elevation') # Get a list of the core nodes core_nodes = mg.core_nodes # Display a message print( 'Running diffusion_with_model_hex_grid.py' ) print( 'Time-step size has been set to ' + str( dt ) + ' years.' ) start_time = time.time() # RUN # Main loop for i in range(0, num_time_steps): # Calculate the gradients and sediment fluxes g = mg.calculate_gradients_at_active_links(z) qs = -kd*g # Calculate the net deposition/erosion rate at each node dqsds = mg.calculate_flux_divergence_at_nodes(qs) # Calculate the total rate of elevation change dzdt = uplift_rate - dqsds # Update the elevations z[core_nodes] = z[core_nodes] + dzdt[core_nodes] * dt # FINALIZE import numpy # Test solution for a 1-cell hex grid if mg.number_of_nodes==7: # single cell with 6 boundaries perimeter = dx*6*(numpy.sqrt(3.)/3.) flux = kd*(numpy.amax(z)/dx) total_outflux = perimeter*flux total_influx = mg.cell_areas*uplift_rate # just one cell ... print 'total influx=',total_influx,'total outflux=',total_outflux print('Run time = '+str(time.time()-start_time)+' seconds') # Plot the points, colored by elevation pylab.figure() maxelev = numpy.amax(z) for i in range(mg.number_of_nodes): mycolor = str(z[i]/maxelev) pylab.plot(mg.node_x[i], mg.node_y[i], 'o', color=mycolor, ms=50) pylab.show() mg.display_grid()
def main(): # INITIALIZE # User-defined parameters nr = 20 nc = 20 plot_interval = 2.0 run_duration = 2.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) # 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() # 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 = HexLCA(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=True, plotter=ca_plotter) current_time += plot_interval # Plot the current grid ca_plotter.update_plot() # FINALIZE # Plot ca_plotter.finalize()
def testing_flux_divergence_with_hex(): """Test flux divergence function(s). Notes ----- Test grid looks like this: (7)-17-.(8)-18-.(9) . . . . . . 11 12 13 14 15 16 / \ / \ / \ (3)--8-.(4)--9-.(5)-10-.(6) . . . . . . 2 3 4 5 6 7 \ / \ / \ / (0)--0-.(1)--1-.(2) Node numbers in parentheses; others are link numbers; period indicates link head. """ hmg = HexModelGrid(3, 3, reorient_links=True) f = hmg.add_zeros('link', 'test_flux') f[:] = np.arange(hmg.number_of_links) make_links_at_node_array(hmg) assert_array_equal(hmg.gt_num_links_at_node, [3, 4, 3, 3, 6, 6, 3, 3, 4, 3]) assert_array_equal(hmg.gt_links_at_node, [[ 0, 0, 1, 2, 3, 5, 7, 11, 13, 15], [ 2, 1, 6, 8, 4, 6, 10, 12, 14, 16], [ 3, 4, 7, 11, 8, 9, 16, 17, 17, 18], [ -1, 5, -1, -1, 9, 10, -1, -1, 18, -1], [ -1, -1, -1, -1, 12, 14, -1, -1, -1, -1], [ -1, -1, -1, -1, 13, 15, -1, -1, -1, -1]]) assert_array_equal(hmg.gt_link_dirs_at_node, [[ -1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [ -1, -1, -1, -1, 1, 1, 1, 1, 1, 1], [ -1, -1, -1, -1, 1, 1, -1, -1, 1, 1], [ 0, -1, 0, 0, -1, -1, 0, 0, -1, 0], [ 0, 0, 0, 0, -1, -1, 0, 0, 0, 0], [ 0, 0, 0, 0, -1, -1, 0, 0, 0, 0]]) raw_net_flux = np.zeros(hmg.number_of_nodes) for r in range(MAX_NUM_LINKS): raw_net_flux += f[hmg.gt_links_at_node[r,:]]*hmg.gt_link_dirs_at_node[r,:] assert_array_equal(raw_net_flux, [ -5., -10., -12., -17., -19., -19., 1., 6., 26., 49.]) nv = np.arange(hmg.number_of_nodes) #gt_calc_gradients_at_faces(hmg, nv) #gt_link_flux_divergence_at_cells_with_2darray(hmg, f) # Some time trials start = time.time() for i in range(1000): gt_grads_at_faces1(hmg, nv) endtime = time.time()
@author: gtucker """ from numpy import arange from pylab import figure, show, title from landlab import HexModelGrid # Case 1: Make and display a hex-shaped grid with horizontal rows of nodes # Create the grid hg1 = HexModelGrid(5, 3, 1.0, orientation="horizontal", shape="hex") # Make some data d = hg1.add_zeros("node", "mydata") d[:] = arange(hg1.number_of_nodes) # Display the grid figure(1) hg1.hexplot(d) title("hexagon shape, horizontal orientation") show() # Case 2: Make and display a hex-shaped grid with vertical columns of nodes # Create the grid hg2 = HexModelGrid(3, 5, 1.0, orientation="vertical", shape="hex") # Make some data